@bitrix24/b24jssdk 0.5.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-AI.md +2 -1
- package/dist/esm/_virtual/_commonjsHelpers.mjs +16 -0
- package/dist/esm/_virtual/_commonjsHelpers.mjs.map +1 -0
- package/dist/esm/_virtual/protobuf.mjs +16 -0
- package/dist/esm/_virtual/protobuf.mjs.map +1 -0
- package/dist/esm/_virtual/protobuf2.mjs +12 -0
- package/dist/esm/_virtual/protobuf2.mjs.map +1 -0
- package/dist/esm/core/abstract-b24.mjs +355 -0
- package/dist/esm/core/abstract-b24.mjs.map +1 -0
- package/dist/esm/core/actions/abstract-action.mjs +24 -0
- package/dist/esm/core/actions/abstract-action.mjs.map +1 -0
- package/dist/esm/core/actions/abstract-batch.mjs +95 -0
- package/dist/esm/core/actions/abstract-batch.mjs.map +1 -0
- package/dist/esm/core/actions/manager.mjs +53 -0
- package/dist/esm/core/actions/manager.mjs.map +1 -0
- package/dist/esm/core/actions/v2/batch-by-chunk.mjs +92 -0
- package/dist/esm/core/actions/v2/batch-by-chunk.mjs.map +1 -0
- package/dist/esm/core/actions/v2/batch.mjs +126 -0
- package/dist/esm/core/actions/v2/batch.mjs.map +1 -0
- package/dist/esm/core/actions/v2/call-list.mjs +131 -0
- package/dist/esm/core/actions/v2/call-list.mjs.map +1 -0
- package/dist/esm/core/actions/v2/call.mjs +68 -0
- package/dist/esm/core/actions/v2/call.mjs.map +1 -0
- package/dist/esm/core/actions/v2/fetch-list.mjs +132 -0
- package/dist/esm/core/actions/v2/fetch-list.mjs.map +1 -0
- package/dist/esm/core/actions/v2/manager-v2.mjs +74 -0
- package/dist/esm/core/actions/v2/manager-v2.mjs.map +1 -0
- package/dist/esm/core/actions/v3/batch-by-chunk.mjs +91 -0
- package/dist/esm/core/actions/v3/batch-by-chunk.mjs.map +1 -0
- package/dist/esm/core/actions/v3/batch.mjs +129 -0
- package/dist/esm/core/actions/v3/batch.mjs.map +1 -0
- package/dist/esm/core/actions/v3/call-list.mjs +127 -0
- package/dist/esm/core/actions/v3/call-list.mjs.map +1 -0
- package/dist/esm/core/actions/v3/call.mjs +58 -0
- package/dist/esm/core/actions/v3/call.mjs.map +1 -0
- package/dist/esm/core/actions/v3/fetch-list.mjs +125 -0
- package/dist/esm/core/actions/v3/fetch-list.mjs.map +1 -0
- package/dist/esm/core/actions/v3/manager-v3.mjs +74 -0
- package/dist/esm/core/actions/v3/manager-v3.mjs.map +1 -0
- package/dist/esm/core/http/abstract-http.mjs +563 -0
- package/dist/esm/core/http/abstract-http.mjs.map +1 -0
- package/dist/esm/core/http/ajax-error.mjs +107 -0
- package/dist/esm/core/http/ajax-error.mjs.map +1 -0
- package/dist/esm/core/http/ajax-result.mjs +176 -0
- package/dist/esm/core/http/ajax-result.mjs.map +1 -0
- package/dist/esm/core/http/limiters/adaptive-delayer.mjs +135 -0
- package/dist/esm/core/http/limiters/adaptive-delayer.mjs.map +1 -0
- package/dist/esm/core/http/limiters/manager.mjs +309 -0
- package/dist/esm/core/http/limiters/manager.mjs.map +1 -0
- package/dist/esm/core/http/limiters/operating-limiter.mjs +171 -0
- package/dist/esm/core/http/limiters/operating-limiter.mjs.map +1 -0
- package/dist/esm/core/http/limiters/params-factory.mjs +121 -0
- package/dist/esm/core/http/limiters/params-factory.mjs.map +1 -0
- package/dist/esm/core/http/limiters/rate-limiter.mjs +402 -0
- package/dist/esm/core/http/limiters/rate-limiter.mjs.map +1 -0
- package/dist/esm/core/http/v2.mjs +100 -0
- package/dist/esm/core/http/v2.mjs.map +1 -0
- package/dist/esm/core/http/v3.mjs +94 -0
- package/dist/esm/core/http/v3.mjs.map +1 -0
- package/dist/esm/core/interaction/batch/abstract-interaction-batch.mjs +69 -0
- package/dist/esm/core/interaction/batch/abstract-interaction-batch.mjs.map +1 -0
- package/dist/esm/core/interaction/batch/parse-row.mjs +67 -0
- package/dist/esm/core/interaction/batch/parse-row.mjs.map +1 -0
- package/dist/esm/core/interaction/batch/processing/interface-strategy.mjs +42 -0
- package/dist/esm/core/interaction/batch/processing/interface-strategy.mjs.map +1 -0
- package/dist/esm/core/interaction/batch/processing/v2/abstract-processing.mjs +121 -0
- package/dist/esm/core/interaction/batch/processing/v2/abstract-processing.mjs.map +1 -0
- package/dist/esm/core/interaction/batch/processing/v2/as-array.mjs +32 -0
- package/dist/esm/core/interaction/batch/processing/v2/as-array.mjs.map +1 -0
- package/dist/esm/core/interaction/batch/processing/v2/as-object.mjs +32 -0
- package/dist/esm/core/interaction/batch/processing/v2/as-object.mjs.map +1 -0
- package/dist/esm/core/interaction/batch/processing/v3/abstract-processing.mjs +118 -0
- package/dist/esm/core/interaction/batch/processing/v3/abstract-processing.mjs.map +1 -0
- package/dist/esm/core/interaction/batch/processing/v3/as-array.mjs +32 -0
- package/dist/esm/core/interaction/batch/processing/v3/as-array.mjs.map +1 -0
- package/dist/esm/core/interaction/batch/processing/v3/as-object.mjs +32 -0
- package/dist/esm/core/interaction/batch/processing/v3/as-object.mjs.map +1 -0
- package/dist/esm/core/interaction/batch/v2.mjs +44 -0
- package/dist/esm/core/interaction/batch/v2.mjs.map +1 -0
- package/dist/esm/core/interaction/batch/v3.mjs +42 -0
- package/dist/esm/core/interaction/batch/v3.mjs.map +1 -0
- package/dist/esm/core/language/list.mjs +56 -0
- package/dist/esm/core/language/list.mjs.map +1 -0
- package/dist/esm/core/request-id-generator.mjs +42 -0
- package/dist/esm/core/request-id-generator.mjs.map +1 -0
- package/dist/esm/core/result.mjs +101 -0
- package/dist/esm/core/result.mjs.map +1 -0
- package/dist/esm/core/sdk-error.mjs +83 -0
- package/dist/esm/core/sdk-error.mjs.map +1 -0
- package/dist/esm/core/tools/abstract-tool.mjs +24 -0
- package/dist/esm/core/tools/abstract-tool.mjs.map +1 -0
- package/dist/esm/core/tools/healthcheck.mjs +48 -0
- package/dist/esm/core/tools/healthcheck.mjs.map +1 -0
- package/dist/esm/core/tools/manager.mjs +50 -0
- package/dist/esm/core/tools/manager.mjs.map +1 -0
- package/dist/esm/core/tools/ping.mjs +56 -0
- package/dist/esm/core/tools/ping.mjs.map +1 -0
- package/dist/esm/core/version-manager.mjs +116 -0
- package/dist/esm/core/version-manager.mjs.map +1 -0
- package/dist/esm/frame/auth.mjs +98 -0
- package/dist/esm/frame/auth.mjs.map +1 -0
- package/dist/esm/frame/b24.mjs +170 -0
- package/dist/esm/frame/b24.mjs.map +1 -0
- package/dist/esm/frame/dialog.mjs +78 -0
- package/dist/esm/frame/dialog.mjs.map +1 -0
- package/dist/esm/frame/frame.mjs +101 -0
- package/dist/esm/frame/frame.mjs.map +1 -0
- package/dist/esm/frame/message/commands.mjs +37 -0
- package/dist/esm/frame/message/commands.mjs.map +1 -0
- package/dist/esm/frame/message/controller.mjs +178 -0
- package/dist/esm/frame/message/controller.mjs.map +1 -0
- package/dist/esm/frame/options.mjs +106 -0
- package/dist/esm/frame/options.mjs.map +1 -0
- package/dist/esm/frame/parent.mjs +253 -0
- package/dist/esm/frame/parent.mjs.map +1 -0
- package/dist/esm/frame/placement.mjs +131 -0
- package/dist/esm/frame/placement.mjs.map +1 -0
- package/dist/esm/frame/slider.mjs +156 -0
- package/dist/esm/frame/slider.mjs.map +1 -0
- package/dist/esm/helper/abstract-helper.mjs +52 -0
- package/dist/esm/helper/abstract-helper.mjs.map +1 -0
- package/dist/esm/helper/app-manager.mjs +37 -0
- package/dist/esm/helper/app-manager.mjs.map +1 -0
- package/dist/esm/helper/currency-manager.mjs +207 -0
- package/dist/esm/helper/currency-manager.mjs.map +1 -0
- package/dist/esm/helper/helper-manager.mjs +388 -0
- package/dist/esm/helper/helper-manager.mjs.map +1 -0
- package/dist/esm/helper/license-manager.mjs +50 -0
- package/dist/esm/helper/license-manager.mjs.map +1 -0
- package/dist/esm/helper/options-manager.mjs +196 -0
- package/dist/esm/helper/options-manager.mjs.map +1 -0
- package/dist/esm/helper/payment-manager.mjs +33 -0
- package/dist/esm/helper/payment-manager.mjs.map +1 -0
- package/dist/esm/helper/profile-manager.mjs +33 -0
- package/dist/esm/helper/profile-manager.mjs.map +1 -0
- package/dist/esm/helper/use-b24-helper.mjs +84 -0
- package/dist/esm/helper/use-b24-helper.mjs.map +1 -0
- package/dist/esm/hook/auth.mjs +77 -0
- package/dist/esm/hook/auth.mjs.map +1 -0
- package/dist/esm/hook/b24.mjs +115 -0
- package/dist/esm/hook/b24.mjs.map +1 -0
- package/dist/esm/index.d.mts +2768 -534
- package/dist/esm/index.d.ts +2768 -534
- package/dist/esm/index.mjs +70 -14118
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/loader-b24frame.mjs +101 -0
- package/dist/esm/loader-b24frame.mjs.map +1 -0
- package/dist/esm/logger/abstract-logger.mjs +69 -0
- package/dist/esm/logger/abstract-logger.mjs.map +1 -0
- package/dist/esm/logger/browser.mjs +162 -0
- package/dist/esm/logger/browser.mjs.map +1 -0
- package/dist/esm/logger/formatter/abstract-formatter.mjs +34 -0
- package/dist/esm/logger/formatter/abstract-formatter.mjs.map +1 -0
- package/dist/esm/logger/formatter/json-formatter.mjs +34 -0
- package/dist/esm/logger/formatter/json-formatter.mjs.map +1 -0
- package/dist/esm/logger/formatter/line-formatter.mjs +41 -0
- package/dist/esm/logger/formatter/line-formatter.mjs.map +1 -0
- package/dist/esm/logger/formatter/telegram-formatter.mjs +103 -0
- package/dist/esm/logger/formatter/telegram-formatter.mjs.map +1 -0
- package/dist/esm/logger/handler/abstract-handler.mjs +39 -0
- package/dist/esm/logger/handler/abstract-handler.mjs.map +1 -0
- package/dist/esm/logger/handler/consola-adapter.mjs +62 -0
- package/dist/esm/logger/handler/consola-adapter.mjs.map +1 -0
- package/dist/esm/logger/handler/console-handler.mjs +98 -0
- package/dist/esm/logger/handler/console-handler.mjs.map +1 -0
- package/dist/esm/logger/handler/console-v2-handler.mjs +51 -0
- package/dist/esm/logger/handler/console-v2-handler.mjs.map +1 -0
- package/dist/esm/logger/handler/memory-handler.mjs +48 -0
- package/dist/esm/logger/handler/memory-handler.mjs.map +1 -0
- package/dist/esm/logger/handler/stream-handler.mjs +73 -0
- package/dist/esm/logger/handler/stream-handler.mjs.map +1 -0
- package/dist/esm/logger/handler/telegram-handler.mjs +157 -0
- package/dist/esm/logger/handler/telegram-handler.mjs.map +1 -0
- package/dist/esm/logger/handler/winston-adapter.mjs +57 -0
- package/dist/esm/logger/handler/winston-adapter.mjs.map +1 -0
- package/dist/esm/logger/logger-factory.mjs +67 -0
- package/dist/esm/logger/logger-factory.mjs.map +1 -0
- package/dist/esm/logger/logger.mjs +76 -0
- package/dist/esm/logger/logger.mjs.map +1 -0
- package/dist/esm/logger/null-logger.mjs +32 -0
- package/dist/esm/logger/null-logger.mjs.map +1 -0
- package/dist/esm/logger/processor/memory-usage-processor.mjs +20 -0
- package/dist/esm/logger/processor/memory-usage-processor.mjs.map +1 -0
- package/dist/esm/logger/processor/pid-processor.mjs +20 -0
- package/dist/esm/logger/processor/pid-processor.mjs.map +1 -0
- package/dist/esm/oauth/auth.mjs +211 -0
- package/dist/esm/oauth/auth.mjs.map +1 -0
- package/dist/esm/oauth/b24.mjs +117 -0
- package/dist/esm/oauth/b24.mjs.map +1 -0
- package/dist/esm/oauth/refresh-token-error.mjs +20 -0
- package/dist/esm/oauth/refresh-token-error.mjs.map +1 -0
- package/dist/esm/pullClient/abstract-connector.mjs +78 -0
- package/dist/esm/pullClient/abstract-connector.mjs.map +1 -0
- package/dist/esm/pullClient/channel-manager.mjs +89 -0
- package/dist/esm/pullClient/channel-manager.mjs.map +1 -0
- package/dist/esm/pullClient/client.mjs +2064 -0
- package/dist/esm/pullClient/client.mjs.map +1 -0
- package/dist/esm/pullClient/errors.mjs +31 -0
- package/dist/esm/pullClient/errors.mjs.map +1 -0
- package/dist/esm/pullClient/json-rpc.mjs +210 -0
- package/dist/esm/pullClient/json-rpc.mjs.map +1 -0
- package/dist/esm/pullClient/long-polling-connector.mjs +157 -0
- package/dist/esm/pullClient/long-polling-connector.mjs.map +1 -0
- package/dist/esm/pullClient/protobuf/index.mjs +17 -0
- package/dist/esm/pullClient/protobuf/index.mjs.map +1 -0
- package/dist/esm/pullClient/protobuf/model.mjs +1058 -0
- package/dist/esm/pullClient/protobuf/model.mjs.map +1 -0
- package/dist/esm/pullClient/protobuf/protobuf.mjs +4653 -0
- package/dist/esm/pullClient/protobuf/protobuf.mjs.map +1 -0
- package/dist/esm/pullClient/shared-config.mjs +133 -0
- package/dist/esm/pullClient/shared-config.mjs.map +1 -0
- package/dist/esm/pullClient/storage-manager.mjs +72 -0
- package/dist/esm/pullClient/storage-manager.mjs.map +1 -0
- package/dist/esm/pullClient/web-socket-connector.mjs +129 -0
- package/dist/esm/pullClient/web-socket-connector.mjs.map +1 -0
- package/dist/esm/tools/browser.mjs +154 -0
- package/dist/esm/tools/browser.mjs.map +1 -0
- package/dist/esm/tools/environment.mjs +29 -0
- package/dist/esm/tools/environment.mjs.map +1 -0
- package/dist/esm/tools/formatters/iban.mjs +304 -0
- package/dist/esm/tools/formatters/iban.mjs.map +1 -0
- package/dist/esm/tools/formatters/numbers.mjs +64 -0
- package/dist/esm/tools/formatters/numbers.mjs.map +1 -0
- package/dist/esm/tools/index.mjs +37 -0
- package/dist/esm/tools/index.mjs.map +1 -0
- package/dist/esm/tools/scroll-size.mjs +25 -0
- package/dist/esm/tools/scroll-size.mjs.map +1 -0
- package/dist/esm/tools/text.mjs +208 -0
- package/dist/esm/tools/text.mjs.map +1 -0
- package/dist/esm/tools/type.mjs +337 -0
- package/dist/esm/tools/type.mjs.map +1 -0
- package/dist/esm/tools/use-formatters.mjs +460 -0
- package/dist/esm/tools/use-formatters.mjs.map +1 -0
- package/dist/esm/tools/uuidv7.mjs +54 -0
- package/dist/esm/tools/uuidv7.mjs.map +1 -0
- package/dist/esm/types/b24-helper.mjs +56 -0
- package/dist/esm/types/b24-helper.mjs.map +1 -0
- package/dist/esm/types/b24.mjs +16 -0
- package/dist/esm/types/b24.mjs.map +1 -0
- package/dist/esm/types/bizproc/index.mjs +187 -0
- package/dist/esm/types/bizproc/index.mjs.map +1 -0
- package/dist/esm/types/catalog/index.mjs +35 -0
- package/dist/esm/types/catalog/index.mjs.map +1 -0
- package/dist/esm/types/common.mjs +31 -0
- package/dist/esm/types/common.mjs.map +1 -0
- package/dist/esm/types/crm/entity-type.mjs +57 -0
- package/dist/esm/types/crm/entity-type.mjs.map +1 -0
- package/dist/esm/types/crm/productrow.mjs +17 -0
- package/dist/esm/types/crm/productrow.mjs.map +1 -0
- package/dist/esm/types/logger.mjs +22 -0
- package/dist/esm/types/logger.mjs.map +1 -0
- package/dist/esm/types/pull.mjs +83 -0
- package/dist/esm/types/pull.mjs.map +1 -0
- package/dist/umd/index.js +31312 -26912
- package/dist/umd/index.js.map +1 -1
- package/dist/umd/index.min.js +63 -40
- package/dist/umd/index.min.js.map +1 -1
- package/package.json +34 -29
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @package @bitrix24/b24jssdk
|
|
3
|
+
* @version 1.0.2
|
|
4
|
+
* @copyright (c) 2026 Bitrix24
|
|
5
|
+
* @license MIT
|
|
6
|
+
* @see https://github.com/bitrix24/b24jssdk
|
|
7
|
+
* @see https://bitrix24.github.io/b24jssdk/
|
|
8
|
+
*/
|
|
9
|
+
import { RateLimiter } from './rate-limiter.mjs';
|
|
10
|
+
import { OperatingLimiter } from './operating-limiter.mjs';
|
|
11
|
+
import { AdaptiveDelayer } from './adaptive-delayer.mjs';
|
|
12
|
+
import { LoggerFactory } from '../../../logger/logger-factory.mjs';
|
|
13
|
+
|
|
14
|
+
var __defProp = Object.defineProperty;
|
|
15
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
16
|
+
class RestrictionManager {
|
|
17
|
+
static {
|
|
18
|
+
__name(this, "RestrictionManager");
|
|
19
|
+
}
|
|
20
|
+
#rateLimiter;
|
|
21
|
+
#operatingLimiter;
|
|
22
|
+
#adaptiveDelayer;
|
|
23
|
+
#config;
|
|
24
|
+
#stats = {
|
|
25
|
+
/** Retry attempts */
|
|
26
|
+
retries: 0,
|
|
27
|
+
/** Consecutive errors */
|
|
28
|
+
consecutiveErrors: 0,
|
|
29
|
+
/** Limit triggers */
|
|
30
|
+
limitHits: 0
|
|
31
|
+
};
|
|
32
|
+
#errorCounts = /* @__PURE__ */ new Map();
|
|
33
|
+
_logger;
|
|
34
|
+
constructor(params) {
|
|
35
|
+
this._logger = LoggerFactory.createNullLogger();
|
|
36
|
+
this.#config = params;
|
|
37
|
+
this.#rateLimiter = new RateLimiter(params.rateLimit);
|
|
38
|
+
this.#operatingLimiter = new OperatingLimiter(params.operatingLimit);
|
|
39
|
+
this.#adaptiveDelayer = new AdaptiveDelayer(params.adaptiveConfig, this.#operatingLimiter);
|
|
40
|
+
}
|
|
41
|
+
// region Logger ////
|
|
42
|
+
setLogger(logger) {
|
|
43
|
+
this._logger = logger;
|
|
44
|
+
this.#rateLimiter.setLogger(this._logger);
|
|
45
|
+
this.#operatingLimiter.setLogger(this._logger);
|
|
46
|
+
this.#adaptiveDelayer.setLogger(this._logger);
|
|
47
|
+
}
|
|
48
|
+
getLogger() {
|
|
49
|
+
return this._logger;
|
|
50
|
+
}
|
|
51
|
+
// endregion ////
|
|
52
|
+
async applyOperatingLimits(requestId, method, params) {
|
|
53
|
+
const operatingWait = await this.#operatingLimiter.waitIfNeeded(requestId, method, params);
|
|
54
|
+
if (operatingWait > 0) {
|
|
55
|
+
this.incrementStats("limitHits");
|
|
56
|
+
this.#logMethodBlocked(this.#operatingLimiter.getTitle(), requestId, method, operatingWait);
|
|
57
|
+
await this.#delay(operatingWait);
|
|
58
|
+
} else {
|
|
59
|
+
const adaptiveDelay = await this.#adaptiveDelayer.waitIfNeeded(requestId, method, params);
|
|
60
|
+
if (adaptiveDelay > 0) {
|
|
61
|
+
this.incrementStats("limitHits");
|
|
62
|
+
this.#logMethodBlocked(this.#adaptiveDelayer.getTitle(), requestId, method, adaptiveDelay);
|
|
63
|
+
await this.#delay(adaptiveDelay);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Checks and waits for the rate limit
|
|
69
|
+
* The loop is needed for parallel requests (Promise.all())
|
|
70
|
+
*/
|
|
71
|
+
async checkRateLimit(requestId, method) {
|
|
72
|
+
let waitTime;
|
|
73
|
+
let times = 1;
|
|
74
|
+
do {
|
|
75
|
+
waitTime = await this.#rateLimiter.waitIfNeeded(requestId, method);
|
|
76
|
+
if (waitTime > 0) {
|
|
77
|
+
this.incrementStats("limitHits");
|
|
78
|
+
this.#logMethodBlockedWithTimes(this.#rateLimiter.getTitle(), requestId, method, waitTime, times);
|
|
79
|
+
await this.#delay(waitTime);
|
|
80
|
+
times++;
|
|
81
|
+
}
|
|
82
|
+
} while (waitTime > 0);
|
|
83
|
+
}
|
|
84
|
+
async updateStats(requestId, method, timeData) {
|
|
85
|
+
await this.#operatingLimiter.updateStats(requestId, method, timeData);
|
|
86
|
+
await this.#adaptiveDelayer.updateStats(requestId, method, timeData);
|
|
87
|
+
await this.#rateLimiter.updateStats(requestId, method, timeData);
|
|
88
|
+
}
|
|
89
|
+
async handleError(requestId, method, params, error, attempt) {
|
|
90
|
+
if (this.#isRateLimitError(error)) {
|
|
91
|
+
const wait = await this.#handleRateLimitExceeded(requestId) * Math.pow(1.5, attempt);
|
|
92
|
+
this.#logError(this.#rateLimiter.getTitle(), requestId, "QUERY_LIMIT_EXCEEDED", error.message, method, wait);
|
|
93
|
+
return wait;
|
|
94
|
+
}
|
|
95
|
+
if (this.#isOperatingLimitError(error)) {
|
|
96
|
+
const wait = Math.max(1e4, await this.#handleOperatingLimitError(requestId, method, params, error));
|
|
97
|
+
this.#logError(this.#operatingLimiter.getTitle(), requestId, "OPERATION_TIME_LIMIT", error.message, method, wait);
|
|
98
|
+
return wait;
|
|
99
|
+
}
|
|
100
|
+
if (!this.#isNeedThrowError(error)) {
|
|
101
|
+
const baseDelay = await this.#getErrorBackoff(requestId);
|
|
102
|
+
const maxDelay = Math.max(3e4, baseDelay);
|
|
103
|
+
const delay = Math.min(maxDelay, baseDelay * Math.pow(2, attempt));
|
|
104
|
+
const jitter = delay * 0.1 * (Math.random() * 2 - 1);
|
|
105
|
+
const wait = Math.max(100, delay + jitter);
|
|
106
|
+
this.#logSomeError(requestId, error?.code ? `${error.code}` : "?", error.message, method, wait);
|
|
107
|
+
return wait;
|
|
108
|
+
}
|
|
109
|
+
return 0;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Checks if the error is a rate limit
|
|
113
|
+
*/
|
|
114
|
+
#isRateLimitError(error) {
|
|
115
|
+
return error.status === 503 || error.code === "QUERY_LIMIT_EXCEEDED";
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Delay when exceeding the rate limit
|
|
119
|
+
*/
|
|
120
|
+
async #handleRateLimitExceeded(requestId) {
|
|
121
|
+
return this.#rateLimiter.handleExceeded(requestId);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Checks if the error is an operating limit
|
|
125
|
+
*
|
|
126
|
+
* @memo `OPERATION_TIME_LIMIT` && `429` - obtained through practical means
|
|
127
|
+
* @memo This doesn't work for `batch` queries.
|
|
128
|
+
*/
|
|
129
|
+
#isOperatingLimitError(error) {
|
|
130
|
+
return error.status === 429 || error.code === "OPERATION_TIME_LIMIT";
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Operating limit error delay
|
|
134
|
+
*
|
|
135
|
+
* @memo Currently, the errors don't include timings for operations.
|
|
136
|
+
* For this reason, we will take data from the previous request
|
|
137
|
+
*/
|
|
138
|
+
async #handleOperatingLimitError(requestId, method, params, _error) {
|
|
139
|
+
return this.#operatingLimiter.getTimeToFree(requestId, method, params, _error);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Checks whether attempts should be stopped if errors are encountered that are unclear.
|
|
143
|
+
*/
|
|
144
|
+
#isNeedThrowError(error) {
|
|
145
|
+
const answerError = {
|
|
146
|
+
code: error?.code ?? "-1",
|
|
147
|
+
description: error?.message ?? ""
|
|
148
|
+
};
|
|
149
|
+
return [
|
|
150
|
+
...this.exceptionCodeForHard,
|
|
151
|
+
...this.exceptionCodeForSoft
|
|
152
|
+
].includes(answerError.code) || (answerError.description ?? "").includes("Could not find value for parameter");
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* These exceptions will be thrown
|
|
156
|
+
*/
|
|
157
|
+
get exceptionCodeForHard() {
|
|
158
|
+
return [
|
|
159
|
+
"ERR_BAD_REQUEST",
|
|
160
|
+
"JSSDK_UNKNOWN_ERROR",
|
|
161
|
+
// 'REQUEST_TIMEOUT', 'NETWORK_ERROR',
|
|
162
|
+
"100",
|
|
163
|
+
"INTERNAL_SERVER_ERROR",
|
|
164
|
+
"ERROR_UNEXPECTED_ANSWER",
|
|
165
|
+
"PORTAL_DELETED",
|
|
166
|
+
"ERROR_BATCH_METHOD_NOT_ALLOWED",
|
|
167
|
+
"ERROR_BATCH_LENGTH_EXCEEDED",
|
|
168
|
+
"NO_AUTH_FOUND",
|
|
169
|
+
"INVALID_REQUEST",
|
|
170
|
+
"OVERLOAD_LIMIT",
|
|
171
|
+
"expired_token",
|
|
172
|
+
"ACCESS_DENIED",
|
|
173
|
+
"INVALID_CREDENTIALS",
|
|
174
|
+
"user_access_error",
|
|
175
|
+
"insufficient_scope",
|
|
176
|
+
"ERROR_MANIFEST_IS_NOT_AVAILABLE",
|
|
177
|
+
"allowed_only_intranet_user",
|
|
178
|
+
"NOT_FOUND",
|
|
179
|
+
"INVALID_ARG_VALUE"
|
|
180
|
+
];
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* These exceptions will be thrown into `AjaxResult` as `AjaxError`
|
|
184
|
+
*/
|
|
185
|
+
get exceptionCodeForSoft() {
|
|
186
|
+
return [
|
|
187
|
+
"ERROR_ENTITY_NOT_FOUND",
|
|
188
|
+
"BITRIX_REST_V3_EXCEPTION_ACCESSDENIEDEXCEPTION",
|
|
189
|
+
"BITRIX_REST_V3_EXCEPTION_INVALIDJSONEXCEPTION",
|
|
190
|
+
"BITRIX_REST_V3_EXCEPTION_INVALIDFILTEREXCEPTION",
|
|
191
|
+
"BITRIX_REST_V3_EXCEPTION_INVALIDSELECTEXCEPTION",
|
|
192
|
+
"BITRIX_REST_V3_EXCEPTION_ENTITYNOTFOUNDEXCEPTION",
|
|
193
|
+
"BITRIX_REST_V3_EXCEPTION_METHODNOTFOUNDEXCEPTION",
|
|
194
|
+
"BITRIX_REST_V3_EXCEPTION_UNKNOWNDTOPROPERTYEXCEPTION",
|
|
195
|
+
"BITRIX_REST_V3_EXCEPTION_VALIDATION_REQUESTVALIDATIONEXCEPTION",
|
|
196
|
+
"BITRIX_REST_V3_EXCEPTION_VALIDATION_DTOVALIDATIONEXCEPTION"
|
|
197
|
+
];
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Delay due to unknown errors
|
|
201
|
+
*/
|
|
202
|
+
async #getErrorBackoff(_requestId) {
|
|
203
|
+
return this.#config.retryDelay;
|
|
204
|
+
}
|
|
205
|
+
incrementError(method) {
|
|
206
|
+
const current = this.#errorCounts.get(method) || 0;
|
|
207
|
+
this.#errorCounts.set(method, current + 1);
|
|
208
|
+
this.incrementStats("consecutiveErrors");
|
|
209
|
+
}
|
|
210
|
+
resetErrors(method) {
|
|
211
|
+
this.#errorCounts.delete(method);
|
|
212
|
+
this.#stats.consecutiveErrors = 0;
|
|
213
|
+
}
|
|
214
|
+
incrementStats(stat) {
|
|
215
|
+
this.#stats[stat]++;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Returns job statistics
|
|
219
|
+
*/
|
|
220
|
+
getStats() {
|
|
221
|
+
return {
|
|
222
|
+
...this.#stats,
|
|
223
|
+
...this.#rateLimiter.getStats(),
|
|
224
|
+
...this.#adaptiveDelayer.getStats(),
|
|
225
|
+
...this.#operatingLimiter.getStats(),
|
|
226
|
+
errorCounts: Object.fromEntries(this.#errorCounts)
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Resets limiters and statistics
|
|
231
|
+
*/
|
|
232
|
+
async reset() {
|
|
233
|
+
await this.#rateLimiter.reset();
|
|
234
|
+
await this.#operatingLimiter.reset();
|
|
235
|
+
await this.#adaptiveDelayer.reset();
|
|
236
|
+
this.#errorCounts.clear();
|
|
237
|
+
this.#stats = {
|
|
238
|
+
retries: 0,
|
|
239
|
+
consecutiveErrors: 0,
|
|
240
|
+
limitHits: 0
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
async setConfig(params) {
|
|
244
|
+
this.#config = params;
|
|
245
|
+
await this.#rateLimiter.setConfig(params.rateLimit);
|
|
246
|
+
await this.#operatingLimiter.setConfig(params.operatingLimit);
|
|
247
|
+
await this.#adaptiveDelayer.setConfig(params.adaptiveConfig);
|
|
248
|
+
}
|
|
249
|
+
getParams() {
|
|
250
|
+
return { ...this.#config };
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Delay function
|
|
254
|
+
*/
|
|
255
|
+
async #delay(ms) {
|
|
256
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Public access to the delay function
|
|
260
|
+
*/
|
|
261
|
+
async waiteDelay(ms) {
|
|
262
|
+
return this.#delay(ms);
|
|
263
|
+
}
|
|
264
|
+
// region Log ////
|
|
265
|
+
#logMethodBlocked(limiter, requestId, method, wait) {
|
|
266
|
+
this.getLogger().notice(`${limiter} blocked method ${method}`, {
|
|
267
|
+
requestId,
|
|
268
|
+
method,
|
|
269
|
+
wait,
|
|
270
|
+
limiter
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
#logMethodBlockedWithTimes(limiter, requestId, method, wait, times) {
|
|
274
|
+
this.getLogger().notice(`${limiter} blocked method ${method} | ${times} times`, {
|
|
275
|
+
requestId,
|
|
276
|
+
method,
|
|
277
|
+
times,
|
|
278
|
+
wait,
|
|
279
|
+
limiter
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
#logError(limiter, requestId, code, message, method, wait) {
|
|
283
|
+
this.getLogger().error(`${limiter} recognized the ${code} error for the ${method} method`, {
|
|
284
|
+
requestId,
|
|
285
|
+
method,
|
|
286
|
+
wait,
|
|
287
|
+
limiter,
|
|
288
|
+
error: {
|
|
289
|
+
code,
|
|
290
|
+
message
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
#logSomeError(requestId, code, message, method, wait) {
|
|
295
|
+
this.getLogger().error(`recognized the ${code} error for the ${method} method`, {
|
|
296
|
+
requestId,
|
|
297
|
+
method,
|
|
298
|
+
wait,
|
|
299
|
+
error: {
|
|
300
|
+
code,
|
|
301
|
+
message
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
// endregion ////
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export { RestrictionManager };
|
|
309
|
+
//# sourceMappingURL=manager.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.mjs","sources":["../../../../../src/core/http/limiters/manager.ts"],"sourcesContent":["import type { RestrictionParams, RestrictionManagerStats } from '../../../types/limiters'\nimport type { LoggerInterface } from '../../../types/logger'\nimport { LoggerFactory } from '../../../logger'\nimport { RateLimiter } from './rate-limiter'\nimport { OperatingLimiter } from './operating-limiter'\nimport { AdaptiveDelayer } from './adaptive-delayer'\n\n/**\n * Delay Management Manager\n *\n * @todo docs\n */\nexport class RestrictionManager {\n #rateLimiter: RateLimiter\n #operatingLimiter: OperatingLimiter\n #adaptiveDelayer: AdaptiveDelayer\n #config: RestrictionParams\n #stats: Pick<RestrictionManagerStats, 'retries' | 'consecutiveErrors' | 'limitHits'> = {\n /** Retry attempts */\n retries: 0,\n /** Consecutive errors */\n consecutiveErrors: 0,\n /** Limit triggers */\n limitHits: 0\n }\n\n #errorCounts = new Map<string, number>()\n\n private _logger: LoggerInterface\n\n constructor(params: RestrictionParams) {\n this._logger = LoggerFactory.createNullLogger()\n this.#config = params\n this.#rateLimiter = new RateLimiter(params.rateLimit!)\n this.#operatingLimiter = new OperatingLimiter(params.operatingLimit!)\n this.#adaptiveDelayer = new AdaptiveDelayer(params.adaptiveConfig!, this.#operatingLimiter)\n }\n\n // region Logger ////\n setLogger(logger: LoggerInterface): void {\n this._logger = logger\n this.#rateLimiter.setLogger(this._logger)\n this.#operatingLimiter.setLogger(this._logger)\n this.#adaptiveDelayer.setLogger(this._logger)\n }\n\n getLogger(): LoggerInterface {\n return this._logger\n }\n // endregion ////\n\n async applyOperatingLimits(requestId: string, method: string, params?: any): Promise<void> {\n // 1. Check operating limit\n const operatingWait = await this.#operatingLimiter.waitIfNeeded(requestId, method, params)\n if (operatingWait > 0) {\n this.incrementStats('limitHits')\n this.#logMethodBlocked(this.#operatingLimiter.getTitle(), requestId, method, operatingWait)\n await this.#delay(operatingWait)\n } else {\n // 2. Apply adaptive delay\n const adaptiveDelay = await this.#adaptiveDelayer.waitIfNeeded(requestId, method, params)\n if (adaptiveDelay > 0) {\n this.incrementStats('limitHits')\n this.#logMethodBlocked(this.#adaptiveDelayer.getTitle(), requestId, method, adaptiveDelay)\n await this.#delay(adaptiveDelay)\n }\n }\n }\n\n /**\n * Checks and waits for the rate limit\n * The loop is needed for parallel requests (Promise.all())\n */\n async checkRateLimit(requestId: string, method: string): Promise<void> {\n // 3. Apply rate limit\n let waitTime\n let times = 1\n do {\n waitTime = await this.#rateLimiter.waitIfNeeded(requestId, method)\n if (waitTime > 0) {\n this.incrementStats('limitHits')\n this.#logMethodBlockedWithTimes(this.#rateLimiter.getTitle(), requestId, method, waitTime, times)\n await this.#delay(waitTime)\n times++\n }\n } while (waitTime > 0)\n }\n\n async updateStats(\n requestId: string,\n method: string,\n timeData: any\n ): Promise<void> {\n await this.#operatingLimiter.updateStats(requestId, method, timeData)\n await this.#adaptiveDelayer.updateStats(requestId, method, timeData)\n await this.#rateLimiter.updateStats(requestId, method, timeData)\n }\n\n async handleError(\n requestId: string,\n method: string,\n params: any,\n error: any,\n attempt: number\n ): Promise<number> {\n // Rate limit exceeded\n if (this.#isRateLimitError(error)) {\n // Since this is error handling, we take into account the number of attempts\n const wait = (await this.#handleRateLimitExceeded(requestId)) * Math.pow(1.5, attempt)\n this.#logError(this.#rateLimiter.getTitle(), requestId, 'QUERY_LIMIT_EXCEEDED', error.message, method, wait)\n return wait\n }\n\n // Operating limit exceeded\n if (this.#isOperatingLimitError(error)) {\n // Since this is error handling, we will increase the minimum to 10 seconds.\n const wait = Math.max(10_000, await this.#handleOperatingLimitError(requestId, method, params, error))\n this.#logError(this.#operatingLimiter.getTitle(), requestId, 'OPERATION_TIME_LIMIT', error.message, method, wait)\n return wait\n }\n\n // Other exceptions\n if (!this.#isNeedThrowError(error)) {\n // Since this is error handling, we take into account the number of attempts\n const baseDelay = await this.#getErrorBackoff(requestId)\n const maxDelay = Math.max(30_000, baseDelay)\n const delay = Math.min(maxDelay, baseDelay * Math.pow(2, attempt))\n\n // Add jitter to prevent thundering herd\n const jitter = delay * 0.1 * (Math.random() * 2 - 1) // ±10% jitter\n const wait = Math.max(100, delay + jitter)\n\n this.#logSomeError(requestId, error?.code ? `${error.code}` : '?', error.message, method, wait)\n\n return wait\n }\n\n return 0 // We don't repeat\n }\n\n /**\n * Checks if the error is a rate limit\n */\n #isRateLimitError(error: any): boolean {\n return error.status === 503\n || error.code === 'QUERY_LIMIT_EXCEEDED'\n }\n\n /**\n * Delay when exceeding the rate limit\n */\n async #handleRateLimitExceeded(requestId: string): Promise<number> {\n return this.#rateLimiter.handleExceeded(requestId)\n }\n\n /**\n * Checks if the error is an operating limit\n *\n * @memo `OPERATION_TIME_LIMIT` && `429` - obtained through practical means\n * @memo This doesn't work for `batch` queries.\n */\n #isOperatingLimitError(error: any): boolean {\n return error.status === 429\n || error.code === 'OPERATION_TIME_LIMIT'\n }\n\n /**\n * Operating limit error delay\n *\n * @memo Currently, the errors don't include timings for operations.\n * For this reason, we will take data from the previous request\n */\n async #handleOperatingLimitError(requestId: string, method: string, params?: any, _error?: any): Promise<number> {\n return this.#operatingLimiter.getTimeToFree(requestId, method, params, _error)\n }\n\n /**\n * Checks whether attempts should be stopped if errors are encountered that are unclear.\n */\n #isNeedThrowError(error: any): boolean {\n const answerError = {\n code: error?.code ?? '-1',\n description: error?.message ?? ''\n }\n\n return [\n ...this.exceptionCodeForHard,\n ...this.exceptionCodeForSoft\n ].includes(answerError.code)\n || (answerError.description ?? '').includes('Could not find value for parameter')\n }\n\n /**\n * These exceptions will be thrown\n */\n get exceptionCodeForHard(): string[] {\n return [\n 'ERR_BAD_REQUEST',\n 'JSSDK_UNKNOWN_ERROR', // 'REQUEST_TIMEOUT', 'NETWORK_ERROR',\n '100',\n 'INTERNAL_SERVER_ERROR', 'ERROR_UNEXPECTED_ANSWER', 'PORTAL_DELETED',\n 'ERROR_BATCH_METHOD_NOT_ALLOWED', 'ERROR_BATCH_LENGTH_EXCEEDED',\n 'NO_AUTH_FOUND',\n 'INVALID_REQUEST',\n 'OVERLOAD_LIMIT', 'expired_token',\n 'ACCESS_DENIED', 'INVALID_CREDENTIALS', 'user_access_error', 'insufficient_scope',\n 'ERROR_MANIFEST_IS_NOT_AVAILABLE',\n 'allowed_only_intranet_user',\n 'NOT_FOUND',\n 'INVALID_ARG_VALUE'\n ]\n }\n\n /**\n * These exceptions will be thrown into `AjaxResult` as `AjaxError`\n */\n get exceptionCodeForSoft(): string[] {\n return [\n 'ERROR_ENTITY_NOT_FOUND',\n 'BITRIX_REST_V3_EXCEPTION_ACCESSDENIEDEXCEPTION',\n 'BITRIX_REST_V3_EXCEPTION_INVALIDJSONEXCEPTION',\n 'BITRIX_REST_V3_EXCEPTION_INVALIDFILTEREXCEPTION',\n 'BITRIX_REST_V3_EXCEPTION_INVALIDSELECTEXCEPTION',\n 'BITRIX_REST_V3_EXCEPTION_ENTITYNOTFOUNDEXCEPTION',\n 'BITRIX_REST_V3_EXCEPTION_METHODNOTFOUNDEXCEPTION',\n 'BITRIX_REST_V3_EXCEPTION_UNKNOWNDTOPROPERTYEXCEPTION',\n 'BITRIX_REST_V3_EXCEPTION_VALIDATION_REQUESTVALIDATIONEXCEPTION',\n 'BITRIX_REST_V3_EXCEPTION_VALIDATION_DTOVALIDATIONEXCEPTION'\n ]\n }\n\n /**\n * Delay due to unknown errors\n */\n async #getErrorBackoff(_requestId: string): Promise<number> {\n return this.#config.retryDelay!\n }\n\n incrementError(method: string): void {\n const current = this.#errorCounts.get(method) || 0\n this.#errorCounts.set(method, current + 1)\n this.incrementStats('consecutiveErrors')\n }\n\n resetErrors(method: string): void {\n this.#errorCounts.delete(method)\n this.#stats.consecutiveErrors = 0\n }\n\n incrementStats(stat: keyof Pick<RestrictionManagerStats, 'retries' | 'consecutiveErrors' | 'limitHits'>): void {\n this.#stats[stat]++\n }\n\n /**\n * Returns job statistics\n */\n getStats(): RestrictionManagerStats & {\n adaptiveDelayAvg: number\n errorCounts: Record<string, number>\n } {\n return {\n ...this.#stats,\n ...this.#rateLimiter.getStats(),\n ...this.#adaptiveDelayer.getStats(),\n ...this.#operatingLimiter.getStats(),\n errorCounts: Object.fromEntries(this.#errorCounts)\n }\n }\n\n /**\n * Resets limiters and statistics\n */\n async reset(): Promise<void> {\n await this.#rateLimiter.reset()\n await this.#operatingLimiter.reset()\n await this.#adaptiveDelayer.reset()\n this.#errorCounts.clear()\n\n this.#stats = {\n retries: 0,\n consecutiveErrors: 0,\n limitHits: 0\n }\n }\n\n async setConfig(params: RestrictionParams): Promise<void> {\n this.#config = params\n await this.#rateLimiter.setConfig(params.rateLimit!)\n await this.#operatingLimiter.setConfig(params.operatingLimit!)\n await this.#adaptiveDelayer.setConfig(params.adaptiveConfig!)\n }\n\n getParams(): RestrictionParams {\n return { ...this.#config }\n }\n\n /**\n * Delay function\n */\n async #delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n }\n\n /**\n * Public access to the delay function\n */\n async waiteDelay(ms: number): Promise<void> {\n return this.#delay(ms)\n }\n\n // region Log ////\n #logMethodBlocked(limiter: string, requestId: string, method: string, wait: number) {\n this.getLogger().notice(`${limiter} blocked method ${method}`, {\n requestId,\n method,\n wait,\n limiter\n })\n }\n\n #logMethodBlockedWithTimes(limiter: string, requestId: string, method: string, wait: number, times: number) {\n this.getLogger().notice(`${limiter} blocked method ${method} | ${times} times`, {\n requestId,\n method,\n times,\n wait,\n limiter\n })\n }\n\n #logError(limiter: string, requestId: string, code: string, message: string, method: string, wait: number) {\n this.getLogger().error(`${limiter} recognized the ${code} error for the ${method} method`, {\n requestId,\n method,\n wait,\n limiter,\n error: {\n code,\n message\n }\n })\n }\n\n #logSomeError(requestId: string, code: string, message: string, method: string, wait: number) {\n this.getLogger().error(`recognized the ${code} error for the ${method} method`, {\n requestId,\n method,\n wait,\n error: {\n code,\n message\n }\n })\n }\n // endregion ////\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @package @bitrix24/b24jssdk
|
|
3
|
+
* @version 1.0.2
|
|
4
|
+
* @copyright (c) 2026 Bitrix24
|
|
5
|
+
* @license MIT
|
|
6
|
+
* @see https://github.com/bitrix24/b24jssdk
|
|
7
|
+
* @see https://bitrix24.github.io/b24jssdk/
|
|
8
|
+
*/
|
|
9
|
+
import { LoggerFactory } from '../../../logger/logger-factory.mjs';
|
|
10
|
+
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
13
|
+
class OperatingLimiter {
|
|
14
|
+
static {
|
|
15
|
+
__name(this, "OperatingLimiter");
|
|
16
|
+
}
|
|
17
|
+
#config;
|
|
18
|
+
#methodStats = /* @__PURE__ */ new Map();
|
|
19
|
+
#stats = {
|
|
20
|
+
/** Heavy requests */
|
|
21
|
+
heavyRequestCount: 0
|
|
22
|
+
};
|
|
23
|
+
_logger;
|
|
24
|
+
getTitle() {
|
|
25
|
+
return "operatingLimiter";
|
|
26
|
+
}
|
|
27
|
+
constructor(config) {
|
|
28
|
+
this._logger = LoggerFactory.createNullLogger();
|
|
29
|
+
this.#config = config;
|
|
30
|
+
}
|
|
31
|
+
// region Logger ////
|
|
32
|
+
setLogger(logger) {
|
|
33
|
+
this._logger = logger;
|
|
34
|
+
}
|
|
35
|
+
getLogger() {
|
|
36
|
+
return this._logger;
|
|
37
|
+
}
|
|
38
|
+
// endregion ////
|
|
39
|
+
get limitMs() {
|
|
40
|
+
return this.#config.limitMs;
|
|
41
|
+
}
|
|
42
|
+
getMethodStat(method) {
|
|
43
|
+
const stats = this.#methodStats.get(method);
|
|
44
|
+
if (!stats) {
|
|
45
|
+
return void 0;
|
|
46
|
+
}
|
|
47
|
+
return stats;
|
|
48
|
+
}
|
|
49
|
+
async canProceed(requestId, method, params) {
|
|
50
|
+
const timeToFree = await this.getTimeToFree(requestId, method, params);
|
|
51
|
+
return timeToFree === 0;
|
|
52
|
+
}
|
|
53
|
+
async waitIfNeeded(requestId, method, params) {
|
|
54
|
+
return this.getTimeToFree(requestId, method, params);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Returns the time until the method's operating limit is released (in ms)
|
|
58
|
+
* The analysis is based on the previous function call.
|
|
59
|
+
* It's important to understand that we're talking about locks of up to 10 minutes.
|
|
60
|
+
* This is a fairly strict lock based on the limit:
|
|
61
|
+
* - not reached - no lock
|
|
62
|
+
* - reached - lock until the unlock time + 1 second
|
|
63
|
+
*/
|
|
64
|
+
async getTimeToFree(requestId, method, params, _error) {
|
|
65
|
+
this.#cleanupOldStats();
|
|
66
|
+
if (method === "batch") {
|
|
67
|
+
return this.#getTimeToFreeBatch(requestId, params);
|
|
68
|
+
}
|
|
69
|
+
const stats = this.#methodStats.get(method);
|
|
70
|
+
if (!stats) {
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
const limitWithBuffer = Math.max(1e3, this.#config.limitMs - 5e3);
|
|
74
|
+
if (stats.operating >= limitWithBuffer) {
|
|
75
|
+
const now = Date.now();
|
|
76
|
+
if (stats.operating_reset_at > now) {
|
|
77
|
+
return stats.operating_reset_at - now + 1e3;
|
|
78
|
+
}
|
|
79
|
+
return 5e3;
|
|
80
|
+
}
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* For `batch` commands, returns the maximum time until the method reaches the operating limit (in ms)
|
|
85
|
+
*/
|
|
86
|
+
async #getTimeToFreeBatch(requestId, params) {
|
|
87
|
+
let maxWait = 0;
|
|
88
|
+
if (!params?.cmd || !Array.isArray(params.cmd)) {
|
|
89
|
+
return maxWait;
|
|
90
|
+
}
|
|
91
|
+
const batchMethods = params.cmd.map((row) => row.split("?")[0]).filter(Boolean);
|
|
92
|
+
for (const methodName of batchMethods) {
|
|
93
|
+
const waitTime = await this.getTimeToFree(requestId, `batch::${methodName}`, {});
|
|
94
|
+
maxWait = Math.max(maxWait, waitTime);
|
|
95
|
+
}
|
|
96
|
+
return maxWait;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Updates operating time statistics for the method
|
|
100
|
+
*/
|
|
101
|
+
async updateStats(requestId, method, data) {
|
|
102
|
+
this.#cleanupOldStats();
|
|
103
|
+
const { operating, operating_reset_at } = data;
|
|
104
|
+
if (operating === void 0 || operating === null) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (!this.#methodStats.has(method)) {
|
|
108
|
+
this.#methodStats.set(method, {
|
|
109
|
+
operating: 0,
|
|
110
|
+
operating_reset_at: 0,
|
|
111
|
+
lastUpdated: Date.now()
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
const stats = this.#methodStats.get(method);
|
|
115
|
+
stats.operating = operating * 1e3;
|
|
116
|
+
stats.operating_reset_at = operating_reset_at * 1e3;
|
|
117
|
+
stats.lastUpdated = Date.now();
|
|
118
|
+
const usagePercent = stats.operating / this.#config.limitMs * 100;
|
|
119
|
+
if (usagePercent > this.#config.heavyPercent) {
|
|
120
|
+
this.#stats.heavyRequestCount++;
|
|
121
|
+
this.#logStat(requestId, method, usagePercent, stats.operating);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Clearing outdated operating limit data
|
|
126
|
+
*/
|
|
127
|
+
#cleanupOldStats() {
|
|
128
|
+
const now = Date.now();
|
|
129
|
+
const maxAge = this.#config.windowMs + 1e4;
|
|
130
|
+
for (const [method, stats] of this.#methodStats.entries()) {
|
|
131
|
+
if (now - stats.lastUpdated > maxAge) {
|
|
132
|
+
this.#methodStats.delete(method);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async reset() {
|
|
137
|
+
this.#methodStats.clear();
|
|
138
|
+
this.#stats = {
|
|
139
|
+
heavyRequestCount: 0
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
getStats() {
|
|
143
|
+
const operatingStats = {};
|
|
144
|
+
for (const [method, stats] of this.#methodStats.entries()) {
|
|
145
|
+
operatingStats[method] = Number.parseFloat((stats.operating / 1e3).toFixed(2));
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
...this.#stats,
|
|
149
|
+
operatingStats
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
async setConfig(config) {
|
|
153
|
+
this.#config = config;
|
|
154
|
+
}
|
|
155
|
+
// region Log ////
|
|
156
|
+
#logStat(requestId, method, percent, operating) {
|
|
157
|
+
this.getLogger().debug(`${this.getTitle()} detected limit for method ${method}`, {
|
|
158
|
+
requestId,
|
|
159
|
+
method,
|
|
160
|
+
operating: {
|
|
161
|
+
percent: Number.parseFloat(percent.toFixed(2)),
|
|
162
|
+
current: Number.parseFloat((operating / 1e3).toFixed(0)),
|
|
163
|
+
max: Number.parseFloat((this.#config.limitMs / 1e3).toFixed(0))
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// endregion ////
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export { OperatingLimiter };
|
|
171
|
+
//# sourceMappingURL=operating-limiter.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operating-limiter.mjs","sources":["../../../../../src/core/http/limiters/operating-limiter.ts"],"sourcesContent":["import type { OperatingLimitConfig, ILimiter } from '../../../types/limiters'\nimport type { PayloadTime } from '../../../types/payloads'\nimport type { LoggerInterface } from '../../../types/logger'\nimport { LoggerFactory } from '../../../logger'\n\ninterface OperatingStats {\n /*\n * operating time in 10 minutes (in ms)\n */\n operating: number\n /**\n * reset time (timestamp in ms)\n */\n operating_reset_at: number\n lastUpdated: number\n}\n\n/**\n * Operating limiting\n *\n * @todo docs\n */\nexport class OperatingLimiter implements ILimiter {\n #config: OperatingLimitConfig\n #methodStats = new Map<string, OperatingStats>()\n #stats = {\n /** Heavy requests */\n heavyRequestCount: 0\n }\n\n private _logger: LoggerInterface\n\n getTitle(): string {\n return 'operatingLimiter'\n }\n\n constructor(config: OperatingLimitConfig) {\n this._logger = LoggerFactory.createNullLogger()\n this.#config = config\n }\n\n // region Logger ////\n setLogger(logger: LoggerInterface): void {\n this._logger = logger\n }\n\n getLogger(): LoggerInterface {\n return this._logger\n }\n // endregion ////\n\n get limitMs(): number {\n return this.#config.limitMs\n }\n\n getMethodStat(method: string): undefined | OperatingStats {\n const stats = this.#methodStats.get(method)\n if (!stats) {\n return undefined\n }\n\n return stats\n }\n\n async canProceed(requestId: string, method: string, params?: any): Promise<boolean> {\n const timeToFree = await this.getTimeToFree(requestId, method, params)\n return timeToFree === 0\n }\n\n async waitIfNeeded(requestId: string, method: string, params?: any): Promise<number> {\n return this.getTimeToFree(requestId, method, params)\n }\n\n /**\n * Returns the time until the method's operating limit is released (in ms)\n * The analysis is based on the previous function call.\n * It's important to understand that we're talking about locks of up to 10 minutes.\n * This is a fairly strict lock based on the limit:\n * - not reached - no lock\n * - reached - lock until the unlock time + 1 second\n */\n async getTimeToFree(\n requestId: string,\n method: string,\n params?: any,\n _error?: any\n ): Promise<number> {\n this.#cleanupOldStats()\n\n if (method === 'batch') {\n return this.#getTimeToFreeBatch(requestId, params)\n }\n\n const stats = this.#methodStats.get(method)\n if (!stats) {\n return 0\n }\n\n // Use limit with buffer. When calculating the operating limit, we will take 5 seconds less\n const limitWithBuffer = Math.max(1_000, this.#config.limitMs - 5_000)\n if (stats.operating >= limitWithBuffer) {\n const now = Date.now()\n if (stats.operating_reset_at > now) {\n // Return the time before reset_at + 1 second\n return (stats.operating_reset_at - now) + 1_000\n }\n return 5_000 // 5 seconds by default\n }\n\n return 0\n }\n\n /**\n * For `batch` commands, returns the maximum time until the method reaches the operating limit (in ms)\n */\n async #getTimeToFreeBatch(requestId: string, params: any): Promise<number> {\n let maxWait = 0\n\n if (!params?.cmd || !Array.isArray(params.cmd)) {\n return maxWait\n }\n\n const batchMethods = params.cmd\n .map((row: string) => row.split('?')[0])\n .filter(Boolean)\n\n for (const methodName of batchMethods) {\n const waitTime = await this.getTimeToFree(requestId, `batch::${methodName}`, {})\n maxWait = Math.max(maxWait, waitTime)\n }\n\n return maxWait\n }\n\n /**\n * Updates operating time statistics for the method\n */\n async updateStats(requestId: string, method: string, data: PayloadTime): Promise<void> {\n this.#cleanupOldStats()\n\n // all in seconds\n const { operating, operating_reset_at } = data\n if (operating === undefined || operating === null) {\n return\n }\n\n if (!this.#methodStats.has(method)) {\n this.#methodStats.set(method, {\n operating: 0,\n operating_reset_at: 0,\n lastUpdated: Date.now()\n })\n }\n\n const stats = this.#methodStats.get(method)!\n\n stats.operating = operating * 1000\n stats.operating_reset_at = operating_reset_at * 1000\n stats.lastUpdated = Date.now()\n\n // Check for heavy requests\n const usagePercent = (stats.operating / this.#config.limitMs) * 100\n if (usagePercent > this.#config.heavyPercent) {\n this.#stats.heavyRequestCount++\n\n // log if close to the limit\n this.#logStat(requestId, method, usagePercent, stats.operating)\n }\n }\n\n /**\n * Clearing outdated operating limit data\n */\n #cleanupOldStats(): void {\n const now = Date.now()\n const maxAge = this.#config.windowMs + 10_000 // 10 seconds extra\n\n for (const [method, stats] of this.#methodStats.entries()) {\n if (now - stats.lastUpdated > maxAge) {\n this.#methodStats.delete(method)\n }\n }\n }\n\n async reset(): Promise<void> {\n this.#methodStats.clear()\n this.#stats = {\n heavyRequestCount: 0\n }\n }\n\n getStats(): {\n heavyRequestCount: number\n operatingStats: { [method: string]: number }\n } {\n const operatingStats: Record<string, number> = {}\n\n for (const [method, stats] of this.#methodStats.entries()) {\n operatingStats[method] = Number.parseFloat((stats.operating / 1000).toFixed(2))\n }\n\n return {\n ...this.#stats,\n operatingStats\n }\n }\n\n async setConfig(config: OperatingLimitConfig): Promise<void> {\n this.#config = config\n }\n\n // region Log ////\n #logStat(requestId: string, method: string, percent: number, operating: number) {\n this.getLogger().debug(`${this.getTitle()} detected limit for method ${method}`, {\n requestId,\n method,\n operating: {\n percent: Number.parseFloat(percent.toFixed(2)),\n current: Number.parseFloat((operating / 1000).toFixed(0)),\n max: Number.parseFloat((this.#config.limitMs / 1000).toFixed(0))\n }\n })\n }\n // endregion ////\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @package @bitrix24/b24jssdk
|
|
3
|
+
* @version 1.0.2
|
|
4
|
+
* @copyright (c) 2026 Bitrix24
|
|
5
|
+
* @license MIT
|
|
6
|
+
* @see https://github.com/bitrix24/b24jssdk
|
|
7
|
+
* @see https://bitrix24.github.io/b24jssdk/
|
|
8
|
+
*/
|
|
9
|
+
var __defProp = Object.defineProperty;
|
|
10
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
11
|
+
class ParamsFactory {
|
|
12
|
+
static {
|
|
13
|
+
__name(this, "ParamsFactory");
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Default parameters for regular tariffs
|
|
17
|
+
*
|
|
18
|
+
* @see Http.#restrictionParams
|
|
19
|
+
*/
|
|
20
|
+
static getDefault() {
|
|
21
|
+
return {
|
|
22
|
+
rateLimit: {
|
|
23
|
+
burstLimit: 50,
|
|
24
|
+
drainRate: 2,
|
|
25
|
+
adaptiveEnabled: true
|
|
26
|
+
},
|
|
27
|
+
operatingLimit: {
|
|
28
|
+
windowMs: 6e5,
|
|
29
|
+
// 10 min
|
|
30
|
+
limitMs: 48e4,
|
|
31
|
+
// 480 sec
|
|
32
|
+
heavyPercent: 80
|
|
33
|
+
},
|
|
34
|
+
adaptiveConfig: {
|
|
35
|
+
enabled: true,
|
|
36
|
+
thresholdPercent: 80,
|
|
37
|
+
coefficient: 0.01,
|
|
38
|
+
maxDelay: 7e3
|
|
39
|
+
},
|
|
40
|
+
maxRetries: 3,
|
|
41
|
+
retryDelay: 1e3
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Parameters for the Enterprise plan
|
|
46
|
+
*/
|
|
47
|
+
static getEnterprise() {
|
|
48
|
+
return {
|
|
49
|
+
...this.getDefault(),
|
|
50
|
+
rateLimit: {
|
|
51
|
+
burstLimit: 250,
|
|
52
|
+
drainRate: 5,
|
|
53
|
+
adaptiveEnabled: true
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Parameters for bulk data processing
|
|
59
|
+
*/
|
|
60
|
+
static getBatchProcessing() {
|
|
61
|
+
return {
|
|
62
|
+
...this.getDefault(),
|
|
63
|
+
rateLimit: {
|
|
64
|
+
burstLimit: 30,
|
|
65
|
+
drainRate: 1,
|
|
66
|
+
adaptiveEnabled: true
|
|
67
|
+
},
|
|
68
|
+
operatingLimit: {
|
|
69
|
+
windowMs: 6e5,
|
|
70
|
+
limitMs: 48e4,
|
|
71
|
+
heavyPercent: 50
|
|
72
|
+
// Higher threshold for notifications
|
|
73
|
+
},
|
|
74
|
+
adaptiveConfig: {
|
|
75
|
+
enabled: true,
|
|
76
|
+
thresholdPercent: 50,
|
|
77
|
+
// More threshold
|
|
78
|
+
coefficient: 0.015,
|
|
79
|
+
// More pause
|
|
80
|
+
maxDelay: 1e4
|
|
81
|
+
// Max 10 seconds
|
|
82
|
+
},
|
|
83
|
+
maxRetries: 5
|
|
84
|
+
// More attempts
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Real-time parameters
|
|
89
|
+
*/
|
|
90
|
+
static getRealtime() {
|
|
91
|
+
return {
|
|
92
|
+
...this.getDefault(),
|
|
93
|
+
adaptiveConfig: {
|
|
94
|
+
enabled: false,
|
|
95
|
+
// Off
|
|
96
|
+
thresholdPercent: 100,
|
|
97
|
+
coefficient: 1e-3,
|
|
98
|
+
maxDelay: 48e4
|
|
99
|
+
},
|
|
100
|
+
maxRetries: 1
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Tariff plan based parameters
|
|
105
|
+
*/
|
|
106
|
+
static fromTariffPlan(plan) {
|
|
107
|
+
switch (plan.toLowerCase()) {
|
|
108
|
+
case "enterprise":
|
|
109
|
+
return this.getEnterprise();
|
|
110
|
+
case "company":
|
|
111
|
+
case "start":
|
|
112
|
+
case "standard":
|
|
113
|
+
case "basic":
|
|
114
|
+
default:
|
|
115
|
+
return this.getDefault();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export { ParamsFactory };
|
|
121
|
+
//# sourceMappingURL=params-factory.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"params-factory.mjs","sources":["../../../../../src/core/http/limiters/params-factory.ts"],"sourcesContent":["import type { RestrictionParams } from '../../../types/limiters'\n\n/**\n * Factory for creating constraint parameters\n */\n// eslint-disable-next-line @typescript-eslint/no-extraneous-class\nexport class ParamsFactory {\n /**\n * Default parameters for regular tariffs\n *\n * @see Http.#restrictionParams\n */\n static getDefault(): RestrictionParams {\n return {\n rateLimit: {\n burstLimit: 50,\n drainRate: 2,\n adaptiveEnabled: true\n },\n operatingLimit: {\n windowMs: 600_000, // 10 min\n limitMs: 480_000, // 480 sec\n heavyPercent: 80\n },\n adaptiveConfig: {\n enabled: true,\n thresholdPercent: 80,\n coefficient: 0.01,\n maxDelay: 7_000\n },\n maxRetries: 3,\n retryDelay: 1_000\n }\n }\n\n /**\n * Parameters for the Enterprise plan\n */\n static getEnterprise(): RestrictionParams {\n return {\n ...this.getDefault(),\n rateLimit: {\n burstLimit: 250,\n drainRate: 5,\n adaptiveEnabled: true\n }\n }\n }\n\n /**\n * Parameters for bulk data processing\n */\n static getBatchProcessing(): RestrictionParams {\n return {\n ...this.getDefault(),\n rateLimit: {\n burstLimit: 30,\n drainRate: 1,\n adaptiveEnabled: true\n },\n operatingLimit: {\n windowMs: 600_000,\n limitMs: 480_000,\n heavyPercent: 50 // Higher threshold for notifications\n },\n adaptiveConfig: {\n enabled: true,\n thresholdPercent: 50, // More threshold\n coefficient: 0.015, // More pause\n maxDelay: 10_000 // Max 10 seconds\n },\n maxRetries: 5 // More attempts\n }\n }\n\n /**\n * Real-time parameters\n */\n static getRealtime(): RestrictionParams {\n return {\n ...this.getDefault(),\n adaptiveConfig: {\n enabled: false, // Off\n thresholdPercent: 100,\n coefficient: 0.001,\n maxDelay: 480_000\n },\n maxRetries: 1\n }\n }\n\n /**\n * Tariff plan based parameters\n */\n static fromTariffPlan(plan: string): RestrictionParams {\n switch (plan.toLowerCase()) {\n case 'enterprise':\n return this.getEnterprise()\n case 'company':\n case 'start':\n case 'standard':\n case 'basic':\n default:\n return this.getDefault()\n }\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;AAMO,MAAM,aAAA,CAAc;AAAA,EAN3B;AAM2B,IAAA,MAAA,CAAA,IAAA,EAAA,eAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMzB,OAAO,UAAA,GAAgC;AACrC,IAAA,OAAO;AAAA,MACL,SAAA,EAAW;AAAA,QACT,UAAA,EAAY,EAAA;AAAA,QACZ,SAAA,EAAW,CAAA;AAAA,QACX,eAAA,EAAiB;AAAA,OACnB;AAAA,MACA,cAAA,EAAgB;AAAA,QACd,QAAA,EAAU,GAAA;AAAA;AAAA,QACV,OAAA,EAAS,IAAA;AAAA;AAAA,QACT,YAAA,EAAc;AAAA,OAChB;AAAA,MACA,cAAA,EAAgB;AAAA,QACd,OAAA,EAAS,IAAA;AAAA,QACT,gBAAA,EAAkB,EAAA;AAAA,QAClB,WAAA,EAAa,IAAA;AAAA,QACb,QAAA,EAAU;AAAA,OACZ;AAAA,MACA,UAAA,EAAY,CAAA;AAAA,MACZ,UAAA,EAAY;AAAA,KACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,aAAA,GAAmC;AACxC,IAAA,OAAO;AAAA,MACL,GAAG,KAAK,UAAA,EAAW;AAAA,MACnB,SAAA,EAAW;AAAA,QACT,UAAA,EAAY,GAAA;AAAA,QACZ,SAAA,EAAW,CAAA;AAAA,QACX,eAAA,EAAiB;AAAA;AACnB,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,kBAAA,GAAwC;AAC7C,IAAA,OAAO;AAAA,MACL,GAAG,KAAK,UAAA,EAAW;AAAA,MACnB,SAAA,EAAW;AAAA,QACT,UAAA,EAAY,EAAA;AAAA,QACZ,SAAA,EAAW,CAAA;AAAA,QACX,eAAA,EAAiB;AAAA,OACnB;AAAA,MACA,cAAA,EAAgB;AAAA,QACd,QAAA,EAAU,GAAA;AAAA,QACV,OAAA,EAAS,IAAA;AAAA,QACT,YAAA,EAAc;AAAA;AAAA,OAChB;AAAA,MACA,cAAA,EAAgB;AAAA,QACd,OAAA,EAAS,IAAA;AAAA,QACT,gBAAA,EAAkB,EAAA;AAAA;AAAA,QAClB,WAAA,EAAa,KAAA;AAAA;AAAA,QACb,QAAA,EAAU;AAAA;AAAA,OACZ;AAAA,MACA,UAAA,EAAY;AAAA;AAAA,KACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,WAAA,GAAiC;AACtC,IAAA,OAAO;AAAA,MACL,GAAG,KAAK,UAAA,EAAW;AAAA,MACnB,cAAA,EAAgB;AAAA,QACd,OAAA,EAAS,KAAA;AAAA;AAAA,QACT,gBAAA,EAAkB,GAAA;AAAA,QAClB,WAAA,EAAa,IAAA;AAAA,QACb,QAAA,EAAU;AAAA,OACZ;AAAA,MACA,UAAA,EAAY;AAAA,KACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,eAAe,IAAA,EAAiC;AACrD,IAAA,QAAQ,IAAA,CAAK,aAAY;AAAG,MAC1B,KAAK,YAAA;AACH,QAAA,OAAO,KAAK,aAAA,EAAc;AAAA,MAC5B,KAAK,SAAA;AAAA,MACL,KAAK,OAAA;AAAA,MACL,KAAK,UAAA;AAAA,MACL,KAAK,OAAA;AAAA,MACL;AACE,QAAA,OAAO,KAAK,UAAA,EAAW;AAAA;AAC3B,EACF;AACF;;;;"}
|