bx-rest 1.5.0 → 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.
Files changed (181) hide show
  1. package/CHANGELOG.md +177 -0
  2. package/README.en.md +116 -5
  3. package/README.md +117 -5
  4. package/esm2022/functions/errors.mjs +17 -5
  5. package/esm2022/functions/mapResult.mjs +4 -2
  6. package/esm2022/functions/uniqueElementCode.mjs +24 -0
  7. package/esm2022/map/disk.mjs +13 -0
  8. package/esm2022/map/im/recent.mjs +1 -9
  9. package/esm2022/map/task.mjs +11 -5
  10. package/esm2022/map/tasks/task.mjs +3 -3
  11. package/esm2022/map/tasks.mjs +4 -3
  12. package/esm2022/map/user.mjs +5 -4
  13. package/esm2022/public-api.mjs +2 -2
  14. package/esm2022/request-navvy/bizproc.mjs +19 -10
  15. package/esm2022/request-navvy/calendar/event.mjs +1 -9
  16. package/esm2022/request-navvy/disk/operation.mjs +3 -10
  17. package/esm2022/request-navvy/pull/config.mjs +1 -3
  18. package/esm2022/request-navvy/socialnetwork/api/livefeed.mjs +1 -5
  19. package/esm2022/request-navvy/task/operation/elapseditem.mjs +14 -71
  20. package/esm2022/request-navvy/tasks/task.mjs +1 -119
  21. package/esm2022/rest/map.mjs +3 -3
  22. package/esm2022/rest/navvy.mjs +66 -64
  23. package/esm2022/services/base.mjs +7 -7
  24. package/esm2022/services/context.mjs +59 -0
  25. package/esm2022/services/http/HttpBX.mjs +55 -20
  26. package/esm2022/services/http/authRefresh.mjs +25 -23
  27. package/esm2022/services/http/http.mjs +14 -69
  28. package/esm2022/services/http/middleware.mjs +149 -0
  29. package/esm2022/services/http/sessionKey.mjs +16 -5
  30. package/esm2022/services/http/transport.mjs +5 -0
  31. package/esm2022/services/navvy/extends/navvy-pag-base.mjs +63 -9
  32. package/esm2022/services/navvy/navvy-alternative-pagination-navigation.mjs +21 -71
  33. package/esm2022/services/navvy/navvy-pag-nav-result-key-object.mjs +10 -49
  34. package/esm2022/services/navvy/navvy-pag-nav-result-key.mjs +14 -73
  35. package/esm2022/services/navvy/navvy-pag-nav-tasks.mjs +4 -76
  36. package/esm2022/services/navvy/navvy-pag-nav-with-useless-key.mjs +10 -76
  37. package/esm2022/services/navvy/navvy-pag.mjs +7 -65
  38. package/esm2022/services/navvy/navvy-support.mjs +2 -15
  39. package/esm2022/services/navvy.mjs +18 -31
  40. package/esm2022/typification/rest/calendar/event/get.mjs +1 -1
  41. package/esm2022/typification/rest/settings.mjs +1 -1
  42. package/esm2022/typification/rest/tasks/task/get.mjs +1 -1
  43. package/esm2022/typification/rest/user/user.mjs +1 -1
  44. package/esm2022/typification/settings.mjs +1 -1
  45. package/fesm2022/bx-rest.mjs +860 -2038
  46. package/fesm2022/bx-rest.mjs.map +1 -1
  47. package/functions/errors.d.ts +9 -0
  48. package/functions/uniqueElementCode.d.ts +12 -0
  49. package/map/disk.d.ts +10 -0
  50. package/map/task.d.ts +3 -3
  51. package/map/tasks/task.d.ts +1 -1
  52. package/map/tasks.d.ts +1 -1
  53. package/package.json +5 -2
  54. package/public-api.d.ts +7 -3
  55. package/request-navvy/pull/config.d.ts +0 -2
  56. package/rest/map.d.ts +2 -2
  57. package/rest/navvy.d.ts +9 -0
  58. package/services/context.d.ts +43 -0
  59. package/services/http/HttpBX.d.ts +10 -0
  60. package/services/http/authRefresh.d.ts +5 -1
  61. package/services/http/http.d.ts +12 -9
  62. package/services/http/middleware.d.ts +31 -0
  63. package/services/http/sessionKey.d.ts +10 -0
  64. package/services/http/transport.d.ts +28 -0
  65. package/services/navvy/extends/navvy-pag-base.d.ts +16 -2
  66. package/services/navvy/navvy-alternative-pagination-navigation.d.ts +5 -2
  67. package/services/navvy/navvy-pag-nav-result-key-object.d.ts +0 -2
  68. package/services/navvy/navvy-pag-nav-result-key.d.ts +1 -4
  69. package/services/navvy/navvy-pag-nav-tasks.d.ts +2 -9
  70. package/services/navvy/navvy-pag-nav-with-useless-key.d.ts +0 -2
  71. package/services/navvy/navvy-pag.d.ts +0 -2
  72. package/services/navvy/navvy-support.d.ts +0 -10
  73. package/services/navvy.d.ts +1 -0
  74. package/typification/rest/calendar/event/get.d.ts +1 -1
  75. package/typification/rest/settings.d.ts +1 -0
  76. package/typification/rest/user/user.d.ts +3 -3
  77. package/typification/settings.d.ts +34 -0
  78. package/esm2022/functions/errorHandler.mjs +0 -34
  79. package/esm2022/request/app.mjs +0 -13
  80. package/esm2022/request/bizproc/activity.mjs +0 -3
  81. package/esm2022/request/bizproc/event.mjs +0 -3
  82. package/esm2022/request/bizproc/robot.mjs +0 -3
  83. package/esm2022/request/bizproc/task.mjs +0 -3
  84. package/esm2022/request/bizproc/workflow/instance.mjs +0 -3
  85. package/esm2022/request/bizproc/workflow/template.mjs +0 -3
  86. package/esm2022/request/bizproc/workflow.mjs +0 -18
  87. package/esm2022/request/bizproc.mjs +0 -15
  88. package/esm2022/request/department.mjs +0 -26
  89. package/esm2022/request/disk/attachedObject.mjs +0 -14
  90. package/esm2022/request/disk/file.mjs +0 -18
  91. package/esm2022/request/disk/folder.mjs +0 -117
  92. package/esm2022/request/disk.mjs +0 -11
  93. package/esm2022/request/lists/element.mjs +0 -18
  94. package/esm2022/request/lists/field.mjs +0 -35
  95. package/esm2022/request/lists.mjs +0 -86
  96. package/esm2022/request/log/blogcomment.mjs +0 -3
  97. package/esm2022/request/log/blogpost.mjs +0 -18
  98. package/esm2022/request/log.mjs +0 -9
  99. package/esm2022/request/pull/application/config.mjs +0 -11
  100. package/esm2022/request/pull/channel/public.mjs +0 -18
  101. package/esm2022/request/pull/config.mjs +0 -13
  102. package/esm2022/request/pull.mjs +0 -11
  103. package/esm2022/request/server.mjs +0 -14
  104. package/esm2022/request/socialnetwork/api/contentview.mjs +0 -14
  105. package/esm2022/request/socialnetwork/api/livefeed/blogpost/important.mjs +0 -14
  106. package/esm2022/request/socialnetwork/api/livefeed/blogpost.mjs +0 -7
  107. package/esm2022/request/socialnetwork/api/livefeed.mjs +0 -7
  108. package/esm2022/request/socialnetwork/api.mjs +0 -9
  109. package/esm2022/request/socialnetwork.mjs +0 -8
  110. package/esm2022/request/sonet_group.mjs +0 -24
  111. package/esm2022/request/task/commentitem.mjs +0 -32
  112. package/esm2022/request/task/elapseditem.mjs +0 -40
  113. package/esm2022/request/task/item/userfield.mjs +0 -14
  114. package/esm2022/request/task/item.mjs +0 -7
  115. package/esm2022/request/task/planner.mjs +0 -11
  116. package/esm2022/request/task.mjs +0 -13
  117. package/esm2022/request/tasks/task/result.mjs +0 -22
  118. package/esm2022/request/tasks/task.mjs +0 -110
  119. package/esm2022/request/tasks.mjs +0 -7
  120. package/esm2022/request/user/userfield.mjs +0 -14
  121. package/esm2022/request/user.mjs +0 -40
  122. package/esm2022/rest/base.mjs +0 -39
  123. package/esm2022/services/http/HttpData.mjs +0 -77
  124. package/esm2022/services/http/base/base.mjs +0 -4
  125. package/esm2022/services/http/httpNavvy.mjs +0 -14
  126. package/esm2022/typification/base/answers.mjs +0 -438
  127. package/esm2022/typification/base/params.mjs +0 -525
  128. package/esm2022/typification/base/workpiece/methods-list.mjs +0 -2
  129. package/esm2022/typification/base/workpiece/methods.mjs +0 -2
  130. package/functions/errorHandler.d.ts +0 -10
  131. package/request/app.d.ts +0 -8
  132. package/request/bizproc/activity.d.ts +0 -2
  133. package/request/bizproc/event.d.ts +0 -2
  134. package/request/bizproc/robot.d.ts +0 -2
  135. package/request/bizproc/task.d.ts +0 -2
  136. package/request/bizproc/workflow/instance.d.ts +0 -2
  137. package/request/bizproc/workflow/template.d.ts +0 -2
  138. package/request/bizproc/workflow.d.ts +0 -13
  139. package/request/bizproc.d.ts +0 -12
  140. package/request/department.d.ts +0 -18
  141. package/request/disk/attachedObject.d.ts +0 -8
  142. package/request/disk/file.d.ts +0 -10
  143. package/request/disk/folder.d.ts +0 -96
  144. package/request/disk.d.ts +0 -8
  145. package/request/lists/element.d.ts +0 -11
  146. package/request/lists/field.d.ts +0 -11
  147. package/request/lists.d.ts +0 -31
  148. package/request/log/blogcomment.d.ts +0 -2
  149. package/request/log/blogpost.d.ts +0 -11
  150. package/request/log.d.ts +0 -6
  151. package/request/pull/application/config.d.ts +0 -5
  152. package/request/pull/channel/public.d.ts +0 -5
  153. package/request/pull/config.d.ts +0 -7
  154. package/request/pull.d.ts +0 -8
  155. package/request/server.d.ts +0 -7
  156. package/request/socialnetwork/api/contentview.d.ts +0 -6
  157. package/request/socialnetwork/api/livefeed/blogpost/important.d.ts +0 -6
  158. package/request/socialnetwork/api/livefeed/blogpost.d.ts +0 -4
  159. package/request/socialnetwork/api/livefeed.d.ts +0 -4
  160. package/request/socialnetwork/api.d.ts +0 -6
  161. package/request/socialnetwork.d.ts +0 -4
  162. package/request/sonet_group.d.ts +0 -8
  163. package/request/task/commentitem.d.ts +0 -23
  164. package/request/task/elapseditem.d.ts +0 -26
  165. package/request/task/item/userfield.d.ts +0 -6
  166. package/request/task/item.d.ts +0 -4
  167. package/request/task/planner.d.ts +0 -4
  168. package/request/task.d.ts +0 -10
  169. package/request/tasks/task/result.d.ts +0 -13
  170. package/request/tasks/task.d.ts +0 -37
  171. package/request/tasks.d.ts +0 -4
  172. package/request/user/userfield.d.ts +0 -8
  173. package/request/user.d.ts +0 -24
  174. package/rest/base.d.ts +0 -33
  175. package/services/http/HttpData.d.ts +0 -7
  176. package/services/http/base/base.d.ts +0 -7
  177. package/services/http/httpNavvy.d.ts +0 -10
  178. package/typification/base/answers.d.ts +0 -12
  179. package/typification/base/params.d.ts +0 -16
  180. package/typification/base/workpiece/methods-list.d.ts +0 -247
  181. package/typification/base/workpiece/methods.d.ts +0 -20
@@ -1,12 +1,11 @@
1
- import { switchMap, catchError, map, take, mergeMap as mergeMap$1 } from 'rxjs/operators';
2
- import { Subscription, of, throwError, from, defer, forkJoin, last, shareReplay, mergeMap, concatMap, toArray, map as map$1, tap } from 'rxjs';
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';
6
6
  import { stringify } from 'qs-esm';
7
7
  import values from 'just-values';
8
8
  import camelCase from 'just-camel-case';
9
- import { __decorate } from 'tslib';
10
9
 
11
10
  const DEFAULT_BX_REST_SETTINGS = {
12
11
  auth: {
@@ -55,7 +54,9 @@ function BXRestMapResult(v) {
55
54
  return undefined;
56
55
  }
57
56
  function instanceOfiBXRestAnswerSuccess(object) {
58
- return 'result' in object;
57
+ // Без проверки типа `in` бросает TypeError на строке, числе и null вместо false.
58
+ // Строка приходит, если вместо Bitrix ответил прокси: HTML axios отдаёт текстом
59
+ return typeof object === 'object' && object !== null && 'result' in object;
59
60
  }
60
61
 
61
62
  function toLocalAtom(date) {
@@ -215,8 +216,12 @@ function parseDateWithFormat(val, format) {
215
216
  if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59) {
216
217
  return null;
217
218
  }
219
+ return buildDate(year, month, day, hour, minute, second);
220
+ }
221
+ /** Собирает дату, отбрасывая несуществующие дни месяца: new Date() превратил бы 31 февраля в 3 марта. */
222
+ function buildDate(year, month, day, hour, minute, second) {
218
223
  const date = new Date(year, month - 1, day, hour, minute, second);
219
- return isNaN(date.getTime()) ? null : date;
224
+ return (isNaN(date.getTime()) || date.getMonth() !== month - 1 || date.getDate() !== day) ? null : date;
220
225
  }
221
226
  /**
222
227
  * Последний резервный разбор — без знания конкретного формата. Работает только для чисто
@@ -259,8 +264,7 @@ function parseDateHeuristically(val) {
259
264
  if (hour > 23 || minute > 59 || second > 59) {
260
265
  return null;
261
266
  }
262
- const date = new Date(year, month - 1, day, hour, minute, second);
263
- return isNaN(date.getTime()) ? null : date;
267
+ return buildDate(year, month, day, hour, minute, second);
264
268
  }
265
269
  /**
266
270
  * Преобразует значение в дату.
@@ -410,9 +414,6 @@ async function getBase64FileLikeStr(file) {
410
414
  return undefined;
411
415
  }
412
416
  function prepareBaseAddress(url, add = '') {
413
- // if (url.search('https://') !== 0 && url.search('http://')) {
414
- // url = 'https://' + url
415
- // }
416
417
  if (add && add.length > 0) {
417
418
  if (url.lastIndexOf('/') !== (url.length - 1)) {
418
419
  url = url + '/';
@@ -519,6 +520,64 @@ class SessionStorage {
519
520
  }
520
521
  }
521
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
+
522
581
  class SessionKeyError extends Error {
523
582
  constructor(message) {
524
583
  super(message);
@@ -530,12 +589,18 @@ class SessionKeyServices {
530
589
  // НОВЫЙ объект (this.value = {...this.value, ...}), а не мутирует старый —
531
590
  // поэтому `= BXRestSettings.value` в виде обычного поля навсегда
532
591
  // "заморозил" бы то, что было на момент создания SessionKeyServices.
533
- // Геттер вместо этого читает актуальный BXRestSettings.value при каждом
534
- // обращении.
592
+ // Геттер вместо этого читает актуальные настройки при каждом обращении:
593
+ // свои настройки клиента или глобальные BXRestSettings.value.
535
594
  get BX_REST_SETTINGS() {
536
- return BXRestSettings.value;
595
+ return this.ctx.settings;
537
596
  }
538
597
  constructor() {
598
+ /**
599
+ * Контекст клиента, в котором создан объект: внутри `new BXRestNavvy(settings)`
600
+ * — контекст этого клиента, в остальных случаях — глобальные настройки.
601
+ * Объявлен первым: конструктор ниже уже читает настройки.
602
+ */
603
+ this.ctx = currentContext();
539
604
  this.authHave = false;
540
605
  this.subscribe = {
541
606
  authData: new Subscription()
@@ -594,6 +659,10 @@ class SessionKeyServices {
594
659
  getHeaders() {
595
660
  return { ...this.BX_REST_SETTINGS.headers };
596
661
  }
662
+ /** Свои middleware из настроек (`middleware`), читаются при каждом запросе — как и остальные настройки. */
663
+ getMiddleware() {
664
+ return this.BX_REST_SETTINGS.middleware ?? [];
665
+ }
597
666
  getSessid() {
598
667
  const check = this.getSearchParam('sessid');
599
668
  if (check) {
@@ -759,151 +828,21 @@ class SessionKeyServices {
759
828
  }
760
829
  }
761
830
 
762
- class HttpData {
763
- constructor() {
764
- this.defSettings = {
765
- timeZone: {
766
- calc: true,
767
- levelOut: false
768
- }
769
- };
770
- }
771
- getHttpParamsPost(obj, sendHttpParams = new FormData(), nesting = [], settings = this.defSettings) {
772
- if (obj instanceof Blob) {
773
- let first = nesting[0];
774
- let setKey = (nesting.length > 1)
775
- ? first + '[' + nesting.slice(1).join('][') + ']'
776
- : first;
777
- sendHttpParams.set(setKey, obj);
778
- return sendHttpParams;
779
- }
780
- else if (obj instanceof Date) {
781
- let first = nesting[0];
782
- let tzoffset = (settings.timeZone.calc) ? obj.getTimezoneOffset() * 60000 : 0; // вычисляем влияние часового пояса
783
- let levelOut = (settings.timeZone.levelOut) ? obj.getTimezoneOffset() * 60000 : 0; // вычисляем влияние часового пояса
784
- let setKey = (nesting.length > 1)
785
- ? first + '[' + nesting.slice(1).join('][') + ']'
786
- : first;
787
- sendHttpParams.set(setKey, (new Date(obj.valueOf() + tzoffset - levelOut)).toISOString());
788
- return sendHttpParams;
789
- }
790
- else {
791
- for (const key in obj) {
792
- let setKey = '';
793
- if (nesting.length) {
794
- let first = nesting[0];
795
- setKey = (nesting.length > 1)
796
- ? first + '[' + nesting.slice(1).join('][') + '][' + key + ']'
797
- : first + '[' + key + ']';
798
- }
799
- else {
800
- setKey = key;
801
- }
802
- switch (typeof obj[key]) {
803
- case 'string':
804
- sendHttpParams.set(setKey, obj[key]);
805
- break;
806
- case 'symbol':
807
- case 'number':
808
- case 'bigint':
809
- case 'boolean':
810
- sendHttpParams.set(setKey, String(obj[key]));
811
- break;
812
- case 'object':
813
- nesting.push(key);
814
- sendHttpParams = this.getHttpParamsPost(obj[key], sendHttpParams, nesting, settings);
815
- nesting.pop();
816
- break;
817
- case 'function':
818
- case 'undefined':
819
- default:
820
- console.error('You sent something wrong', obj[key], typeof obj[key], typeof obj);
821
- }
822
- }
823
- }
824
- return sendHttpParams;
825
- }
826
- sliceArrayIntoChunks(arr, chunkSize) {
827
- const res = [];
828
- for (let i = 0; i < arr.length; i += chunkSize) {
829
- const chunk = arr.slice(i, i + chunkSize);
830
- res.push(chunk);
831
- }
832
- return res;
833
- }
834
- removingMultipleSlashes(str) {
835
- return str.replace(/\/{2,}/g, '/');
836
- }
837
- }
838
-
839
- class BaseHttp extends HttpData {
840
- }
841
-
842
- class HttpServices extends BaseHttp {
831
+ /**
832
+ * Общая часть HTTP-клиента: экземпляр axios и источник токена и адреса.
833
+ * Сами запросы отправляет `HttpBXServices` (`BXRestRequest`).
834
+ */
835
+ class HttpServices {
843
836
  constructor() {
844
- super();
845
837
  this.session = new SessionKeyServices();
846
- this.axiosInstance = axios.create();
847
- }
848
- httpPost(url, params = {}, settings = this.defSettings) {
849
- const auth = this.session.getAuthParams();
850
- const checkIsOn = this.session.getCheckAuthParamsIsOn();
851
- const paramsClone = clone(params);
852
- if (checkIsOn) {
853
- if (!auth) {
854
- return throwError(() => this.session.getAuthError('post'));
855
- }
856
- paramsClone[this.session.getKeyAuth()] = auth;
857
- }
858
- return this.session.getBaseUrl().pipe(switchMap((baseUrl) => {
859
- if (!baseUrl) {
860
- return throwError(() => this.session.getBaseUrlError('post'));
861
- }
862
- const fullUrl = prepareBaseAddress(baseUrl) + url;
863
- if (this.session.getKeyAuth() === 'sessid') {
864
- const urlEncodedBody = new URLSearchParams();
865
- Object.keys(paramsClone).forEach((key) => {
866
- const value = paramsClone[key];
867
- if (typeof value === 'object' && value !== null) {
868
- for (const subKey in value) {
869
- if (Object.prototype.hasOwnProperty.call(value, subKey)) {
870
- urlEncodedBody.append(`${key}[${subKey}]`, value[subKey]);
871
- }
872
- }
873
- }
874
- else {
875
- urlEncodedBody.append(key, value);
876
- }
877
- });
878
- return from(this.axiosInstance.post(fullUrl, urlEncodedBody.toString(), {
879
- headers: {
880
- 'Content-Type': 'application/x-www-form-urlencoded',
881
- },
882
- }).then((response) => response.data));
883
- }
884
- const body = this.getHttpParamsPost(paramsClone, new FormData(), [], settings);
885
- return from(this.axiosInstance.post(fullUrl, body).then((response) => response.data));
886
- }));
887
838
  }
888
- httpGet(url, params = {}) {
889
- const auth = this.session.getAuthParams();
890
- const checkIsOn = this.session.getCheckAuthParamsIsOn();
891
- const paramsClone = clone(params);
892
- if (checkIsOn) {
893
- if (!auth) {
894
- return throwError(() => this.session.getAuthError('get'));
895
- }
896
- paramsClone[this.session.getKeyAuth()] = auth;
897
- }
898
- return this.session.getBaseUrl().pipe(switchMap((baseUrl) => {
899
- if (!baseUrl) {
900
- return throwError(() => this.session.getBaseUrlError('get'));
901
- }
902
- const fullUrl = prepareBaseAddress(baseUrl) + url;
903
- const queryString = new URLSearchParams(paramsClone).toString();
904
- const finalUrl = `${fullUrl}?${queryString}`;
905
- return from(this.axiosInstance.get(finalUrl).then((response) => response.data));
906
- }));
839
+ /**
840
+ * Экземпляр axios клиента. Один на контекст (клиента со своими настройками
841
+ * или глобальные настройки) и создаётся при первом запросе — раньше каждый
842
+ * объект запроса создавал свой.
843
+ */
844
+ get axiosInstance() {
845
+ return this.session.ctx.axios ??= axios.create();
907
846
  }
908
847
  }
909
848
 
@@ -1004,20 +943,33 @@ function parseBXRestErrorBody(body) {
1004
943
  * Bitrix error body, so the caller can keep its own handling for them.
1005
944
  */
1006
945
  function bxRestApiErrorFromHttp(err, method) {
1007
- if (!axios.isAxiosError(err) || !err.response) {
946
+ const response = httpErrorResponse(err);
947
+ if (!response) {
1008
948
  return undefined;
1009
949
  }
1010
- const parsed = parseBXRestErrorBody(err.response.data);
950
+ const parsed = parseBXRestErrorBody(response.data);
1011
951
  if (!parsed) {
1012
952
  return undefined;
1013
953
  }
1014
954
  return new BXRestApiError(parsed.error, parsed.error_description, {
1015
- status: err.response.status,
955
+ status: response.status,
1016
956
  method,
1017
957
  cause: err,
1018
958
  authRefreshError: getAuthRefreshError(err)
1019
959
  });
1020
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
+ }
1021
973
 
1022
974
  /**
1023
975
  * Коды ошибок Bitrix, которые лечатся продлением токена. `expired_token` —
@@ -1040,34 +992,34 @@ const AUTH_ERROR_CODES = ['expired_token', 'invalid_token'];
1040
992
  * Ответ 401 с другим кодом Bitrix ошибкой авторизации не считается.
1041
993
  */
1042
994
  function isBXRestAuthError(error) {
1043
- if (!axios.isAxiosError(error) || !error.response) {
995
+ const response = httpErrorResponse(error);
996
+ if (!response) {
1044
997
  return false;
1045
998
  }
1046
- const parsed = parseBXRestErrorBody(error.response.data);
999
+ const parsed = parseBXRestErrorBody(response.data);
1047
1000
  if (parsed) {
1048
1001
  return AUTH_ERROR_CODES.includes(parsed.error);
1049
1002
  }
1050
- return error.response.status === 401;
1003
+ return response.status === 401;
1051
1004
  }
1052
- // Общее на всю библиотеку состояние продления — как и сами BXRestSettings.
1053
- // pendingRefresh — идущее сейчас продление, его ждут все упавшие запросы;
1054
- // refreshCount — сколько продлений уже завершилось успешно.
1055
- let pendingRefresh;
1056
- let refreshCount = 0;
1057
- function sharedRefresh(refresh) {
1058
- if (!pendingRefresh) {
1059
- 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()
1060
1012
  // Через then, чтобы синхронное исключение в refresh() тоже стало
1061
1013
  // отклонённым промисом, а не вылетело из catchError
1062
1014
  .then(() => refresh())
1063
1015
  .then(() => {
1064
- refreshCount++;
1016
+ ctx.refreshCount++;
1065
1017
  })
1066
1018
  .finally(() => {
1067
- pendingRefresh = undefined;
1019
+ ctx.pendingRefresh = undefined;
1068
1020
  });
1069
1021
  }
1070
- return pendingRefresh;
1022
+ return ctx.pendingRefresh;
1071
1023
  }
1072
1024
  /**
1073
1025
  * Повтор запроса после продления авторизации (`BXRestSettings.auth.refresh`).
@@ -1076,23 +1028,26 @@ function sharedRefresh(refresh) {
1076
1028
  * `defer()` в HttpBXServices): повтор — это повторная подписка, поэтому
1077
1029
  * токен, адрес и заголовки берутся уже новые. На второй попытке ошибка не
1078
1030
  * перехватывается — запрос повторяется не больше одного раза.
1031
+ *
1032
+ * `ctx` — контекст клиента, из которого берутся `refresh`, `isAuthError` и
1033
+ * общее состояние продления.
1079
1034
  */
1080
- function withAuthRefresh(request$) {
1035
+ function withAuthRefresh(request$, ctx = globalContext) {
1081
1036
  return defer(() => {
1082
- const { refresh, isAuthError = isBXRestAuthError } = BXRestSettings.value.auth;
1037
+ const { refresh, isAuthError = isBXRestAuthError } = ctx.settings.auth;
1083
1038
  if (!refresh) {
1084
1039
  return request$;
1085
1040
  }
1086
- const refreshCountAtStart = refreshCount;
1041
+ const refreshCountAtStart = ctx.refreshCount;
1087
1042
  return request$.pipe(catchError((error) => {
1088
1043
  if (!isAuthError(error)) {
1089
1044
  return throwError(() => error);
1090
1045
  }
1091
1046
  // Пока этот запрос был в пути, токен уже продлили по ошибке другого
1092
1047
  // запроса — повторяем без нового продления
1093
- const refreshed = (refreshCount !== refreshCountAtStart)
1048
+ const refreshed = (ctx.refreshCount !== refreshCountAtStart)
1094
1049
  ? Promise.resolve()
1095
- : sharedRefresh(refresh);
1050
+ : sharedRefresh(refresh, ctx);
1096
1051
  return from(refreshed).pipe(catchError((refreshError) => {
1097
1052
  if (error && typeof error === 'object') {
1098
1053
  error.authRefreshError = refreshError;
@@ -1103,6 +1058,159 @@ function withAuthRefresh(request$) {
1103
1058
  });
1104
1059
  }
1105
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
+
1106
1214
  class HttpBXServices extends HttpServices {
1107
1215
  /**
1108
1216
  * Не считайте этот метод образцом/финальным API.
@@ -1167,8 +1275,8 @@ class HttpBXServices extends HttpServices {
1167
1275
  get(name, params = {}, headers) {
1168
1276
  return this.httpGet(this.getNameMethod(name), params, undefined, headers);
1169
1277
  }
1170
- // settings — только для совместимости сигнатуры с HttpServices: здесь тело
1171
- // уходит JSON-ом/urlencoded, и пересчёт дат из iHttpParamSettings не нужен.
1278
+ // settings не используется и оставлен ради прежней сигнатуры: headers
1279
+ // остаётся четвёртым параметром у httpPost и httpGet.
1172
1280
  httpPost(url, params = {}, settings, headers) {
1173
1281
  // defer() откладывает всё содержимое (в том числе чтение BXRestSettings
1174
1282
  // через this.session.*) до реальной подписки — иначе даже с "живым"
@@ -1199,19 +1307,19 @@ class HttpBXServices extends HttpServices {
1199
1307
  return throwError(() => this.session.getBaseUrlError('post'));
1200
1308
  }
1201
1309
  const fullUrl = prepareBaseAddress(baseUrl) + url;
1202
- if (key === 'sessid') {
1203
- // Преобразуем параметры в формат x-www-form-urlencoded
1204
- const bodyString = this.serializeBitrixParams(paramsClone);
1205
- return from(this.axiosInstance.post(fullUrl, bodyString, {
1206
- headers: this.buildHeaders(headers, { 'Content-Type': 'application/x-www-form-urlencoded' }),
1207
- }).then((response) => response.data));
1208
- }
1209
- 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,
1210
1316
  withCredentials: this.session.getWithCredentials(),
1211
- headers: this.buildHeaders(headers, { 'Content-Type': 'application/json' }),
1212
- }).then((response) => response.data));
1317
+ headers: this.buildHeaders(headers, {
1318
+ 'Content-Type': urlencoded ? 'application/x-www-form-urlencoded' : 'application/json'
1319
+ }),
1320
+ });
1213
1321
  }));
1214
- }));
1322
+ }), this.session.ctx);
1215
1323
  }
1216
1324
  httpGet(url, params = {}, settings, headers) {
1217
1325
  // Та же причина, что и у httpPost выше: откладываем чтение BXRestSettings
@@ -1221,26 +1329,59 @@ class HttpBXServices extends HttpServices {
1221
1329
  // авторизации — как в httpPost.
1222
1330
  return withAuthRefresh(defer(() => {
1223
1331
  const paramsClone = clone(params);
1332
+ const key = this.session.getKeyAuth();
1224
1333
  const auth = this.session.getAuthParams();
1225
1334
  const checkIsOn = this.session.getCheckAuthParamsIsOn();
1226
1335
  if (checkIsOn) {
1227
1336
  if (!auth) {
1228
1337
  return throwError(() => this.session.getAuthError('get'));
1229
1338
  }
1230
- paramsClone[this.session.getKeyAuth()] = auth;
1339
+ if (key !== 'OAuth2') {
1340
+ paramsClone[key] = auth;
1341
+ }
1231
1342
  }
1232
1343
  return this.session.getBaseUrl().pipe(switchMap((baseUrl) => {
1233
1344
  if (!baseUrl) {
1234
1345
  return throwError(() => this.session.getBaseUrlError('get'));
1235
1346
  }
1236
1347
  const fullUrl = prepareBaseAddress(baseUrl) + url;
1237
- const queryString = new URLSearchParams(paramsClone).toString();
1348
+ const queryString = this.serializeBitrixParams(paramsClone);
1238
1349
  const finalUrl = `${fullUrl}?${queryString}`;
1239
- return from(this.axiosInstance.get(finalUrl, {
1350
+ return this.send({
1351
+ method: 'GET',
1352
+ url: finalUrl,
1353
+ withCredentials: this.session.getWithCredentials(),
1240
1354
  headers: this.buildHeaders(headers),
1241
- }).then((response) => response.data));
1355
+ });
1242
1356
  }));
1243
- }));
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);
1244
1385
  }
1245
1386
  /**
1246
1387
  * Заголовки запроса: `BXRestSettings.headers`, поверх них — заголовки
@@ -1259,6 +1400,19 @@ class HttpBXServices extends HttpServices {
1259
1400
  }
1260
1401
  }
1261
1402
 
1403
+ /** Больше команд в одном запросе `batch` Bitrix не принимает. */
1404
+ const BATCH_COMMANDS_LIMIT = 50;
1405
+ /**
1406
+ * Параметры остальных страниц для методов с постраничной навигацией через `start`.
1407
+ * Отсчёт идёт от `start` самого запроса: первая страница уже получена именно с него.
1408
+ */
1409
+ function offsetPageParams(param, total, pageSize) {
1410
+ const pages = [];
1411
+ for (let start = (Number(param?.start) || 0) + pageSize; start < (total ?? 0); start += pageSize) {
1412
+ pages.push({ ...clone(param), start });
1413
+ }
1414
+ return pages;
1415
+ }
1262
1416
  class NavvyPagBase {
1263
1417
  constructor(url, param, map = undefined, restApi = false) {
1264
1418
  this.url = url;
@@ -1302,13 +1456,7 @@ class NavvyPagBase {
1302
1456
  }
1303
1457
  mapAndError(request, options) {
1304
1458
  const method = this.http.getNameMethod(this.url);
1305
- return request.pipe(map(v => {
1306
- if (options?.throwOnApiError && v && !instanceOfiBXRestAnswerSuccess(v)) {
1307
- throw this.apiErrorFromBody(v);
1308
- }
1309
- return BXRestMapResult(v);
1310
- }), catchError((err) => {
1311
- console.error(err);
1459
+ return request.pipe(catchError((err) => {
1312
1460
  if (err instanceof BXRestApiError) {
1313
1461
  throw err;
1314
1462
  }
@@ -1328,6 +1476,14 @@ class NavvyPagBase {
1328
1476
  Object.assign(error, { authRefreshError });
1329
1477
  }
1330
1478
  throw error;
1479
+ }), map(v => {
1480
+ if (v && typeof v !== 'object') {
1481
+ throw this.notRestAnswerError();
1482
+ }
1483
+ if (options?.throwOnApiError && v && !instanceOfiBXRestAnswerSuccess(v)) {
1484
+ throw this.apiErrorFromBody(v);
1485
+ }
1486
+ return BXRestMapResult(v);
1331
1487
  }));
1332
1488
  }
1333
1489
  /**
@@ -1336,12 +1492,48 @@ class NavvyPagBase {
1336
1492
  */
1337
1493
  resFirstPage() {
1338
1494
  return this.resVanilla().pipe(map(v => {
1339
- if (v && !instanceOfiBXRestAnswerSuccess(v)) {
1495
+ if (!v || typeof v !== 'object') {
1496
+ throw this.notRestAnswerError();
1497
+ }
1498
+ if (!instanceOfiBXRestAnswerSuccess(v)) {
1340
1499
  throw this.apiErrorFromBody(v);
1341
1500
  }
1342
1501
  return v;
1343
1502
  }));
1344
1503
  }
1504
+ /**
1505
+ * Остальные страницы для `.resAll()`, в порядке `params`. Команды уходят через `batch`,
1506
+ * пакеты — по очереди. Ошибка любой страницы завершает весь запрос: неполный список
1507
+ * выглядел бы для вызывающего кода как полный.
1508
+ */
1509
+ resPages(params) {
1510
+ const method = this.http.getNameMethod(this.url);
1511
+ const commands = params.map(param => method + '?' + serializeBitrixParams(param));
1512
+ const batches = [];
1513
+ for (let i = 0; i < commands.length; i += BATCH_COMMANDS_LIMIT) {
1514
+ batches.push(commands.slice(i, i + BATCH_COMMANDS_LIMIT));
1515
+ }
1516
+ return from(batches).pipe(concatMap(cmd => this.http.post(['batch'], { halt: 1, cmd }, false, this.requestHeaders)), map(answer => this.batchPages(answer)), toArray(), map(pages => pages.flat()));
1517
+ }
1518
+ batchPages(answer) {
1519
+ if (!answer || typeof answer !== 'object') {
1520
+ throw this.notRestAnswerError();
1521
+ }
1522
+ if (!instanceOfiBXRestAnswerSuccess(answer)) {
1523
+ throw this.apiErrorFromBody(answer);
1524
+ }
1525
+ // Портал отдаёт result_error массивом, когда ошибок нет, и объектом с ключами команд, когда есть
1526
+ const failed = Object.values(answer.result?.result_error ?? {})[0];
1527
+ if (failed) {
1528
+ const parsed = parseBXRestErrorBody(failed);
1529
+ throw new BXRestApiError(parsed?.error, parsed?.error_description, { method: this.http.getNameMethod(this.url) });
1530
+ }
1531
+ return Object.values(answer.result?.result ?? {}).filter(Boolean);
1532
+ }
1533
+ // В тексте ошибки — только метод, без тела ответа: это может быть целая HTML-страница
1534
+ notRestAnswerError() {
1535
+ return new Error(`Bitrix24 answered ${this.http.getNameMethod(this.url)} with a body that is not a REST response.`);
1536
+ }
1345
1537
  apiErrorFromBody(v) {
1346
1538
  const parsed = parseBXRestErrorBody(v);
1347
1539
  return new BXRestApiError(parsed ? parsed.error : v.error, parsed ? parsed.error_description : v.error_description, { method: this.http.getNameMethod(this.url) });
@@ -1351,6 +1543,138 @@ class NavvyPagBase {
1351
1543
  class NavvySimple extends NavvyPagBase {
1352
1544
  }
1353
1545
 
1546
+ /**
1547
+ * Класс-прослойка-обработчик для методов работающих на альтернативной постраничной навигации тика как методы по
1548
+ * затраченному времени на задачи https://dev.1c-bitrix.ru/rest_help/tasks/task/elapseditem/index.php
1549
+ *
1550
+ * не завершенный класс, работаем от частного к общему
1551
+ */
1552
+ class NavvyAlterPagNav extends NavvyPagBase {
1553
+ resAll() {
1554
+ return this.resFirstPage().pipe(mergeMap(first => this.resPages(first.next ? this.pageParams(first.total) : []).pipe(map(pages => {
1555
+ const items = [first.result ?? [], ...pages].flat();
1556
+ return ((this.map ? this.map(items) : items) ?? []);
1557
+ }))),
1558
+ // refCount: без подписчиков оставшиеся страницы запрашивать незачем
1559
+ shareReplay({ bufferSize: 1, refCount: true }));
1560
+ }
1561
+ /**
1562
+ * Параметры остальных страниц. Размер страницы берётся из запроса: портал ограничивает
1563
+ * его 50 записями, но вызывающий код может попросить и меньше.
1564
+ */
1565
+ pageParams(total = 0) {
1566
+ const nav = this.param.PARAMS?.NAV_PARAMS;
1567
+ const nPageSize = Math.min(nav?.nPageSize || this.pageSize, this.pageSize);
1568
+ const pages = [];
1569
+ for (let iNumPage = (nav?.iNumPage || 1) + 1; iNumPage <= Math.ceil(total / nPageSize); iNumPage++) {
1570
+ pages.push({ ...clone(this.param), PARAMS: { ...this.param.PARAMS, NAV_PARAMS: { ...nav, nPageSize, iNumPage } } });
1571
+ }
1572
+ return pages;
1573
+ }
1574
+ }
1575
+
1576
+ class NavvyPagNavWithUselessKey extends NavvyPagBase {
1577
+ resAll() {
1578
+ return this.resFirstPage().pipe(mergeMap(first => {
1579
+ const params = first.next ? offsetPageParams(this.param, first.total, this.pageSize) : [];
1580
+ return this.resPages(params).pipe(map(pages => {
1581
+ const merged = Object.assign({}, first.result, ...pages);
1582
+ return (this.map ? this.map(merged) : [merged]);
1583
+ }));
1584
+ }));
1585
+ }
1586
+ }
1587
+
1588
+ class NavvyPagNavResultKey extends NavvyPagBase {
1589
+ constructor(url, param, key, map, restApi) {
1590
+ // Без своего map результат — массив по ключу, как и обещают типы `.res()` и `.resAll()`.
1591
+ // Иначе `.res()` отдал бы весь объект `{ items: [...] }`.
1592
+ super(url, param, map ?? (result => (result?.[key] ?? [])), restApi);
1593
+ this.key = key;
1594
+ }
1595
+ resAll() {
1596
+ return this.resFirstPage().pipe(mergeMap(first => this.resPages(offsetPageParams(this.param, first.total, this.pageSize)).pipe(map(pages => {
1597
+ const items = [first.result, ...pages].flatMap(page => page?.[this.key] ?? []);
1598
+ const joined = { ...first.result, [this.key]: items };
1599
+ return (this.map?.(joined) ?? []);
1600
+ }))),
1601
+ // refCount: без подписчиков оставшиеся страницы запрашивать незачем
1602
+ shareReplay({ bufferSize: 1, refCount: true }));
1603
+ }
1604
+ }
1605
+
1606
+ class NavvyPagNavTasks extends NavvyPagNavResultKey {
1607
+ constructor(url, param, map, restApi) {
1608
+ super(url, param, 'tasks', map, restApi);
1609
+ }
1610
+ }
1611
+
1612
+ class NavvyPag extends NavvyPagBase {
1613
+ resAll() {
1614
+ return this.resFirstPage().pipe(mergeMap(first => this.resPages(offsetPageParams(this.param, first.total, this.pageSize)).pipe(map(pages => {
1615
+ const items = [first.result ?? [], ...pages].flat();
1616
+ return ((this.map ? this.map(items) : items) ?? []);
1617
+ }))));
1618
+ }
1619
+ }
1620
+
1621
+ /** Пагинация для методов, возвращающих коллекцию как объект с идентификаторами в ключах. */
1622
+ class NavvyPagNavResultKeyObject extends NavvyPagBase {
1623
+ constructor(url, param, key, mapResult) {
1624
+ // Без своего map результат — значения объекта по ключу, как и обещают типы `.res()` и `.resAll()`.
1625
+ super(url, param, mapResult ?? (result => Object.values(result?.[key] ?? {})));
1626
+ this.key = key;
1627
+ }
1628
+ resAll() {
1629
+ return this.resFirstPage().pipe(mergeMap(first => this.resPages(offsetPageParams(this.param, first.total, this.pageSize)).pipe(map(pages => {
1630
+ const merged = Object.assign({}, first.result?.[this.key], ...pages.map(page => page[this.key]));
1631
+ return this.map?.({ ...first.result, [this.key]: merged });
1632
+ }))),
1633
+ // refCount: без подписчиков оставшиеся страницы запрашивать незачем
1634
+ shareReplay({ bufferSize: 1, refCount: true }));
1635
+ }
1636
+ }
1637
+
1638
+ class Navvy {
1639
+ constructor() {
1640
+ // Контекст, в котором создан Navvy. Запросы создаются позже, при вызове
1641
+ // метода, поэтому их HTTP-объекты получают этот контекст явно, а не текущий.
1642
+ this.ctx = currentContext();
1643
+ }
1644
+ simple(url, arg, map) {
1645
+ return runInContext(this.ctx, () => new NavvySimple(url, arg !== undefined ? arg : undefined, map));
1646
+ }
1647
+ simpleV3(url, arg, map) {
1648
+ return runInContext(this.ctx, () => new NavvySimple(url, arg !== undefined ? arg : undefined, map, true));
1649
+ }
1650
+ /**
1651
+ * Новый, пока тестируемый метод для api методов с пагинацией
1652
+ *
1653
+ * @param url
1654
+ * @param arg
1655
+ * @param map
1656
+ * @constructor
1657
+ */
1658
+ pagNav(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));
1663
+ }
1664
+ pagNavResultKey(url, arg, key, map) {
1665
+ return runInContext(this.ctx, () => new NavvyPagNavResultKey(url, arg, key, map));
1666
+ }
1667
+ pagNavResultKeyObject(url, arg, key, map) {
1668
+ return runInContext(this.ctx, () => new NavvyPagNavResultKeyObject(url, arg, key, map));
1669
+ }
1670
+ pagNavWithUselessKey(url, arg, map) {
1671
+ return runInContext(this.ctx, () => new NavvyPagNavWithUselessKey(url, arg, map));
1672
+ }
1673
+ alterPagNav(url, arg, map) {
1674
+ return runInContext(this.ctx, () => new NavvyAlterPagNav(url, arg, map));
1675
+ }
1676
+ }
1677
+
1354
1678
  const $get = 'get';
1355
1679
  const $add = 'add';
1356
1680
  const $set = 'set';
@@ -2263,1496 +2587,180 @@ var partNameMethods$1 = /*#__PURE__*/Object.freeze({
2263
2587
  $quote: $quote,
2264
2588
  $ratio: $ratio,
2265
2589
  $reaction: $reaction,
2266
- $read: $read,
2267
- $reading: $reading,
2268
- $recall: $recall,
2269
- $recent: $recent,
2270
- $recipient: $recipient,
2271
- $record: $record,
2272
- $recurring: $recurring,
2273
- $region: $region,
2274
- $register: $register,
2275
- $remove: $remove,
2276
- $removeAttachments: $removeAttachments,
2277
- $removeCard: $removeCard,
2278
- $removeEntities: $removeEntities,
2279
- $removecrmactivity: $removecrmactivity,
2280
- $rename: $rename,
2281
- $renew: $renew,
2282
- $reply: $reply,
2283
- $repo: $repo,
2284
- $report: $report,
2285
- $reports: $reports,
2286
- $repowidget: $repowidget,
2287
- $request: $request,
2288
- $requisite: $requisite,
2289
- $reset: $reset,
2290
- $resolveIdByPublicUrl: $resolveIdByPublicUrl,
2291
- $resource: $resource,
2292
- $resourcetype: $resourcetype,
2293
- $restore: $restore,
2294
- $restoreFromVersion: $restoreFromVersion,
2295
- $result: $result,
2296
- $resume: $resume,
2297
- $revision: $revision,
2298
- $rights: $rights,
2299
- $robot: $robot,
2300
- $role: $role,
2301
- $roundingRule: $roundingRule,
2302
- $sale: $sale,
2303
- $save: $save,
2304
- $schedule: $schedule,
2305
- $schema: $schema,
2306
- $search: $search,
2307
- $searchCrmEntities: $searchCrmEntities,
2308
- $section: $section,
2309
- $send: $send,
2310
- $sendContext: $sendContext,
2311
- $sendMessage: $sendMessage,
2312
- $sender: $sender,
2313
- $senders: $senders,
2314
- $server: $server,
2315
- $service: $service,
2316
- $session: $session,
2317
- $set: $set,
2318
- $setAccessCodes: $setAccessCodes,
2319
- $setDelivery: $setDelivery,
2320
- $setLandingRef: $setLandingRef,
2321
- $setOwner: $setOwner,
2322
- $setQuantity: $setQuantity,
2323
- $setRights: $setRights,
2324
- $setSiteRef: $setSiteRef,
2325
- $setowner: $setowner,
2326
- $settings: $settings,
2327
- $share: $share,
2328
- $sharetouser: $sharetouser,
2329
- $shipment: $shipment,
2330
- $shipmentItem: $shipmentItem,
2331
- $shipmentProperty: $shipmentProperty,
2332
- $shipmentPropertyValue: $shipmentPropertyValue,
2333
- $show: $show,
2334
- $showBlock: $showBlock,
2335
- $sign: $sign,
2336
- $silent: $silent,
2337
- $sip: $sip,
2338
- $site: $site,
2339
- $skip: $skip,
2340
- $sku: $sku,
2341
- $slots: $slots,
2342
- $socialnetwork: $socialnetwork,
2343
- $sonet_group: $sonet_group,
2344
- $source: $source,
2345
- $spam: $spam,
2346
- $stagehistory: $stagehistory,
2347
- $stages: $stages,
2348
- $start: $start,
2349
- $startwatch: $startwatch,
2350
- $startwithsound: $startwithsound,
2351
- $startwithtext: $startwithtext,
2352
- $statistic: $statistic,
2353
- $status: $status,
2354
- $statusLang: $statusLang,
2355
- $statuslist: $statuslist,
2356
- $stop: $stop,
2357
- $stopwatch: $stopwatch,
2358
- $storage: $storage,
2359
- $store: $store,
2360
- $storeProduct: $storeProduct,
2361
- $subscribe: $subscribe,
2362
- $syspage: $syspage,
2363
- $system: $system,
2364
- $tail: $tail,
2365
- $task: $task,
2366
- $tasks: $tasks,
2367
- $telephony: $telephony,
2368
- $template: $template,
2369
- $terminate: $terminate,
2370
- $text: $text,
2371
- $textField: $textField,
2372
- $thread: $thread,
2373
- $time: $time,
2374
- $timeMan: $timeMan,
2375
- $timecontrol: $timecontrol,
2376
- $timeline: $timeline,
2377
- $todo: $todo,
2378
- $trace: $trace,
2379
- $tracking: $tracking,
2380
- $tradeBinding: $tradeBinding,
2381
- $tradePlatform: $tradePlatform,
2382
- $transfer: $transfer,
2383
- $tree: $tree,
2384
- $trigger: $trigger,
2385
- $tts: $tts,
2386
- $type: $type,
2387
- $types: $types,
2388
- $unbind: $unbind,
2389
- $unbindingFromGroup: $unbindingFromGroup,
2390
- $unbindingFromMenu: $unbindingFromMenu,
2391
- $unfavoriteBlock: $unfavoriteBlock,
2392
- $unmute: $unmute,
2393
- $unpay: $unpay,
2394
- $unpin: $unpin,
2395
- $unpinAll: $unpinAll,
2396
- $unpublic: $unpublic,
2397
- $unpublicFolder: $unpublicFolder,
2398
- $unread: $unread,
2399
- $unregister: $unregister,
2400
- $unset: $unset,
2401
- $unsubscribe: $unsubscribe,
2402
- $upBlock: $upBlock,
2403
- $update: $update,
2404
- $updateAttrs: $updateAttrs,
2405
- $updateAvatar: $updateAvatar,
2406
- $updateCards: $updateCards,
2407
- $updateCatalogProduct: $updateCatalogProduct,
2408
- $updateColor: $updateColor,
2409
- $updateContent: $updateContent,
2410
- $updateDeadline: $updateDeadline,
2411
- $updateDescription: $updateDescription,
2412
- $updateFolder: $updateFolder,
2413
- $updateNodes: $updateNodes,
2414
- $updateResponsibleUser: $updateResponsibleUser,
2415
- $updateStyles: $updateStyles,
2416
- $updateTitle: $updateTitle,
2417
- $upload: $upload,
2418
- $uploadFile: $uploadFile,
2419
- $uploadfile: $uploadfile,
2420
- $uploadversion: $uploadversion,
2421
- $url: $url,
2422
- $user: $user,
2423
- $userconsent: $userconsent,
2424
- $userfield: $userfield,
2425
- $userfieldtype: $userfieldtype,
2426
- $users: $users,
2427
- $v1: $v1,
2428
- $v2: $v2,
2429
- $vat: $vat,
2430
- $version: $version,
2431
- $voices: $voices,
2432
- $volatileType: $volatileType,
2433
- $vote: $vote,
2434
- $voximplant: $voximplant,
2435
- $waitlist: $waitlist,
2436
- $workflow: $workflow,
2437
- $workgroup: $workgroup,
2438
- $writing: $writing
2439
- });
2440
-
2441
- class BXRestUserUserfield {
2442
- constructor() {
2443
- this.url = {
2444
- list: [$user, $userfield, $list],
2445
- };
2446
- this.http = new HttpBXServices();
2447
- }
2448
- list() {
2449
- return this.http.post(this.url.list);
2450
- }
2451
- }
2452
-
2453
- class BXRestUser {
2454
- constructor() {
2455
- this.http = new HttpBXServices();
2456
- this.userfield = new BXRestUserUserfield();
2457
- this.url = {
2458
- admin: [$user, 'admin'],
2459
- get: [$user, $get],
2460
- current: [$user, 'current'],
2461
- update: [$user, $update],
2462
- search: [$user, $search],
2463
- access: [$user, 'access'],
2464
- fields: [$user, 'fields'],
2465
- };
2466
- }
2467
- admin() {
2468
- return this.http.post(this.url.admin);
2469
- }
2470
- get(params = {}) {
2471
- return this.http.post(this.url.get, params);
2472
- }
2473
- current() {
2474
- return this.http.post(this.url.current, {});
2475
- }
2476
- update(user) {
2477
- return this.http.post(this.url.update, user);
2478
- }
2479
- search(params) {
2480
- return this.http.post(this.url.search, params);
2481
- }
2482
- access(access) {
2483
- return this.http.post(this.url.access, { ACCESS: access });
2484
- }
2485
- fields() {
2486
- return this.http.post(this.url.fields);
2487
- }
2488
- }
2489
-
2490
- class BXRestListsElement {
2491
- constructor() {
2492
- this.url = {
2493
- add: [$lists, $element, $add],
2494
- get: [$lists, $element, $get],
2495
- };
2496
- this.http = new HttpBXServices();
2497
- }
2498
- get(pram) {
2499
- return this.http.post(this.url.get, pram);
2500
- }
2501
- add(param) {
2502
- return this.http.post(this.url.add, param);
2503
- }
2504
- }
2505
-
2506
- class BXRestListsField {
2507
- constructor() {
2508
- this.url = {
2509
- // /**
2510
- // * Метод создает поле списка
2511
- // */
2512
- // add: [$lists, $field, $add],
2513
- // /**
2514
- // * Метод удаляет поле списка
2515
- // */
2516
- // delete: [$lists, $field, $delete],
2517
- /**
2518
- * Метод возвращает данные поля
2519
- */
2520
- get: [$lists, $field, $get],
2521
- // type: {
2522
- // /**
2523
- // * Метод возвращает доступные типа полей для указанного списка
2524
- // */
2525
- // get: [$lists, $field, $type, $get],
2526
- // },
2527
- // /**
2528
- // * Метод обновляет поле списка
2529
- // */
2530
- // update: [$lists, $field, $update],
2531
- };
2532
- this.http = new HttpBXServices();
2533
- }
2534
- get(param) {
2535
- return this.http.post(this.url.get, param);
2536
- }
2537
- }
2538
-
2539
- class BXRestLists {
2540
- constructor() {
2541
- this.url = {
2542
- // /**
2543
- // * Метод создаёт список
2544
- // */
2545
- // add: [$lists, $add],
2546
- // /**
2547
- // * Метод удаляет список
2548
- // */
2549
- // delete: [$lists, $delete],
2550
- /**
2551
- * Метод возвращает данные по спискам
2552
- */
2553
- get: [$lists, $get],
2554
- // /**
2555
- // * Метод обновляет существующий список
2556
- // */
2557
- // update: [$lists, $update],
2558
- // /**
2559
- // * Метод возвращает id типа инфоблока
2560
- // */
2561
- // getIBlockTypeId: [$lists, $get, $iblock, $type, $id],
2562
- element: {
2563
- /**
2564
- * Метод создаёт элемент списка
2565
- */
2566
- add: [$lists, $element, $add],
2567
- // /**
2568
- // * Метод удаляет элемент списка TODO: Реализовать
2569
- // */
2570
- // delete: [$lists, $element, $delete],
2571
- /**
2572
- * Метод возвращает список элементов или элемент
2573
- */
2574
- get: [$lists, $element, $get],
2575
- // /**
2576
- // * Метод обновляет элемент списка TODO: Реализовать
2577
- // */
2578
- // update: [$lists, $element, $update],
2579
- // /**
2580
- // * Метод возвращает путь к файлу TODO: Реализовать
2581
- // */
2582
- // getFileUrl: [$lists, $element, $get, $file, $url]
2583
- },
2584
- field: {
2585
- // /**
2586
- // * Метод создает поле списка
2587
- // */
2588
- // add: [$lists, $field, $add],
2589
- // /**
2590
- // * Метод удаляет поле списка
2591
- // */
2592
- // delete: [$lists, $field, $delete],
2593
- /**
2594
- * Метод возвращает данные поля
2595
- */
2596
- get: [$lists, $field, $get],
2597
- // type: {
2598
- // /**
2599
- // * Метод возвращает доступные типа полей для указанного списка
2600
- // */
2601
- // get: [$lists, $field, $type, $get],
2602
- // },
2603
- // /**
2604
- // * Метод обновляет поле списка
2605
- // */
2606
- // update: [$lists, $field, $update],
2607
- }
2608
- };
2609
- this.element = new BXRestListsElement();
2610
- this.field = new BXRestListsField();
2611
- this.http = new HttpBXServices();
2612
- }
2613
- // getField(pram: getListFieldParam): Observable<iHttpAnswerBX<FieldItemLists[]> | undefined> {
2614
- // return this.http.post<iHttpAnswerBX<{ [key: string]: FieldItemLists }>>(this.url.field.get, pram)
2615
- // }
2616
- get(param) {
2617
- return this.http.post(this.url.get, param);
2618
- }
2619
- }
2620
-
2621
- class BXRestTaskElapsedItem {
2622
- constructor() {
2623
- this.url = {
2624
- getList: [$task, $elapseditem, $getlist],
2625
- add: [$task, $elapseditem, $add],
2626
- delete: [$task, $elapseditem, $delete],
2627
- isActionAllowed: [$task, $elapseditem, $isactionallowed],
2628
- update: [$task, $elapseditem, $update],
2629
- };
2630
- this.http = new HttpBXServices();
2631
- }
2632
- getList(param = {}) {
2633
- return this.http.post(this.url.getList, param);
2634
- }
2635
- add(param) {
2636
- return this.http.post(this.url.add, param);
2637
- }
2638
- update(param) {
2639
- return this.http.post(this.url.update, param);
2640
- }
2641
- del(param) {
2642
- return this.http.post(this.url.delete, param);
2643
- }
2644
- /**
2645
- * idAction:
2646
- * 1 - ACTION_ELAPSED_TIME_ADD
2647
- * 2 - ACTION_ELAPSED_TIME_MODIFY
2648
- * 3 - ACTION_ELAPSED_TIME_REMOVE
2649
- * ITEMID - обязателен в конечной отправке но не обязателен для ACTION_ELAPSED_TIME_ADD,
2650
- * поэтому этом методе можно ставить "1" например, так же метод может выдавать ошибки о не доступности задачи
2651
- * поэтому рекомендую воспользоваться аналогичным методом в пространстве имен navvy
2652
- * @param param
2653
- */
2654
- isActionAllowed(param) {
2655
- return this.http.post(this.url.isActionAllowed, param);
2656
- }
2657
- }
2658
-
2659
- class BXRestTaskCommentItem {
2660
- constructor() {
2661
- this.url = {
2662
- getManifest: [$task, $commentitem, $getmanifest], // Возвращает список методов и их описание
2663
- getList: [$task, $commentitem, $getlist], // Возвращает список комментариев к задаче
2664
- get: [$task, $commentitem, $get], // Возвращает комментарий к задаче
2665
- add: [$task, $commentitem, $add], // Создает новый комментарий к задаче
2666
- update: [$task, $commentitem, $update], // Обновляет данные комментария
2667
- delete: [$task, $commentitem, $delete], // Удаляет комментарий
2668
- isActionAllowed: [$task, $commentitem, $isactionallowed], // Проверяет, разрешено ли действие
2669
- };
2670
- this.http = new HttpBXServices();
2671
- }
2672
- add(param) {
2673
- return this.http.post(this.url.add, param);
2674
- }
2675
- update(param) {
2676
- return this.http.post(this.url.update, param);
2677
- }
2678
- get(param) {
2679
- return this.http.post(this.url.get, param);
2680
- }
2681
- getlist(param) {
2682
- return this.http.post(this.url.getList, param);
2683
- }
2684
- del(param) {
2685
- return this.http.post(this.url.delete, param);
2686
- }
2687
- }
2688
-
2689
- class BXRestTaskPlanner {
2690
- constructor() {
2691
- this.http = new HttpBXServices();
2692
- }
2693
- getList() {
2694
- return this.http.post([$task, $planner, $getlist]);
2695
- }
2696
- }
2697
-
2698
- class BXRestTaskItemUserField {
2699
- constructor() {
2700
- this.url = {
2701
- getList: [$task, $item, $userfield, 'getlist'],
2702
- };
2703
- this.http = new HttpBXServices();
2704
- }
2705
- getList(param) {
2706
- return this.http.post(this.url.getList, param);
2707
- }
2708
- }
2709
-
2710
- class BXRestTaskItem {
2711
- constructor() {
2712
- this.userField = new BXRestTaskItemUserField();
2713
- }
2714
- }
2715
-
2716
- class BXRestTask {
2717
- constructor() {
2718
- this.elapsedItem = new BXRestTaskElapsedItem();
2719
- this.commentItem = new BXRestTaskCommentItem();
2720
- this.planner = new BXRestTaskPlanner();
2721
- this.item = new BXRestTaskItem();
2722
- }
2723
- }
2724
-
2725
- class BXRestTasksTaskResult {
2726
- constructor() {
2727
- this.url = {
2728
- list: [$tasks, $task, $result, $list],
2729
- addFromComment: [$tasks, $task, $result, 'addFromComment'],
2730
- deleteFromComment: [$tasks, $task, $result, 'deleteFromComment'],
2731
- };
2732
- this.http = new HttpBXServices();
2733
- }
2734
- deleteFromComment(commentID) {
2735
- return this.http.post(this.url.deleteFromComment, { commentId: commentID });
2736
- }
2737
- addFromComment(param) {
2738
- return this.http.post(this.url.addFromComment, param);
2739
- }
2740
- list(param) {
2741
- return this.http.post(this.url.list, param);
2742
- }
2743
- }
2744
-
2745
- class BXRestTasksTask {
2746
- constructor() {
2747
- this.url = {
2748
- add: [$tasks, $task, $add],
2749
- approve: [$tasks, $task, $approve],
2750
- complete: [$tasks, $task, $complete],
2751
- defer: [$tasks, $task, $defer],
2752
- get: [$tasks, $task, $get],
2753
- getFields: [$tasks, $task, $getFields],
2754
- getAccess: [$tasks, $task, $getaccess],
2755
- list: [$tasks, $task, $list],
2756
- update: [$tasks, $task, $update],
2757
- };
2758
- this.result = new BXRestTasksTaskResult();
2759
- this.http = new HttpBXServices();
2760
- }
2761
- add(param) {
2762
- return this.http.post(this.url.add, param);
2763
- }
2764
- approve(param) {
2765
- return this.http.post(this.url.approve, param);
2766
- }
2767
- complete(param) {
2768
- return this.http.post(this.url.complete, param);
2769
- }
2770
- defer(param) {
2771
- return this.http.post(this.url.defer, param);
2772
- }
2773
- update(param) {
2774
- return this.http.post(this.url.update, param);
2775
- }
2776
- get(param) {
2777
- return this.http.post(this.url.get, param);
2778
- }
2779
- list(param) {
2780
- return this.http.post(this.url.list, param);
2781
- }
2782
- /*
2783
- listArray(requestArray: RequestApiTaskListBX = {}) {
2784
- return this.list(requestArray).pipe(
2785
- map(v => this.http.mapResult(v)),
2786
- map(v => (v && v.tasks) ? v.tasks : [])
2787
- )
2788
- }
2789
-
2790
- listAll(requestArray: RequestApiTaskListBX = {}, cache = false): Observable<TaskBX[]> {
2791
- if (!requestArray.select) {
2792
- requestArray.select = this.def.select
2793
- if (cache) {
2794
- return this.storeTask$.pipe(
2795
- take(1),
2796
- mergeMap(tasks => {
2797
- if (tasks && tasks.data.http.list && requestArray.filter && requestArray.filter.ID) {
2798
- const ids = (typeof requestArray.filter.ID === 'number') ? [requestArray.filter.ID] : requestArray.filter.ID
2799
- let filter = tasks.data.http.list.filter(i => (i.id) ? ids.includes(i.id) : false)
2800
- if (filter.length === ids.length) {
2801
- return of(filter)
2802
- }
2803
- }
2804
- return this.getEndListArray(requestArray)
2805
- })
2806
- )
2807
- }
2808
- return this.getEndListArray(requestArray)
2809
- }
2810
- return this.getEndListArray(requestArray)
2811
- }
2812
-
2813
- getEndListArray(requestArray: RequestApiTaskListBX): Observable<TaskBX[]> {
2814
- return this.list(requestArray).pipe(
2815
- mergeMap((items: AnswerApiTaskBX | undefined): ObservableInput<any> | Observable<AnswerApiTaskBX[]> => {
2816
- if (items && items.result && typeof items.result.tasks === 'object') {
2817
- const items$ = of(items.result.tasks)
2818
- if (items.next) {
2819
- this.nowLoad$.next({
2820
- total: (items.total) ? items.total : 0,
2821
- next: items.next
2822
- })
2823
- requestArray.start = items.next
2824
- return this.getEndListArray(requestArray).pipe(
2825
- map(vEnd => {
2826
- if (vEnd && items.result.tasks) {
2827
- return [...items.result.tasks, ...vEnd]
2828
- }
2829
- return (items.result.tasks) ? items.result.tasks : []
2830
- }))
2831
- }
2832
- this.nowLoad$.next({
2833
- total: 0,
2834
- next: 0
2835
- })
2836
- return items$
2837
- } else {
2838
- return of([])
2839
- }
2840
- })
2841
- )
2842
- }
2843
- */
2844
- getFields() {
2845
- return this.http.post(this.url.getFields);
2846
- }
2847
- getAccess(param) {
2848
- return this.http.post(this.url.getAccess, param);
2849
- }
2850
- }
2851
-
2852
- class BXRestTasks {
2853
- constructor() {
2854
- this.task = new BXRestTasksTask();
2855
- }
2856
- }
2857
-
2858
- class BXRestDiskFile {
2859
- constructor() {
2860
- this.url = {
2861
- get: [$disk, $file, $get],
2862
- markDeleted: [$disk, $file, $markdeleted],
2863
- };
2864
- this.http = new HttpBXServices();
2865
- }
2866
- get(param) {
2867
- return this.http.post(this.url.get, param);
2868
- }
2869
- markDeleted(param) {
2870
- return this.http.post(this.url.markDeleted, param);
2871
- }
2872
- }
2873
-
2874
- class BXRestDiskFolder {
2875
- constructor() {
2876
- this.url = {
2877
- getFields: [$disk, $folder, $getFields],
2878
- get: [$disk, $folder, $get],
2879
- getChildren: [$disk, $folder, $getchildren],
2880
- addSubFolder: [$disk, $folder, 'addsubfolder'],
2881
- copyTo: [$disk, $folder, $copyto],
2882
- moveTo: [$disk, $folder, $moveto],
2883
- rename: [$disk, $folder, $rename],
2884
- deleteTree: [$disk, $folder, 'deletetree'],
2885
- markDeleted: [$disk, $folder, $markdeleted],
2886
- restore: [$disk, $folder, $restore],
2887
- uploadFile: [$disk, $folder, $uploadfile],
2888
- getExternalLink: [$disk, $folder, 'getExternalLink'],
2889
- };
2890
- this.http = new HttpBXServices();
2891
- }
2892
- /**
2893
- * Возвращает папку по идентификатору
2894
- *
2895
- * @param param
2896
- */
2897
- get(param) {
2898
- return this.http.post(this.url.get, param);
2899
- }
2900
- /**
2901
- * Создает дочернюю папку
2902
- *
2903
- * @param param
2904
- */
2905
- addSubFolder(param) {
2906
- return this.http.post(this.url.addSubFolder, param);
2907
- }
2908
- /**
2909
- * Копирует папку в указанную папку
2910
- *
2911
- * @param param
2912
- */
2913
- copyTo(param) {
2914
- return this.http.post(this.url.copyTo, param);
2915
- }
2916
- /**
2917
- * Перемещает папку в указанную папку
2918
- *
2919
- * @param param
2920
- */
2921
- moveTo(param) {
2922
- return this.http.post(this.url.moveTo, param);
2923
- }
2924
- /**
2925
- * Переименовывает папку
2926
- *
2927
- * @param param
2928
- */
2929
- rename(param) {
2930
- return this.http.post(this.url.rename, param);
2931
- }
2932
- /**
2933
- * Уничтожает папку и всё её дочерние элементы навсегда
2934
- * В ответе 'result': true - успешное уничтожение папки
2935
- *
2936
- * @param param
2937
- */
2938
- deleteTree(param) {
2939
- return this.http.post(this.url.deleteTree, param);
2940
- }
2941
- /**
2942
- * Перемещает папку в корзину
2943
- *
2944
- * @param param
2945
- */
2946
- markDeleted(param) {
2947
- return this.http.post(this.url.markDeleted, param);
2948
- }
2949
- /**
2950
- * Восстанавливает папку из корзины
2951
- *
2952
- * @param param
2953
- */
2954
- restore(param) {
2955
- return this.http.post(this.url.restore, param);
2956
- }
2957
- /**
2958
- * Метод возвращает публичную ссылку
2959
- *
2960
- * @param param
2961
- */
2962
- getExternalLink(param) {
2963
- return this.http.post(this.url.restore, param);
2964
- }
2965
- /**
2966
- * Возвращает описание полей папки
2967
- */
2968
- getFields() {
2969
- return this.http.post(this.url.getFields);
2970
- }
2971
- /**
2972
- * Загружает новый файл в указанную папку
2973
- *
2974
- * @param param
2975
- */
2976
- uploadFile(param) {
2977
- return this.http.post(this.url.uploadFile, param);
2978
- }
2979
- /**
2980
- * Возвращает список файлов и папок, которые находятся непосредственно в папке
2981
- *
2982
- * @param param
2983
- */
2984
- getChildren(param) {
2985
- return this.http.post(this.url.getChildren, param);
2986
- }
2987
- }
2988
-
2989
- class BXRestDiskAttachedObject {
2990
- constructor() {
2991
- this.url = {
2992
- get: [$disk, 'attachedObject', $get],
2993
- };
2994
- this.http = new HttpBXServices();
2995
- }
2996
- get(param) {
2997
- return this.http.post(this.url.get, param);
2998
- }
2999
- }
3000
-
3001
- class BXRestDisk {
3002
- constructor() {
3003
- this.file = new BXRestDiskFile();
3004
- this.folder = new BXRestDiskFolder();
3005
- this.attachedObject = new BXRestDiskAttachedObject();
3006
- }
3007
- }
3008
-
3009
- class BXRestBizProcWorkflowInstance {
3010
- }
3011
-
3012
- class BXRestBizProcWorkflowTemplate {
3013
- }
3014
-
3015
- class HttpNavvyServices {
3016
- constructor() {
3017
- this.httpServices = new HttpBXServices();
3018
- }
3019
- // Реализация метода
3020
- post(url, params) {
3021
- if (params === undefined) {
3022
- params = {};
3023
- }
3024
- return this.httpServices.post(url, params);
3025
- }
3026
- }
3027
-
3028
- class BXRestBizProcWorkflow {
3029
- constructor() {
3030
- this.instances = new BXRestBizProcWorkflowInstance();
3031
- this.template = new BXRestBizProcWorkflowTemplate();
3032
- this.http = new HttpNavvyServices();
3033
- }
3034
- /**
3035
- * Запускает Бизнес-процесс
3036
- */
3037
- start(param) {
3038
- return this.http.post([$bizproc, $workflow, $start], param);
3039
- }
3040
- }
3041
-
3042
- class BXRestBizProcActivity {
3043
- }
3044
-
3045
- class BXRestBizProcTask {
3046
- }
3047
-
3048
- class BXRestBizProcRobot {
3049
- }
3050
-
3051
- class BXRestBizProcEvent {
3052
- }
3053
-
3054
- class BXRestBizProc {
3055
- constructor() {
3056
- this.workflow = new BXRestBizProcWorkflow();
3057
- this.activity = new BXRestBizProcActivity();
3058
- this.task = new BXRestBizProcTask();
3059
- this.robot = new BXRestBizProcRobot();
3060
- this.event = new BXRestBizProcEvent();
3061
- }
3062
- }
3063
-
3064
- class BXRestLogBlogPost {
3065
- constructor() {
3066
- this.url = {
3067
- add: [$log, $blogpost, $add],
3068
- get: [$log, $blogpost, $get],
3069
- };
3070
- this.http = new HttpBXServices();
3071
- }
3072
- add(param) {
3073
- return this.http.post(this.url.add, param);
3074
- }
3075
- get(param = {}) {
3076
- return this.http.post(this.url.get, param);
3077
- }
3078
- }
3079
-
3080
- class BXRestLogBlogComment {
3081
- }
3082
-
3083
- class BXRestLog {
3084
- constructor() {
3085
- this.blogPost = new BXRestLogBlogPost();
3086
- this.blogComment = new BXRestLogBlogComment();
3087
- }
3088
- }
3089
-
3090
- class BXRestSonetGroup {
3091
- constructor() {
3092
- this.url = {
3093
- get: [$sonet_group, $get],
3094
- };
3095
- this.http = new HttpBXServices();
3096
- }
3097
- // // TODO: filter и select позже нормально описать
3098
- // getList(filter: any = {}, select: iWorkgroupFields[] = ['ID', 'NAME']){
3099
- // return this.httpPost<iHttpAnswerBX<{workgroups: iListWorkgroup[]}>>(
3100
- // this.url.get,
3101
- // {
3102
- // order: select,
3103
- // filter: filter
3104
- // }
3105
- // )
3106
- // }
3107
- get(param = {}) {
3108
- return this.http.post(this.url.get, param);
3109
- }
3110
- }
3111
-
3112
- class BXRestServer {
3113
- constructor() {
3114
- this.http = new HttpBXServices();
3115
- this.url = {
3116
- time: [$server, $time],
3117
- };
3118
- }
3119
- time() {
3120
- return this.http.post(this.url.time);
3121
- }
3122
- }
3123
-
3124
- class BXRestDepartment {
3125
- constructor() {
3126
- this.url = {
3127
- get: [$department, $get],
3128
- del: [$department, $delete],
3129
- add: [$department, $add],
3130
- update: [$department, $update],
3131
- };
3132
- this.http = new HttpBXServices();
3133
- }
3134
- get(param = {}) {
3135
- return this.http.post(this.url.get, param);
3136
- }
3137
- add(param) {
3138
- return this.http.post(this.url.add, param);
3139
- }
3140
- del(param) {
3141
- return this.http.post(this.url.del, param);
3142
- }
3143
- update(param) {
3144
- return this.http.post(this.url.update, param);
3145
- }
3146
- }
3147
-
3148
- class BXRestApp {
3149
- constructor() {
3150
- this.http = new HttpBXServices();
3151
- }
3152
- /**
3153
- * Показ информации о приложении. Метод поддерживает безопасный вызов
3154
- */
3155
- info() {
3156
- return this.http.post(['app', 'info']);
3157
- }
3158
- }
3159
-
3160
- class BXRestSocialNetWorkApiContentView {
3161
- constructor() {
3162
- this.url = {
3163
- set: [$socialnetwork, $api, 'contentView', $set],
3164
- };
3165
- this.http = new HttpBXServices();
3166
- }
3167
- set(param) {
3168
- return this.http.post(this.url.set, param);
3169
- }
3170
- }
3171
-
3172
- class BXRestSocialNetWorkApiLiveFeedBlogPostImportant {
3173
- constructor() {
3174
- this.url = {
3175
- vote: [$socialnetwork, $api, 'liveFeed', 'blogPost', 'important', 'vote'],
3176
- };
3177
- this.http = new HttpBXServices();
3178
- }
3179
- vote(param) {
3180
- return this.http.post(this.url.vote, param);
3181
- }
3182
- }
3183
-
3184
- class BXRestSocialNetWorkApiLiveFeedBlogPost {
3185
- constructor() {
3186
- this.important = new BXRestSocialNetWorkApiLiveFeedBlogPostImportant();
3187
- }
3188
- }
3189
-
3190
- class BXRestSocialNetWorkApiLiveFeed {
3191
- constructor() {
3192
- this.blogPost = new BXRestSocialNetWorkApiLiveFeedBlogPost();
3193
- }
3194
- }
3195
-
3196
- class BXRestSocialNetWorkApi {
3197
- constructor() {
3198
- this.contentView = new BXRestSocialNetWorkApiContentView();
3199
- this.liveFeed = new BXRestSocialNetWorkApiLiveFeed();
3200
- }
3201
- }
3202
-
3203
- class BXRestSocialNetWork {
3204
- constructor() {
3205
- // private http = new HttpBXServices)
3206
- this.api = new BXRestSocialNetWorkApi();
3207
- }
3208
- }
3209
-
3210
- class BXRestPullApplicationConfig {
3211
- constructor() {
3212
- this.http = new HttpBXServices();
3213
- }
3214
- get() {
3215
- return this.http.post([$pull, $application, $config, $get]);
3216
- }
3217
- }
3218
-
3219
- class BXRestPullConfig {
3220
- constructor() {
3221
- this.http = new HttpBXServices();
3222
- this.config = new BXRestPullApplicationConfig();
3223
- }
3224
- get() {
3225
- return this.http.post([$pull, $config, $get]);
3226
- }
3227
- }
3228
-
3229
- class BXRestPullChannelPublic {
3230
- constructor() {
3231
- this.http = new HttpBXServices();
3232
- /**
3233
- * Пес его знает что за метод такой, судя по коду нужно всю инфу json объектом о пользователе передать,
3234
- * но это не точно
3235
- */
3236
- // list() {
3237
- // return this.http.post<iBXRestPullChannelPublicGetHttp>([$pull, $channel, $public, $list])
3238
- // }
3239
- }
3240
- get() {
3241
- return this.http.post([$pull, $channel, $public, $get]);
3242
- }
3243
- }
3244
-
3245
- class BXRestPull {
3246
- constructor() {
3247
- this.config = new BXRestPullConfig();
3248
- this.channel = {
3249
- public: new BXRestPullChannelPublic()
3250
- };
3251
- }
3252
- }
3253
-
3254
- class BXRest {
3255
- constructor() {
3256
- this.http = new HttpBXServices();
3257
- this.user = new BXRestUser();
3258
- this.lists = new BXRestLists();
3259
- this.task = new BXRestTask();
3260
- this.tasks = new BXRestTasks();
3261
- this.disk = new BXRestDisk();
3262
- this.bizProc = new BXRestBizProc();
3263
- this.log = new BXRestLog();
3264
- this.sonet_group = new BXRestSonetGroup();
3265
- this.server = new BXRestServer();
3266
- this.department = new BXRestDepartment();
3267
- this.app = new BXRestApp();
3268
- this.socialNetWork = new BXRestSocialNetWork();
3269
- this.pull = new BXRestPull();
3270
- }
3271
- profile() {
3272
- return this.http.post(['profile']);
3273
- }
3274
- batch(param, headers) {
3275
- return this.http.post(['batch'], param, false, headers);
3276
- }
3277
- }
3278
-
3279
- /**
3280
- * Класс-прослойка-обработчик для методов работающих на альтернативной постраничной навигации тика как методы по
3281
- * затраченному времени на задачи https://dev.1c-bitrix.ru/rest_help/tasks/task/elapseditem/index.php
3282
- *
3283
- * не завершенный класс, работаем от частного к общему
3284
- */
3285
- class NavvyAlterPagNav extends NavvyPagBase {
3286
- resAll() {
3287
- let save = [];
3288
- return this.resultAllEnd()
3289
- .pipe(map(v => {
3290
- if (v) {
3291
- save.push(...v);
3292
- }
3293
- return save;
3294
- }), last(), shareReplay(1));
3295
- }
3296
- resultAllEnd() {
3297
- let BXRestClass = new BXRest();
3298
- // return this.mapForVanillaEnd(this.func, this.param)
3299
- return this.resFirstPage().pipe(mergeMap(items => {
3300
- if (items && instanceOfiBXRestAnswerSuccess(items)) {
3301
- if (items.total && items.next) {
3302
- const count = [...Array(Math.floor(items.total / this.pageSize)).keys()];
3303
- // Разделяем массив на блоки
3304
- const chunks = [];
3305
- for (let i = 0; i < count.length; i += this.pageSize) {
3306
- chunks.push(count.slice(i, i + this.pageSize));
3307
- }
3308
- const batchRequests = chunks.map(chunk => {
3309
- return BXRestClass.batch({
3310
- halt: 1,
3311
- cmd: chunk.map(i => {
3312
- const param = clone(this.param);
3313
- if (!param.PARAMS) {
3314
- param.PARAMS = {
3315
- NAV_PARAMS: {
3316
- iNumPage: 0,
3317
- nPageSize: 50
3318
- }
3319
- };
3320
- }
3321
- // Устанавливаем start в зависимости от индекса
3322
- param.PARAMS.NAV_PARAMS.iNumPage = i + 2; // первая страница уже есть, старт со второй
3323
- // Формируем строку запроса
3324
- return this.http.getNameMethod(this.url)
3325
- + '?' + serializeBitrixParams(param);
3326
- })
3327
- }, this.requestHeaders);
3328
- });
3329
- return from(batchRequests).pipe(concatMap(request => request), // Выполняет запросы по очереди
3330
- toArray(), // Собирает все результаты в массив
3331
- map(results => {
3332
- const res = items.result;
3333
- for (let result of results) {
3334
- if (result && instanceOfiBXRestAnswerSuccess(result) && result.result && result.result.result) {
3335
- res.push(...result.result.result.map(i => i).flat());
3336
- }
3337
- }
3338
- return (this.map) ?
3339
- this.map(res)
3340
- : res;
3341
- }));
3342
- }
3343
- }
3344
- return this.mapResultForGetAll(items);
3345
- }), catchError(err => {
3346
- // this.snackBar.error("Проблемы с поточным получение затреканого времени")
3347
- console.error(err);
3348
- return throwError(() => err);
3349
- }));
3350
- }
3351
- mapResultForGetAll(items) {
3352
- return (instanceOfiBXRestAnswerSuccess(items)) ? from([items.result]).pipe(map(v => (v && this.map) ? this.map(v) : v)) : from([]);
3353
- }
3354
- }
3355
-
3356
- class NavvyPagNavWithUselessKey extends NavvyPagBase {
3357
- constructor() {
3358
- super(...arguments);
3359
- this.save = [];
3360
- }
3361
- resAll() {
3362
- let BXRestClass = new BXRest();
3363
- return this.resFirstPage().pipe(mergeMap(items => {
3364
- if (items && instanceOfiBXRestAnswerSuccess(items)) {
3365
- if (items.total && items.next) {
3366
- const count = [...Array(Math.floor(items.total / this.pageSize)).keys()];
3367
- // Разделяем массив на блоки
3368
- const chunks = [];
3369
- for (let i = 0; i < count.length; i += this.pageSize) {
3370
- chunks.push(count.slice(i, i + this.pageSize));
3371
- }
3372
- const batchRequests = chunks.map(chunk => {
3373
- return BXRestClass.batch({
3374
- halt: 1,
3375
- cmd: chunk.map(i => {
3376
- const param = clone(this.param);
3377
- // Устанавливаем start в зависимости от индекса
3378
- param.start = (i + 1) * this.pageSize;
3379
- // Формируем строку запроса
3380
- return this.http.getNameMethod(this.url)
3381
- + '?' + serializeBitrixParams(param);
3382
- })
3383
- }, this.requestHeaders).pipe(map(v => {
3384
- if (v && instanceOfiBXRestAnswerSuccess(v) && v.result && v.result.result && items.result) {
3385
- return Object.assign({}, items.result, v.result.result);
3386
- }
3387
- throw new Error('wrong batch');
3388
- }));
3389
- });
3390
- return from(batchRequests).pipe(concatMap(request => request), // Выполняет запросы по очереди
3391
- toArray()); // Собирает все результаты в массив
3392
- /*
3393
- return this.getAllTaskElapsedItem(func, param).pipe(
3394
- map(vEnd => {
3395
- if (vEnd && vEnd.result && items.result) {
3396
- return merge(clone(vEnd), {result: [...items.result, ...vEnd.result]})
3397
- }
3398
- return items
3399
- })
3400
- )
3401
- */
3402
- }
3403
- else {
3404
- return of([items.result]);
3405
- }
3406
- }
3407
- return of(undefined);
3408
- // return from([BXRestMapResult(items)])
3409
- // as ReturnType<Observable<T | undefined>, Observable<R | undefined>>
3410
- }), map(v => {
3411
- if (v) {
3412
- const mergedObject = v.reduce((acc, obj) => {
3413
- return { ...acc, ...obj };
3414
- }, {});
3415
- if (this.map) {
3416
- return this.map(mergedObject);
3417
- }
3418
- this.save.push(...v);
3419
- return this.save;
3420
- }
3421
- return v;
3422
- }), catchError(err => {
3423
- // this.snackBar.error("Проблемы с поточным получение затреканого времени")
3424
- console.error(err);
3425
- return throwError(() => err);
3426
- }));
3427
- }
3428
- }
3429
-
3430
- class NavvyPagNavTasks extends NavvyPagBase {
3431
- constructor(url, param, map, restApi) {
3432
- // Без своего map результат — массив задач, как и обещают типы `.res()` и `.resAll()`.
3433
- super(url, param, map ?? (result => (result?.tasks ?? [])), restApi);
3434
- this.save = [];
3435
- }
3436
- resAll() {
3437
- let save = [];
3438
- return this.resultAllEnd()
3439
- .pipe(map(v => {
3440
- if (v) {
3441
- save.push(...v);
3442
- }
3443
- return save;
3444
- }), last(), shareReplay(1));
3445
- }
3446
- resultAllEnd() {
3447
- let BXRestClass = new BXRest();
3448
- return this.resFirstPage().pipe(mergeMap(items => {
3449
- if (items && instanceOfiBXRestAnswerSuccess(items)) {
3450
- this.save = [];
3451
- // TODO: проверить будет ли быстрее работать метод в случаях когда total < 100 (то есть можно обойтись двумя прямыми запросами)
3452
- if (items.total && items.total > 50) {
3453
- const count = [...Array(Math.floor(items.total / this.pageSize)).keys()];
3454
- // Разделяем массив на блоки
3455
- const chunks = [];
3456
- for (let i = 0; i < count.length; i += this.pageSize) {
3457
- chunks.push(count.slice(i, i + this.pageSize));
3458
- }
3459
- const batchRequests = chunks.map(chunk => {
3460
- return BXRestClass.batch({
3461
- halt: 1,
3462
- cmd: chunk.map(i => {
3463
- const param = clone(this.param);
3464
- // Устанавливаем start в зависимости от индекса
3465
- param.start = (i + 1) * this.pageSize;
3466
- // Формируем строку запроса
3467
- return this.http.getNameMethod(this.url)
3468
- + '?' + serializeBitrixParams(param);
3469
- })
3470
- }, this.requestHeaders);
3471
- });
3472
- return from(batchRequests).pipe(concatMap(request => request), // Выполняет запросы по очереди
3473
- toArray(), // Собирает все результаты в массив
3474
- map(results => {
3475
- if (items.result && items.result.tasks) {
3476
- const res = items.result.tasks;
3477
- for (let result of results) {
3478
- if (result && instanceOfiBXRestAnswerSuccess(result) && result.result && result.result.result) {
3479
- res.push(...result.result.result.filter(i => i).map(i => i.tasks).flat());
3480
- }
3481
- }
3482
- return (this.map) ?
3483
- this.map({ tasks: res })
3484
- : res;
3485
- }
3486
- throw new Error('wrong batch');
3487
- }));
3488
- }
3489
- return this.mapResForGetAll(items);
3490
- }
3491
- return this.mapResForGetAll(items);
3492
- }), catchError(err => {
3493
- console.error(err);
3494
- return throwError(() => err);
3495
- }));
3496
- }
3497
- mapResForGetAll(items) {
3498
- return (instanceOfiBXRestAnswerSuccess(items)) ? from([items.result]).pipe(map(v => (v && this.map) ? this.map(v) : v)) : from([]);
3499
- }
3500
- }
3501
-
3502
- class NavvyPag extends NavvyPagBase {
3503
- constructor() {
3504
- super(...arguments);
3505
- this.save = [];
3506
- }
3507
- resAll() {
3508
- let BXRestClass = new BXRest();
3509
- return this.resFirstPage().pipe(mergeMap(items => {
3510
- if (items && instanceOfiBXRestAnswerSuccess(items)) {
3511
- this.save = [];
3512
- // TODO: проверить будет ли быстрее работать метод в случаях когда total < 100 (то есть можно обойтись двумя прямыми запросами)
3513
- if (items.total && items.total > this.pageSize) {
3514
- const mathFloor = Math.floor(items.total / this.pageSize);
3515
- const count = (mathFloor === items.total / this.pageSize) // если mathFloor равен обычному делению, значит один запрос будет лишним, так как результат первой страницы уже есть, а последняя в данном случаи будет пустая (или с мусорными аднными)
3516
- ? [...Array(mathFloor - 1).keys()]
3517
- : [...Array(mathFloor).keys()];
3518
- // Разделяем массив на блоки
3519
- const chunks = [];
3520
- for (let i = 0; i < count.length; i += this.pageSize) {
3521
- chunks.push(count.slice(i, i + this.pageSize));
3522
- }
3523
- const batchRequests = chunks.map(chunk => {
3524
- return BXRestClass.batch({
3525
- halt: 1,
3526
- cmd: chunk.map(i => {
3527
- const param = clone(this.param);
3528
- // Устанавливаем start в зависимости от индекса
3529
- param.start = (i + 1) * this.pageSize;
3530
- // Формируем строку запроса
3531
- return this.http.getNameMethod(this.url)
3532
- + '?' + serializeBitrixParams(param);
3533
- })
3534
- }, this.requestHeaders).pipe();
3535
- });
3536
- return from(batchRequests).pipe(concatMap(request => request), // Выполняет запросы по очереди
3537
- toArray(), // Собирает все результаты в массив
3538
- map(results => {
3539
- const res = items.result;
3540
- for (let result of results) {
3541
- if (result && instanceOfiBXRestAnswerSuccess(result) && result.result && result.result.result) {
3542
- res.push(...result.result.result.map(i => i).flat());
3543
- }
3544
- }
3545
- return (this.map) ?
3546
- this.map(res)
3547
- : res;
3548
- }));
3549
- }
3550
- return this.mapResForGetAll(items);
3551
- }
3552
- return this.mapResForGetAll(items);
3553
- }), map(v => {
3554
- if (v) {
3555
- this.save.push(...v);
3556
- }
3557
- return this.save;
3558
- }));
3559
- }
3560
- mapResForGetAll(items) {
3561
- return (instanceOfiBXRestAnswerSuccess(items)) ? from([items.result]).pipe(map(v => (v && this.map) ? this.map(v) : v)) : from([]);
3562
- }
3563
- }
3564
-
3565
- class NavvyPagNavResultKey extends NavvyPagBase {
3566
- constructor(url, param, key, map) {
3567
- // Без своего map результат — массив по ключу, как и обещают типы `.res()` и `.resAll()`.
3568
- // Иначе `.res()` отдал бы весь объект `{ items: [...] }`, а `.resAll()` упал бы на нём
3569
- // при 50 записях и меньше: первая страница разворачивается через `save.push(...v)`.
3570
- super(url, param, map ?? (result => (result?.[key] ?? [])));
3571
- this.key = key;
3572
- this.save = [];
3573
- }
3574
- resAll() {
3575
- let save = [];
3576
- return this.resultAllEnd()
3577
- .pipe(map(v => {
3578
- if (v) {
3579
- save.push(...v);
3580
- }
3581
- return save;
3582
- }), last(), shareReplay(1));
3583
- }
3584
- resultAllEnd() {
3585
- let BXRestClass = new BXRest();
3586
- return this.resFirstPage().pipe(mergeMap(items => {
3587
- if (items && instanceOfiBXRestAnswerSuccess(items)) {
3588
- this.save = [];
3589
- if (items.total && items.total > 50) {
3590
- const mathFloor = Math.floor(items.total / this.pageSize);
3591
- const count = (mathFloor === items.total / this.pageSize)
3592
- ? [...Array(mathFloor - 1).keys()]
3593
- : [...Array(mathFloor).keys()];
3594
- const chunks = [];
3595
- for (let i = 0; i < count.length; i += this.pageSize) {
3596
- chunks.push(count.slice(i, i + this.pageSize));
3597
- }
3598
- const batchRequests = chunks.map(chunk => {
3599
- return BXRestClass.batch({
3600
- halt: 1,
3601
- cmd: chunk.map(i => {
3602
- const param = clone(this.param);
3603
- param.start = (i + 1) * this.pageSize;
3604
- return this.http.getNameMethod(this.url)
3605
- + '?' + serializeBitrixParams(param);
3606
- })
3607
- }, this.requestHeaders);
3608
- });
3609
- return from(batchRequests).pipe(concatMap(request => request), toArray(), map(results => {
3610
- const firstPage = items.result?.[this.key];
3611
- if (firstPage) {
3612
- const res = firstPage;
3613
- for (let result of results) {
3614
- if (result && instanceOfiBXRestAnswerSuccess(result) && result.result && result.result.result) {
3615
- res.push(...result.result.result.filter(i => i).map(i => i[this.key]).flat());
3616
- }
3617
- }
3618
- return (this.map) ?
3619
- this.map({ [this.key]: res })
3620
- : res;
3621
- }
3622
- throw new Error('wrong batch');
3623
- }));
3624
- }
3625
- return this.mapResForGetAll(items);
3626
- }
3627
- return this.mapResForGetAll(items);
3628
- }), catchError(err => {
3629
- console.error(err);
3630
- return throwError(() => err);
3631
- }));
3632
- }
3633
- mapResForGetAll(items) {
3634
- return (instanceOfiBXRestAnswerSuccess(items)) ? from([items.result]).pipe(map(v => (v && this.map) ? this.map(v) : v)) : from([]);
3635
- }
3636
- }
3637
-
3638
- /** Пагинация для методов, возвращающих коллекцию как объект с идентификаторами в ключах. */
3639
- class NavvyPagNavResultKeyObject extends NavvyPagBase {
3640
- constructor(url, param, key, mapResult) {
3641
- // Без своего map результат — значения объекта по ключу, как и обещают типы `.res()` и `.resAll()`.
3642
- super(url, param, mapResult ?? (result => Object.values(result?.[key] ?? {})));
3643
- this.key = key;
3644
- }
3645
- resAll() {
3646
- return this.resultAllEnd().pipe(last(), shareReplay(1));
3647
- }
3648
- resultAllEnd() {
3649
- const bxRest = new BXRest();
3650
- return this.resFirstPage().pipe(mergeMap(items => {
3651
- if (!items || !instanceOfiBXRestAnswerSuccess(items)) {
3652
- return from([]);
3653
- }
3654
- if (!items.total || items.total <= this.pageSize) {
3655
- return this.mapResult(items);
3656
- }
3657
- const pageCount = Math.ceil(items.total / this.pageSize);
3658
- const commands = Array.from({ length: pageCount - 1 }, (_, index) => {
3659
- const param = clone(this.param);
3660
- param.start = (index + 1) * this.pageSize;
3661
- return bxRest.batch({
3662
- halt: 1,
3663
- cmd: [this.http.getNameMethod(this.url) + '?' + serializeBitrixParams(param)]
3664
- }, this.requestHeaders);
3665
- });
3666
- return from(commands).pipe(concatMap(request => request), toArray(), mergeMap(results => {
3667
- const merged = { ...(items.result?.[this.key] ?? {}) };
3668
- for (const result of results) {
3669
- if (result && instanceOfiBXRestAnswerSuccess(result)) {
3670
- for (const page of result.result?.result ?? []) {
3671
- Object.assign(merged, page?.[this.key] ?? {});
3672
- }
3673
- }
3674
- }
3675
- return this.mapResult({ result: { [this.key]: merged } });
3676
- }));
3677
- }), catchError(error => {
3678
- console.error(error);
3679
- return throwError(() => error);
3680
- }));
3681
- }
3682
- mapResult(items) {
3683
- if (!instanceOfiBXRestAnswerSuccess(items)) {
3684
- return from([]);
3685
- }
3686
- return from([items.result]).pipe(map$1(value => this.map?.(value)));
3687
- }
3688
- }
3689
-
3690
- class NavvySupport {
3691
- constructor(requestClass) {
3692
- this.requestClass = requestClass;
3693
- this.pageSize = 50; // стандартный размер страницы
3694
- }
3695
- mapAndError(request) {
3696
- return request.pipe(map(v => BXRestMapResult(v)), catchError((err) => {
3697
- console.error(err);
3698
- throw new Error((err.error) ? err.error : err);
3699
- }));
3700
- }
3701
- }
3702
-
3703
- class Navvy {
3704
- simple(url, arg, map) {
3705
- return new NavvySimple(url, arg !== undefined ? arg : undefined, map);
3706
- }
3707
- simpleV3(url, arg, map) {
3708
- return new NavvySimple(url, arg !== undefined ? arg : undefined, map, true);
3709
- }
3710
- /**
3711
- * Новый, пока тестируемый метод для api методов с пагинацией
3712
- *
3713
- * @param url
3714
- * @param arg
3715
- * @param map
3716
- * @constructor
3717
- */
3718
- pagNav(url, arg, map) {
3719
- return new NavvyPag(url, arg, map);
3720
- }
3721
- // old PagNav
3722
- // PagNav<T, R, A extends iBXRestPagination>(
3723
- // func: (param: A) => Observable<iBXRestAnswer<T[]> | undefined>,
3724
- // arg: A,
3725
- // map: ((param: T[] | undefined) => R[] | undefined) | undefined) {
3726
- // return new NavvyPagNav(this.requestClass, this.mapClass, func, arg, map)
3727
- // }
3728
- // Batch<T, R, A extends iBXRestPagination>(
3729
- // func: (param: A) => Observable<iBXRestAnswer<T[]> | undefined>,
3730
- // arg: A,
3731
- // map: ((param: T[] | undefined) => R[] | undefined) | undefined) {
3732
- // return new NavvyBatch(this.requestClass, this.mapClass, func, arg, map)
3733
- // }
3734
- pagNavTasks(url,
3735
- // func: (param: A) => Observable<iBXRestAnswer<{tasks: T[] | undefined}> | undefined>,
3736
- arg, map) {
3737
- return new NavvyPagNavTasks(url, arg, map);
3738
- }
3739
- pagNavResultKey(url, arg, key, map) {
3740
- return new NavvyPagNavResultKey(url, arg, key, map);
3741
- }
3742
- pagNavResultKeyObject(url, arg, key, map) {
3743
- return new NavvyPagNavResultKeyObject(url, arg, key, map);
3744
- }
3745
- pagNavWithUselessKey(url,
3746
- // func: (param: A) => Observable<iBXRestAnswer<{ [key: string]: T }> | undefined>,
3747
- arg, map) {
3748
- return new NavvyPagNavWithUselessKey(url, arg, map);
3749
- }
3750
- alterPagNav(url,
3751
- // func: (param: A) => Observable<iBXRestAnswer<T[]> | undefined>,
3752
- arg, map) {
3753
- return new NavvyAlterPagNav(url, arg, map);
3754
- }
3755
- }
2590
+ $read: $read,
2591
+ $reading: $reading,
2592
+ $recall: $recall,
2593
+ $recent: $recent,
2594
+ $recipient: $recipient,
2595
+ $record: $record,
2596
+ $recurring: $recurring,
2597
+ $region: $region,
2598
+ $register: $register,
2599
+ $remove: $remove,
2600
+ $removeAttachments: $removeAttachments,
2601
+ $removeCard: $removeCard,
2602
+ $removeEntities: $removeEntities,
2603
+ $removecrmactivity: $removecrmactivity,
2604
+ $rename: $rename,
2605
+ $renew: $renew,
2606
+ $reply: $reply,
2607
+ $repo: $repo,
2608
+ $report: $report,
2609
+ $reports: $reports,
2610
+ $repowidget: $repowidget,
2611
+ $request: $request,
2612
+ $requisite: $requisite,
2613
+ $reset: $reset,
2614
+ $resolveIdByPublicUrl: $resolveIdByPublicUrl,
2615
+ $resource: $resource,
2616
+ $resourcetype: $resourcetype,
2617
+ $restore: $restore,
2618
+ $restoreFromVersion: $restoreFromVersion,
2619
+ $result: $result,
2620
+ $resume: $resume,
2621
+ $revision: $revision,
2622
+ $rights: $rights,
2623
+ $robot: $robot,
2624
+ $role: $role,
2625
+ $roundingRule: $roundingRule,
2626
+ $sale: $sale,
2627
+ $save: $save,
2628
+ $schedule: $schedule,
2629
+ $schema: $schema,
2630
+ $search: $search,
2631
+ $searchCrmEntities: $searchCrmEntities,
2632
+ $section: $section,
2633
+ $send: $send,
2634
+ $sendContext: $sendContext,
2635
+ $sendMessage: $sendMessage,
2636
+ $sender: $sender,
2637
+ $senders: $senders,
2638
+ $server: $server,
2639
+ $service: $service,
2640
+ $session: $session,
2641
+ $set: $set,
2642
+ $setAccessCodes: $setAccessCodes,
2643
+ $setDelivery: $setDelivery,
2644
+ $setLandingRef: $setLandingRef,
2645
+ $setOwner: $setOwner,
2646
+ $setQuantity: $setQuantity,
2647
+ $setRights: $setRights,
2648
+ $setSiteRef: $setSiteRef,
2649
+ $setowner: $setowner,
2650
+ $settings: $settings,
2651
+ $share: $share,
2652
+ $sharetouser: $sharetouser,
2653
+ $shipment: $shipment,
2654
+ $shipmentItem: $shipmentItem,
2655
+ $shipmentProperty: $shipmentProperty,
2656
+ $shipmentPropertyValue: $shipmentPropertyValue,
2657
+ $show: $show,
2658
+ $showBlock: $showBlock,
2659
+ $sign: $sign,
2660
+ $silent: $silent,
2661
+ $sip: $sip,
2662
+ $site: $site,
2663
+ $skip: $skip,
2664
+ $sku: $sku,
2665
+ $slots: $slots,
2666
+ $socialnetwork: $socialnetwork,
2667
+ $sonet_group: $sonet_group,
2668
+ $source: $source,
2669
+ $spam: $spam,
2670
+ $stagehistory: $stagehistory,
2671
+ $stages: $stages,
2672
+ $start: $start,
2673
+ $startwatch: $startwatch,
2674
+ $startwithsound: $startwithsound,
2675
+ $startwithtext: $startwithtext,
2676
+ $statistic: $statistic,
2677
+ $status: $status,
2678
+ $statusLang: $statusLang,
2679
+ $statuslist: $statuslist,
2680
+ $stop: $stop,
2681
+ $stopwatch: $stopwatch,
2682
+ $storage: $storage,
2683
+ $store: $store,
2684
+ $storeProduct: $storeProduct,
2685
+ $subscribe: $subscribe,
2686
+ $syspage: $syspage,
2687
+ $system: $system,
2688
+ $tail: $tail,
2689
+ $task: $task,
2690
+ $tasks: $tasks,
2691
+ $telephony: $telephony,
2692
+ $template: $template,
2693
+ $terminate: $terminate,
2694
+ $text: $text,
2695
+ $textField: $textField,
2696
+ $thread: $thread,
2697
+ $time: $time,
2698
+ $timeMan: $timeMan,
2699
+ $timecontrol: $timecontrol,
2700
+ $timeline: $timeline,
2701
+ $todo: $todo,
2702
+ $trace: $trace,
2703
+ $tracking: $tracking,
2704
+ $tradeBinding: $tradeBinding,
2705
+ $tradePlatform: $tradePlatform,
2706
+ $transfer: $transfer,
2707
+ $tree: $tree,
2708
+ $trigger: $trigger,
2709
+ $tts: $tts,
2710
+ $type: $type,
2711
+ $types: $types,
2712
+ $unbind: $unbind,
2713
+ $unbindingFromGroup: $unbindingFromGroup,
2714
+ $unbindingFromMenu: $unbindingFromMenu,
2715
+ $unfavoriteBlock: $unfavoriteBlock,
2716
+ $unmute: $unmute,
2717
+ $unpay: $unpay,
2718
+ $unpin: $unpin,
2719
+ $unpinAll: $unpinAll,
2720
+ $unpublic: $unpublic,
2721
+ $unpublicFolder: $unpublicFolder,
2722
+ $unread: $unread,
2723
+ $unregister: $unregister,
2724
+ $unset: $unset,
2725
+ $unsubscribe: $unsubscribe,
2726
+ $upBlock: $upBlock,
2727
+ $update: $update,
2728
+ $updateAttrs: $updateAttrs,
2729
+ $updateAvatar: $updateAvatar,
2730
+ $updateCards: $updateCards,
2731
+ $updateCatalogProduct: $updateCatalogProduct,
2732
+ $updateColor: $updateColor,
2733
+ $updateContent: $updateContent,
2734
+ $updateDeadline: $updateDeadline,
2735
+ $updateDescription: $updateDescription,
2736
+ $updateFolder: $updateFolder,
2737
+ $updateNodes: $updateNodes,
2738
+ $updateResponsibleUser: $updateResponsibleUser,
2739
+ $updateStyles: $updateStyles,
2740
+ $updateTitle: $updateTitle,
2741
+ $upload: $upload,
2742
+ $uploadFile: $uploadFile,
2743
+ $uploadfile: $uploadfile,
2744
+ $uploadversion: $uploadversion,
2745
+ $url: $url,
2746
+ $user: $user,
2747
+ $userconsent: $userconsent,
2748
+ $userfield: $userfield,
2749
+ $userfieldtype: $userfieldtype,
2750
+ $users: $users,
2751
+ $v1: $v1,
2752
+ $v2: $v2,
2753
+ $vat: $vat,
2754
+ $version: $version,
2755
+ $voices: $voices,
2756
+ $volatileType: $volatileType,
2757
+ $vote: $vote,
2758
+ $voximplant: $voximplant,
2759
+ $waitlist: $waitlist,
2760
+ $workflow: $workflow,
2761
+ $workgroup: $workgroup,
2762
+ $writing: $writing
2763
+ });
3756
2764
 
3757
2765
  class BXRestNavvyUserUserfield {
3758
2766
  constructor() {
@@ -3801,8 +2809,9 @@ class BXRestMapUser {
3801
2809
  let res = Object.assign(clone(user), {
3802
2810
  ID: toNum(user.ID),
3803
2811
  IS_ONLINE: toBool(user.IS_ONLINE),
3804
- DATE_REGISTER: toDate(user.DATE_REGISTER),
3805
- PERSONAL_BIRTHDAY: toDate(user.PERSONAL_BIRTHDAY),
2812
+ // Дня рождения может не быть вовсе (пустая строка), а при урезанном scope нет и самих полей
2813
+ DATE_REGISTER: user.DATE_REGISTER ? toDate(user.DATE_REGISTER) : undefined,
2814
+ PERSONAL_BIRTHDAY: user.PERSONAL_BIRTHDAY ? toDate(user.PERSONAL_BIRTHDAY) : undefined,
3806
2815
  });
3807
2816
  if (user.LAST_LOGIN) {
3808
2817
  res.LAST_LOGIN = toDate(user.LAST_LOGIN);
@@ -3813,7 +2822,7 @@ class BXRestMapUser {
3813
2822
  return Object.assign(clone(user), {
3814
2823
  ID: toStr(user.ID),
3815
2824
  IS_ONLINE: toBXYorN(user.IS_ONLINE),
3816
- DATE_REGISTER: toISOStringWithTimezone(user.DATE_REGISTER),
2825
+ DATE_REGISTER: user.DATE_REGISTER ? toISOStringWithTimezone(user.DATE_REGISTER) : '',
3817
2826
  PERSONAL_BIRTHDAY: toStr(user.PERSONAL_BIRTHDAY),
3818
2827
  LAST_LOGIN: toStr(user.LAST_LOGIN)
3819
2828
  });
@@ -4306,8 +3315,8 @@ class BXRestMapTasksTaskResult {
4306
3315
  }
4307
3316
 
4308
3317
  class BXRestMapTasksTask {
4309
- constructor() {
4310
- this.result = BXRestMapTasksTaskResult;
3318
+ static get result() {
3319
+ return BXRestMapTasksTaskResult;
4311
3320
  }
4312
3321
  static getAccess(v) {
4313
3322
  return (v && v.allowedActions) ? v.allowedActions : undefined;
@@ -4696,12 +3705,6 @@ class BXRestNavvyTasksTask {
4696
3705
  * Переводит задачу в статус «завершена»
4697
3706
  */
4698
3707
  complete: [$tasks, $task, $complete],
4699
- // counters: {
4700
- // /**
4701
- // * Получает счетчики пользователя
4702
- // */
4703
- // get: [$tasks, $task, $counters, $get],
4704
- // },
4705
3708
  /**
4706
3709
  * Переводит задачу в статус «отложена»
4707
3710
  */
@@ -4714,30 +3717,6 @@ class BXRestNavvyTasksTask {
4714
3717
  * Возвращает информацию о конкретной задаче
4715
3718
  */
4716
3719
  get: [$tasks, $task, $get],
4717
- // /**
4718
- // * Удаляет задачу
4719
- // */
4720
- // delete: [$tasks, $task, $delete],
4721
- // /**
4722
- // * Позволяет отклонить задачу
4723
- // */
4724
- // disapprove: [$tasks, $task, $disapprove],
4725
- // favorite: {
4726
- // /**
4727
- // * Добавляет задачи в "Избранное"
4728
- // */
4729
- // add: [$tasks, $task, $favorite, $add],
4730
- // /**
4731
- // * Удаляет задачи из "Избранного"
4732
- // */
4733
- // delete: [$tasks, $task, $favorite, $delete],
4734
- // },
4735
- // files: {
4736
- // /**
4737
- // * Прикрепляет загруженный на диск файл к задаче
4738
- // */
4739
- // attach: [$tasks, $task, $files, $attach],
4740
- // },
4741
3720
  /**
4742
3721
  * Возвращает все доступные поля
4743
3722
  */
@@ -4746,36 +3725,10 @@ class BXRestNavvyTasksTask {
4746
3725
  * Метод для проверки доступа к задаче
4747
3726
  */
4748
3727
  getAccess: [$tasks, $task, $getaccess],
4749
- // history: {
4750
- // /**
4751
- // * Получает историю задачи
4752
- // */
4753
- // list: [$tasks, $task, $history, $list],
4754
- // },
4755
3728
  /**
4756
3729
  * Возвращает массив задач, каждая из которых содержит массив полей
4757
3730
  */
4758
3731
  list: [$tasks, $task, $list],
4759
- // /**
4760
- // * Останавливает выполнение задачи, переводя ее в статус "ждет выполнения"
4761
- // */
4762
- // pause: [$tasks, $task, $pause],
4763
- // /**
4764
- // * Возобновляет задачу после ее завершения
4765
- // */
4766
- // renew: [$tasks, $task, $renew],
4767
- // /**
4768
- // * Переводит задачу в статус «выполняется»
4769
- // */
4770
- // start: [$tasks, $task, $start],
4771
- // /**
4772
- // * Позволяет наблюдать за задачей
4773
- // */
4774
- // startWatch: [$tasks, $task, 'startwatch'],
4775
- // /**
4776
- // * Останавливает наблюдение за задачей
4777
- // */
4778
- // stopwatch: [$tasks, $task, 'stopwatch'],
4779
3732
  /**
4780
3733
  * Обновляет задачу
4781
3734
  */
@@ -4880,68 +3833,6 @@ class BXRestNavvyTasksTask {
4880
3833
  list(param = {}) {
4881
3834
  return this.Navvy.pagNavTasks(this.url.list, param, (BXRestMapTasksTask.list));
4882
3835
  }
4883
- /*
4884
- listArray(requestArray: RequestApiTaskListBX = {}) {
4885
- return this.list(requestArray).pipe(
4886
- map(v => this.http.mapResult(v)),
4887
- map(v => (v && v.tasks) ? v.tasks : [])
4888
- )
4889
- }
4890
-
4891
- listAll(requestArray: RequestApiTaskListBX = {}, cache = false): Observable<TaskBX[]> {
4892
- if (!requestArray.select) {
4893
- requestArray.select = this.def.select
4894
- if (cache) {
4895
- return this.storeTask$.pipe(
4896
- take(1),
4897
- mergeMap(tasks => {
4898
- if (tasks && tasks.data.http.list && requestArray.filter && requestArray.filter.ID) {
4899
- const ids = (typeof requestArray.filter.ID === 'number') ? [requestArray.filter.ID] : requestArray.filter.ID
4900
- let filter = tasks.data.http.list.filter(i => (i.id) ? ids.includes(i.id) : false)
4901
- if (filter.length === ids.length) {
4902
- return of(filter)
4903
- }
4904
- }
4905
- return this.getEndListArray(requestArray)
4906
- })
4907
- )
4908
- }
4909
- return this.getEndListArray(requestArray)
4910
- }
4911
- return this.getEndListArray(requestArray)
4912
- }
4913
-
4914
- getEndListArray(requestArray: RequestApiTaskListBX): Observable<TaskBX[]> {
4915
- return this.list(requestArray).pipe(
4916
- mergeMap((items: AnswerApiTaskBX | undefined): ObservableInput<any> | Observable<AnswerApiTaskBX[]> => {
4917
- if (items && items.result && typeof items.result.tasks === 'object') {
4918
- const items$ = of(items.result.tasks)
4919
- if (items.next) {
4920
- this.nowLoad$.next({
4921
- total: (items.total) ? items.total : 0,
4922
- next: items.next
4923
- })
4924
- requestArray.start = items.next
4925
- return this.getEndListArray(requestArray).pipe(
4926
- map(vEnd => {
4927
- if (vEnd && items.result.tasks) {
4928
- return [...items.result.tasks, ...vEnd]
4929
- }
4930
- return (items.result.tasks) ? items.result.tasks : []
4931
- }))
4932
- }
4933
- this.nowLoad$.next({
4934
- total: 0,
4935
- next: 0
4936
- })
4937
- return items$
4938
- } else {
4939
- return of([])
4940
- }
4941
- })
4942
- )
4943
- }
4944
- */
4945
3836
  /**
4946
3837
  * Возвращает список полей задачи.
4947
3838
  */
@@ -5272,6 +4163,10 @@ class BXRestNavvyOperationElapsedItem {
5272
4163
  * Возвращает список записей о затраченном времени по задаче.
5273
4164
  */
5274
4165
  getListByIDTask(ids) {
4166
+ // Пустой batch завершается без значения, и вызывающий код получил бы EmptyError
4167
+ if (!ids.length) {
4168
+ return of([]);
4169
+ }
5275
4170
  // Работает только потому что "nPageSize: 99999"
5276
4171
  return this.http.branch(ids.map(i => {
5277
4172
  return {
@@ -5374,33 +4269,17 @@ class BXRestNavvyOperationElapsedItem {
5374
4269
  * @param userCurrent
5375
4270
  */
5376
4271
  checkPermissionAddElapsedTimeToTask(idTask, userCurrent = undefined) {
5377
- // let permission = Permission.get()
5378
- // if (permission?.tasks?.length) {
5379
- // let findTask = permission.tasks.find(i => i.id === idTask)
5380
- // if (findTask?.permission) {
5381
- // return of(findTask.permission['ELAPSEDTIME.ADD'])
5382
- // }
5383
4272
  return ((userCurrent) ? of(userCurrent) : this.BXRestNavvyUser.current().res()).pipe(mergeMap(self => {
5384
4273
  if (self) {
5385
4274
  return this.BXRestNavvyTasks.task.getAccess({
5386
4275
  id: idTask,
5387
4276
  users: [self.ID]
5388
- }).res().pipe(
5389
- // tap(v => {
5390
- // if (v && v[self.ID]) {
5391
- // Permission.set({
5392
- // tasks: [{id: idTask, permission: v[self.ID], elapsedItem: []}]
5393
- // })
5394
- // }
5395
- // }),
5396
- map(v => {
4277
+ }).res().pipe(map(v => {
5397
4278
  return (v && v[self.ID]) ? v[self.ID]['ELAPSEDTIME.ADD'] : false;
5398
4279
  }));
5399
4280
  }
5400
4281
  return of(undefined);
5401
4282
  }));
5402
- // }
5403
- // return of(undefined)
5404
4283
  }
5405
4284
  /**
5406
4285
  * Проверка на возможность прочтения такски
@@ -5409,35 +4288,17 @@ class BXRestNavvyOperationElapsedItem {
5409
4288
  * @param userCurrent
5410
4289
  */
5411
4290
  checkPermissionReadTask(idTask, userCurrent = undefined) {
5412
- // let permission = Permission.get()
5413
- // if (permission?.tasks?.length) {
5414
- // let findTask = permission.tasks.find(i => i.id === idTask)
5415
- // if (findTask?.permission) {
5416
- // return of(findTask.permission.ACCEPT)
5417
- // }
5418
- // console.log('idTask', idTask)
5419
4291
  return ((userCurrent) ? of(userCurrent) : this.BXRestNavvyUser.current().res()).pipe(mergeMap(self => {
5420
4292
  if (self) {
5421
4293
  return this.BXRestNavvyTasks.task.getAccess({
5422
4294
  id: idTask,
5423
4295
  users: [self.ID]
5424
- }).res().pipe(
5425
- // tap(v => {
5426
- // if (v && v[self.ID]) {
5427
- // Permission.set({
5428
- // tasks: [{id: idTask, permission: v[self.ID], elapsedItem: []}]
5429
- // })
5430
- // }
5431
- // }),
5432
- map(v => {
4296
+ }).res().pipe(map(v => {
5433
4297
  return (v && v[self.ID]) ? !!v[self.ID] : false; // отдельного флага на чтение нет, выходит что если права отдались то и права есть
5434
4298
  }));
5435
4299
  }
5436
4300
  return of(undefined);
5437
4301
  }));
5438
- // }
5439
- //
5440
- // return of(undefined)
5441
4302
  }
5442
4303
  /**
5443
4304
  * Законченный метод добавления записи с предварительной проверкой прав
@@ -5453,12 +4314,12 @@ class BXRestNavvyOperationElapsedItem {
5453
4314
  return this.BXRestNavvyElapsedItem.add(param).res();
5454
4315
  }
5455
4316
  else {
5456
- return throwError(() => new Error('Отсутствуют права добавление записи затраченного времени'));
4317
+ return throwError(() => new Error('No permission to add an elapsed time record to the task'));
5457
4318
  }
5458
4319
  }));
5459
4320
  }
5460
4321
  else {
5461
- return throwError(() => new Error('Отсутствуют права на чтение задачи'));
4322
+ return throwError(() => new Error('No permission to read the task'));
5462
4323
  }
5463
4324
  }));
5464
4325
  }
@@ -5475,48 +4336,21 @@ class BXRestNavvyOperationElapsedItem {
5475
4336
  if (allowed) {
5476
4337
  return this.BXRestNavvyElapsedItem.update(param).res();
5477
4338
  }
5478
- return throwError(() => new Error('Отсутствуют права на изменение записи затраченного времени'));
4339
+ return throwError(() => new Error('No permission to update the elapsed time record'));
5479
4340
  }));
5480
4341
  }
5481
- return throwError(() => new Error('Отсутствуют права на чтение задачи'));
4342
+ return throwError(() => new Error('No permission to read the task'));
5482
4343
  }));
5483
4344
  }
5484
- // TODO: разобраться что это за ебатня в комментах и вписать нормальной комент если она нужна
5485
4345
  /**
5486
4346
  * Проверяет право на изменение записи о затраченном времени.
5487
4347
  */
5488
4348
  isAllowedModify(idTask, idItem) {
5489
- // let permission = Permission.get()
5490
- // if (permission?.tasks?.length) {
5491
- // let findTask = permission.tasks.find(i => i.id === idTask)
5492
- // if (findTask) {
5493
- // let find = findTask.elapsedItem.find(i => i.id === idItem)
5494
- // if (find && find.verified.edit) {
5495
- // return of(find.edit)
5496
- // }
5497
- // }
5498
- // }
5499
4349
  return this.BXRestNavvyElapsedItem.isActionAllowed({
5500
4350
  TASKID: idTask,
5501
4351
  ITEMID: idItem,
5502
4352
  ACTIONID: 2
5503
4353
  }).res();
5504
- // .pipe(
5505
- // tap(v => {
5506
- // if (v !== undefined) {
5507
- // Permission.setTaskElapsedItem(idTask,
5508
- // {
5509
- // id: idItem,
5510
- // edit: v,
5511
- // del: false,
5512
- // verified: {
5513
- // edit: true,
5514
- // del: false,
5515
- // }
5516
- // })
5517
- // }
5518
- // })
5519
- // )
5520
4354
  }
5521
4355
  /**
5522
4356
  * isActionAllowed с фиксом на проверку возможности чтения задачи записи
@@ -5533,7 +4367,7 @@ class BXRestNavvyOperationElapsedItem {
5533
4367
  if (canRead) {
5534
4368
  return this.BXRestNavvyElapsedItem.isActionAllowed(param).res();
5535
4369
  }
5536
- return throwError(() => new Error('Отсутствуют права на чтение задачи'));
4370
+ return throwError(() => new Error('No permission to read the task'));
5537
4371
  }));
5538
4372
  }
5539
4373
  /**
@@ -5549,12 +4383,12 @@ class BXRestNavvyOperationElapsedItem {
5549
4383
  return this.BXRestNavvyElapsedItem.delete(param).res();
5550
4384
  }
5551
4385
  else {
5552
- return throwError(() => new Error('Отсутствуют права на удаление записи затраченного времени'));
4386
+ return throwError(() => new Error('No permission to delete the elapsed time record'));
5553
4387
  }
5554
4388
  }));
5555
4389
  }
5556
4390
  else {
5557
- return throwError(() => new Error('Отсутствуют права на чтение задачи'));
4391
+ return throwError(() => new Error('No permission to read the task'));
5558
4392
  }
5559
4393
  }));
5560
4394
  }
@@ -6567,7 +5401,7 @@ class BXRestNavvyDiskOperation {
6567
5401
  generateUniqueName: true
6568
5402
  }).res();
6569
5403
  }
6570
- return throwError(() => new Error('Отсутствует общее хранилище для приложения'));
5404
+ return throwError(() => new Error('Could not get the app storage'));
6571
5405
  }));
6572
5406
  }
6573
5407
  /**
@@ -6585,13 +5419,6 @@ class BXRestNavvyDiskOperation {
6585
5419
  * Возвращает список папок и файлов в общем хранилище приложения.
6586
5420
  */
6587
5421
  getRootFoldersApp() {
6588
- // return this.BXDiskFolder$.pipe(
6589
- // take(1),
6590
- // mergeMap(
6591
- // saveData => {
6592
- // if (saveData.content.root.app) {
6593
- // return of(saveData.content.root.app)
6594
- // }
6595
5422
  return this.storage.getForApp().res().pipe(mergeMap$1(v => {
6596
5423
  if (v && v.ID) {
6597
5424
  return this.storage.getChildren({ id: v.ID }).res();
@@ -6617,7 +5444,7 @@ class BXRestNavvyDiskOperation {
6617
5444
  if (v && v.ID) {
6618
5445
  return this.storage.addFolder({ id: v.ID, data: { NAME: folderName } }).res();
6619
5446
  }
6620
- return throwError(() => new Error('Отсутствуют права добавление записи затраченного времени'));
5447
+ return throwError(() => new Error('Could not get the app storage'));
6621
5448
  }));
6622
5449
  }));
6623
5450
  }
@@ -6988,6 +5815,32 @@ class BXRestNavvyBizProcRobot {
6988
5815
  }
6989
5816
  }
6990
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;
6991
5844
  /** Бизнес-процессы, задания, действия и роботы (`bizproc.*`). */
6992
5845
  class BXRestNavvyBizProc {
6993
5846
  constructor() {
@@ -7017,21 +5870,26 @@ class BXRestNavvyBizProc {
7017
5870
  // Не понимаю почему DATE_CREATE указывается не на сервере
7018
5871
  // но если пользователь не указал, надо указать
7019
5872
  const value = parametersElement['DATE_CREATE'];
7020
- if (value === null || value === undefined || (typeof value === 'string' || value.trim() === '')) {
5873
+ if (value === null || value === undefined || (typeof value === 'string' && value.trim() === '')) {
7021
5874
  parametersElement['DATE_CREATE'] = new Date();
7022
5875
  }
7023
- return this.BXRestNavvyLists.element.add({
5876
+ // ELEMENT_CODE обязателен и должен быть уникальным в списке. Занятые коды
5877
+ // знает только портал, поэтому на совпадение создаём новый код и повторяем.
5878
+ // throwOnApiError: иначе ошибка в ответе 2xx пришла бы как undefined.
5879
+ const addElement = (attempt) => this.BXRestNavvyLists.element.add({
7024
5880
  IBLOCK_TYPE_ID: 'bitrix_processes',
7025
5881
  IBLOCK_ID: id,
7026
- ELEMENT_CODE: 'trace_studio_' + Date.now() + '_' + Math.random(),
7027
- // тут должно быть уникально значение (генерация уникальных значений на фронте лол),
7028
- // как ещё уникальнее сделать я просто не знаю
7029
- // это поле обязательно без него не работает
5882
+ ELEMENT_CODE: uniqueElementCode(),
7030
5883
  FIELDS: {
7031
5884
  NAME: String(parametersElement['NAME']),
7032
5885
  ...parametersElement
7033
5886
  }
7034
- }).res().pipe(mergeMap(v => {
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 => {
7035
5893
  if (v) {
7036
5894
  if (Object.keys(parametersBizProc).length && templateIDs.length) {
7037
5895
  let request = [];
@@ -7048,7 +5906,7 @@ class BXRestNavvyBizProc {
7048
5906
  return of(true);
7049
5907
  }
7050
5908
  }
7051
- return throwError(() => new Error('Не удалось запустить бизнес процесс'));
5909
+ return throwError(() => new Error('Could not start the business process: the list element was not created'));
7052
5910
  }));
7053
5911
  }
7054
5912
  }
@@ -7318,14 +6176,6 @@ class BXRestNavvyRestCalendarEvent {
7318
6176
  update: [$calendar, $event, $update],
7319
6177
  };
7320
6178
  this.Navvy = new Navvy();
7321
- // /** Возвращает список событий календаря, всегда весь список, паганации в методе нет да и не нужна */
7322
- // get(param: iBXRestCalendarEventGetParam) {
7323
- // return this.Navvy.simple(
7324
- // this.url.get,
7325
- // param,
7326
- // BXRestMapCalendarEvent.get
7327
- // )
7328
- // }
7329
6179
  this.get = Object.assign(
7330
6180
  /**
7331
6181
  * Возвращает список событий календаря, всегда весь список, паганации в методе нет да и не нужна.
@@ -8414,40 +7264,6 @@ class BXRestNavvyImNotify {
8414
7264
  }
8415
7265
  }
8416
7266
 
8417
- function CatchError(options) {
8418
- return function (target, propertyKey, descriptor) {
8419
- const original = descriptor.value;
8420
- descriptor.value = function (...args) {
8421
- try {
8422
- return original.apply(this, args);
8423
- }
8424
- catch (err) {
8425
- const errorInfo = {
8426
- message: `❌ Error in ${target.constructor.name}.${propertyKey}`,
8427
- args,
8428
- error: err instanceof Error ? err.message : String(err),
8429
- stack: err instanceof Error ? err.stack : new Error().stack,
8430
- };
8431
- console.error(formatError(errorInfo));
8432
- if (options?.rethrow)
8433
- throw err;
8434
- return options?.defaultValue;
8435
- }
8436
- };
8437
- return descriptor;
8438
- };
8439
- }
8440
- // Общая функция форматирования
8441
- function formatError(info) {
8442
- const stackLines = info.stack?.split('\n').slice(2).join('\n');
8443
- return [
8444
- info.message,
8445
- info.args ? ` • args: ${JSON.stringify(info.args)}` : '',
8446
- info.error ? ` • error: ${info.error}` : '',
8447
- ` • stack trace:\n${stackLines}`,
8448
- ].join('\n');
8449
- }
8450
-
8451
7267
  class BXRestMapImRecent {
8452
7268
  static get(value) {
8453
7269
  return value
@@ -8518,12 +7334,6 @@ class BXRestMapImRecent {
8518
7334
  return chat;
8519
7335
  }
8520
7336
  }
8521
- __decorate([
8522
- CatchError({ rethrow: true })
8523
- ], BXRestMapImRecent, "get", null);
8524
- __decorate([
8525
- CatchError({ rethrow: true })
8526
- ], BXRestMapImRecent, "list", null);
8527
7337
 
8528
7338
  class BXRestNavvyImRecent {
8529
7339
  constructor() {
@@ -9263,12 +8073,8 @@ class BXRestNavvySocialNetWorkApiLiveFeedBlogPost {
9263
8073
  }
9264
8074
  }
9265
8075
 
9266
- // import { Navvy } from '../../../services/navvy'
9267
- // import { BXRestSocialNetWorkApiLiveFeed } from '../../../request/socialnetwork/api/livefeed'
9268
8076
  class BXRestNavvySocialNetWorkApiLiveFeed {
9269
8077
  constructor() {
9270
- // private readonly contentView = new BXRestSocialNetWorkApiLiveFeed)
9271
- // private readonly Navvy = new Navvy(this.contentView, null)
9272
8078
  /**
9273
8079
  * Сообщения Ленты новостей в социальной сети (`socialnetwork.api.liveFeed.blogPost.*`).
9274
8080
  */
@@ -9362,17 +8168,6 @@ class BXRestMapPull {
9362
8168
  }
9363
8169
  }
9364
8170
 
9365
- class BXRestMapPullChannelPublic {
9366
- static get(value) {
9367
- return value ? {
9368
- ...value,
9369
- start: toDate(value.start),
9370
- end: toDate(value.end)
9371
- }
9372
- : undefined;
9373
- }
9374
- }
9375
-
9376
8171
  class BXRestNavvyPullConfig {
9377
8172
  constructor() {
9378
8173
  this.url = {
@@ -9383,7 +8178,6 @@ class BXRestNavvyPullConfig {
9383
8178
  };
9384
8179
  this.Navvy = new Navvy();
9385
8180
  }
9386
- static { this.public = new BXRestMapPullChannelPublic(); }
9387
8181
  /**
9388
8182
  * @experimental
9389
8183
  * Этот метод находится в процессе тестирования и может измениться.
@@ -9393,6 +8187,17 @@ class BXRestNavvyPullConfig {
9393
8187
  }
9394
8188
  }
9395
8189
 
8190
+ class BXRestMapPullChannelPublic {
8191
+ static get(value) {
8192
+ return value ? {
8193
+ ...value,
8194
+ start: toDate(value.start),
8195
+ end: toDate(value.end)
8196
+ }
8197
+ : undefined;
8198
+ }
8199
+ }
8200
+
9396
8201
  class BXRestNavvyPullChannelPublic {
9397
8202
  constructor() {
9398
8203
  this.url = {
@@ -20203,69 +19008,70 @@ class BXRestNavvyUserFieldType {
20203
19008
  }
20204
19009
 
20205
19010
  class BXRestNavvy {
20206
- constructor() {
20207
- this.ai = new BXRestNavvyAi();
20208
- this.mailService = new BXRestNavvyMailService();
20209
- this.messageService = new BXRestNavvyMessageService();
20210
- this.userConsent = new BXRestNavvyUserConsent();
20211
- this.telephony = new BXRestNavvyTelephony();
20212
- this.vote = new BXRestNavvyVote();
20213
- this.imConnector = new BXRestNavvyImConnector();
20214
- this.entity = new BXRestNavvyEntity();
20215
- this.biConnector = new BXRestNavvyBiConnector();
20216
- this.voxImplant = new BXRestNavvyVoxImplant();
20217
- this.mail = new BXRestNavvyMail();
20218
- this.note = new BXRestNavvyNote();
20219
- this.documentGenerator = new BXRestNavvyDocumentGenerator();
20220
- this.imBot = new BXRestNavvyImBot();
20221
- this.booking = new BXRestNavvyBooking();
20222
- this.imOpenLines = new BXRestNavvyImOpenLines();
20223
- this.landing = new BXRestNavvyLanding();
20224
- this.catalog = new BXRestNavvyCatalog();
20225
- this.sale = new BXRestNavvySale();
20226
- this.sign = new BXRestNavvySign();
20227
- this.eventLog = new BXRestNavvyEventLog();
20228
- this.placement = new BXRestNavvyPlacement();
20229
- this.userFieldType = new BXRestNavvyUserFieldType();
20230
- this.user = new BXRestNavvyUser();
20231
- this.lists = new BXRestNavvyLists();
20232
- this.task = new BXRestNavvyTask();
20233
- this.tasks = new BXRestNavvyTasks();
20234
- this.disk = new BXRestNavvyDisk();
20235
- this.bizProc = new BXRestNavvyBizProc();
20236
- this.log = new BXRestNavvyLog();
20237
- this.calendar = new BXRestNavvyCalendar();
20238
- this.sonet_group = new BXRestNavvySonetGroup();
20239
- this.server = new BXRestNavvyServer();
20240
- this.department = new BXRestNavvyDepartment();
20241
- this.im = new BXRestNavvyIm();
20242
- this.app = new BXRestNavvyApp();
20243
- this.timeMan = new BXRestNavvyTimeMan();
20244
- this.socialNetWork = new BXRestNavvySocialNetWork();
20245
- this.pull = new BXRestNavvyPull();
20246
- this.crm = new BXRestNavvyCrm();
20247
- /** Регистрация обработчиков и работа с онлайн- и офлайн-событиями. */
20248
- this.event = new BXRestNavvyEvent();
20249
- /** Проверка существования и доступности REST-методов. */
20250
- this.method = new BXRestNavvyMethod();
20251
- /** Получение описаний кодов доступа. */
20252
- this.access = new BXRestNavvyAccess();
20253
- /** Проверка доступности возможностей портала. */
20254
- this.feature = new BXRestNavvyFeature();
20255
- this.Navvy = new Navvy();
20256
- // public batch<T, C, M>(param: iBXRestNavvyParamBatch<T, C, M>) {
20257
- // const modifiedObject = Object.fromEntries(
20258
- // Object.entries(param.cmd).map(([key, value]) => {
20259
- // let modifiedValue = value.resultVanilla.arguments
20260
- // return [key, modifiedValue]
20261
- // })
20262
- // )
20263
- //
20264
- // return this.BXRest.batch({
20265
- // halt: param.halt,
20266
- // cmd: modifiedObject
20267
- // })
20268
- // }
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
+ }
20269
19075
  }
20270
19076
  /**
20271
19077
  * Возвращает базовую информацию о текущем пользователе без scope `user`.
@@ -20291,6 +19097,15 @@ class BXRestNavvy {
20291
19097
  }
20292
19098
  }
20293
19099
 
19100
+ class BXRestMapDisk {
19101
+ constructor() {
19102
+ this.folder = new BXRestMapDiskFolder();
19103
+ this.attachedObject = new BXRestMapDiskAttachedObject();
19104
+ this.file = new BXRestMapDiskFile();
19105
+ this.storage = new BXRestMapDiskStorage();
19106
+ }
19107
+ }
19108
+
20294
19109
  class BXRestMapCalendarUser {
20295
19110
  constructor() {
20296
19111
  this.settings = new BXRestMapCalendarUserSettings();
@@ -20322,16 +19137,23 @@ class BXRestMapTaskStage {
20322
19137
  }
20323
19138
 
20324
19139
  class BXRestMapTask {
20325
- constructor() {
20326
- this.commentItem = new BXRestMapTaskCommentItem();
20327
- this.elapsedItem = new BXRestMapTaskElapsedItem();
20328
- this.stages = new BXRestMapTaskStage();
19140
+ // Геттеры, а не статические поля: статический инициализатор выполняется при загрузке
19141
+ // модуля, поэтому бандлер не сможет выбросить класс, даже если он нигде не используется.
19142
+ static get commentItem() {
19143
+ return BXRestMapTaskCommentItem;
19144
+ }
19145
+ static get elapsedItem() {
19146
+ return BXRestMapTaskElapsedItem;
19147
+ }
19148
+ static get stages() {
19149
+ return BXRestMapTaskStage;
20329
19150
  }
20330
19151
  }
20331
19152
 
20332
19153
  class BXRestMapTasks {
20333
- constructor() {
20334
- this.task = new BXRestMapTasksTask();
19154
+ // Геттер — по той же причине, что и в BXRestMapTask
19155
+ static get task() {
19156
+ return BXRestMapTasksTask;
20335
19157
  }
20336
19158
  }
20337
19159
 
@@ -20349,7 +19171,7 @@ class BXRestMap {
20349
19171
  return BXRestMapLists;
20350
19172
  }
20351
19173
  get disk() {
20352
- return BXRestDisk;
19174
+ return BXRestMapDisk;
20353
19175
  }
20354
19176
  get calendar() {
20355
19177
  return BXRestMapCalendar;
@@ -20943,5 +19765,5 @@ function toRecord(value) {
20943
19765
  * Generated bundle index. Do not edit.
20944
19766
  */
20945
19767
 
20946
- export { base as BXBaseServices, BXRestApiError, BXRestFrame, BXRestFrameError, BXRestMap, BXRestMapResult, BXRestNavvy, HttpBXServices as BXRestRequest, BXRestSettings, HttpNavvyServices, Navvy, SessionKeyError, SessionKeyServices, getAuthRefreshError, instanceOfiBXRestAnswerSuccess as isBXRestAnswerSuccess, isBXRestAuthError, partNameMethods$1 as partNameMethods };
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 };
20947
19769
  //# sourceMappingURL=bx-rest.mjs.map