@bitrix24/b24jssdk 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-AI.md +3 -2
- package/README.md +2 -0
- package/dist/cjs/_virtual/_commonjsHelpers.cjs +19 -0
- package/dist/cjs/_virtual/_commonjsHelpers.cjs.map +1 -0
- package/dist/cjs/_virtual/protobuf.cjs +20 -0
- package/dist/cjs/_virtual/protobuf.cjs.map +1 -0
- package/dist/cjs/_virtual/protobuf2.cjs +14 -0
- package/dist/cjs/_virtual/protobuf2.cjs.map +1 -0
- package/dist/cjs/core/abstract-b24.cjs +357 -0
- package/dist/cjs/core/abstract-b24.cjs.map +1 -0
- package/dist/cjs/core/actions/abstract-action.cjs +26 -0
- package/dist/cjs/core/actions/abstract-action.cjs.map +1 -0
- package/dist/cjs/core/actions/abstract-batch.cjs +97 -0
- package/dist/cjs/core/actions/abstract-batch.cjs.map +1 -0
- package/dist/cjs/core/actions/manager.cjs +55 -0
- package/dist/cjs/core/actions/manager.cjs.map +1 -0
- package/dist/cjs/core/actions/v2/batch-by-chunk.cjs +95 -0
- package/dist/cjs/core/actions/v2/batch-by-chunk.cjs.map +1 -0
- package/dist/cjs/core/actions/v2/batch.cjs +128 -0
- package/dist/cjs/core/actions/v2/batch.cjs.map +1 -0
- package/dist/cjs/core/actions/v2/call-list.cjs +144 -0
- package/dist/cjs/core/actions/v2/call-list.cjs.map +1 -0
- package/dist/cjs/core/actions/v2/call.cjs +56 -0
- package/dist/cjs/core/actions/v2/call.cjs.map +1 -0
- package/dist/cjs/core/actions/v2/fetch-list.cjs +145 -0
- package/dist/cjs/core/actions/v2/fetch-list.cjs.map +1 -0
- package/dist/cjs/core/actions/v2/manager-v2.cjs +76 -0
- package/dist/cjs/core/actions/v2/manager-v2.cjs.map +1 -0
- package/dist/cjs/core/actions/v3/_keyset-paginate.cjs +69 -0
- package/dist/cjs/core/actions/v3/_keyset-paginate.cjs.map +1 -0
- package/dist/cjs/core/actions/v3/aggregate.cjs +96 -0
- package/dist/cjs/core/actions/v3/aggregate.cjs.map +1 -0
- package/dist/cjs/core/actions/v3/batch-by-chunk.cjs +93 -0
- package/dist/cjs/core/actions/v3/batch-by-chunk.cjs.map +1 -0
- package/dist/cjs/core/actions/v3/batch.cjs +122 -0
- package/dist/cjs/core/actions/v3/batch.cjs.map +1 -0
- package/dist/cjs/core/actions/v3/call-list.cjs +126 -0
- package/dist/cjs/core/actions/v3/call-list.cjs.map +1 -0
- package/dist/cjs/core/actions/v3/call-tail.cjs +118 -0
- package/dist/cjs/core/actions/v3/call-tail.cjs.map +1 -0
- package/dist/cjs/core/actions/v3/call.cjs +51 -0
- package/dist/cjs/core/actions/v3/call.cjs.map +1 -0
- package/dist/cjs/core/actions/v3/fetch-list.cjs +122 -0
- package/dist/cjs/core/actions/v3/fetch-list.cjs.map +1 -0
- package/dist/cjs/core/actions/v3/fetch-tail.cjs +112 -0
- package/dist/cjs/core/actions/v3/fetch-tail.cjs.map +1 -0
- package/dist/cjs/core/actions/v3/manager-v3.cjs +100 -0
- package/dist/cjs/core/actions/v3/manager-v3.cjs.map +1 -0
- package/dist/cjs/core/http/abstract-http.cjs +641 -0
- package/dist/cjs/core/http/abstract-http.cjs.map +1 -0
- package/dist/cjs/core/http/ajax-error.cjs +113 -0
- package/dist/cjs/core/http/ajax-error.cjs.map +1 -0
- package/dist/cjs/core/http/ajax-result.cjs +219 -0
- package/dist/cjs/core/http/ajax-result.cjs.map +1 -0
- package/dist/cjs/core/http/limiters/adaptive-delayer.cjs +137 -0
- package/dist/cjs/core/http/limiters/adaptive-delayer.cjs.map +1 -0
- package/dist/cjs/core/http/limiters/manager.cjs +373 -0
- package/dist/cjs/core/http/limiters/manager.cjs.map +1 -0
- package/dist/cjs/core/http/limiters/operating-limiter.cjs +173 -0
- package/dist/cjs/core/http/limiters/operating-limiter.cjs.map +1 -0
- package/dist/cjs/core/http/limiters/params-factory.cjs +124 -0
- package/dist/cjs/core/http/limiters/params-factory.cjs.map +1 -0
- package/dist/cjs/core/http/limiters/rate-limiter.cjs +404 -0
- package/dist/cjs/core/http/limiters/rate-limiter.cjs.map +1 -0
- package/dist/cjs/core/http/redact.cjs +85 -0
- package/dist/cjs/core/http/redact.cjs.map +1 -0
- package/dist/cjs/core/http/v2.cjs +85 -0
- package/dist/cjs/core/http/v2.cjs.map +1 -0
- package/dist/cjs/core/http/v3.cjs +82 -0
- package/dist/cjs/core/http/v3.cjs.map +1 -0
- package/dist/cjs/core/interaction/batch/abstract-interaction-batch.cjs +71 -0
- package/dist/cjs/core/interaction/batch/abstract-interaction-batch.cjs.map +1 -0
- package/dist/cjs/core/interaction/batch/parse-row.cjs +69 -0
- package/dist/cjs/core/interaction/batch/parse-row.cjs.map +1 -0
- package/dist/cjs/core/interaction/batch/processing/interface-strategy.cjs +87 -0
- package/dist/cjs/core/interaction/batch/processing/interface-strategy.cjs.map +1 -0
- package/dist/cjs/core/interaction/batch/processing/v2/abstract-processing.cjs +138 -0
- package/dist/cjs/core/interaction/batch/processing/v2/abstract-processing.cjs.map +1 -0
- package/dist/cjs/core/interaction/batch/processing/v2/as-array.cjs +34 -0
- package/dist/cjs/core/interaction/batch/processing/v2/as-array.cjs.map +1 -0
- package/dist/cjs/core/interaction/batch/processing/v2/as-object.cjs +34 -0
- package/dist/cjs/core/interaction/batch/processing/v2/as-object.cjs.map +1 -0
- package/dist/cjs/core/interaction/batch/processing/v3/abstract-processing.cjs +115 -0
- package/dist/cjs/core/interaction/batch/processing/v3/abstract-processing.cjs.map +1 -0
- package/dist/cjs/core/interaction/batch/processing/v3/as-array.cjs +34 -0
- package/dist/cjs/core/interaction/batch/processing/v3/as-array.cjs.map +1 -0
- package/dist/cjs/core/interaction/batch/processing/v3/as-object.cjs +34 -0
- package/dist/cjs/core/interaction/batch/processing/v3/as-object.cjs.map +1 -0
- package/dist/cjs/core/interaction/batch/v2.cjs +47 -0
- package/dist/cjs/core/interaction/batch/v2.cjs.map +1 -0
- package/dist/cjs/core/interaction/batch/v3.cjs +45 -0
- package/dist/cjs/core/interaction/batch/v3.cjs.map +1 -0
- package/dist/cjs/core/language/list.cjs +59 -0
- package/dist/cjs/core/language/list.cjs.map +1 -0
- package/dist/cjs/core/request-id-generator.cjs +44 -0
- package/dist/cjs/core/request-id-generator.cjs.map +1 -0
- package/dist/cjs/core/result.cjs +137 -0
- package/dist/cjs/core/result.cjs.map +1 -0
- package/dist/cjs/core/sdk-error.cjs +85 -0
- package/dist/cjs/core/sdk-error.cjs.map +1 -0
- package/dist/cjs/core/tools/abstract-tool.cjs +26 -0
- package/dist/cjs/core/tools/abstract-tool.cjs.map +1 -0
- package/dist/cjs/core/tools/healthcheck.cjs +50 -0
- package/dist/cjs/core/tools/healthcheck.cjs.map +1 -0
- package/dist/cjs/core/tools/manager.cjs +52 -0
- package/dist/cjs/core/tools/manager.cjs.map +1 -0
- package/dist/cjs/core/tools/ping.cjs +58 -0
- package/dist/cjs/core/tools/ping.cjs.map +1 -0
- package/dist/cjs/core/version-manager.cjs +57 -0
- package/dist/cjs/core/version-manager.cjs.map +1 -0
- package/dist/cjs/frame/auth.cjs +100 -0
- package/dist/cjs/frame/auth.cjs.map +1 -0
- package/dist/cjs/frame/b24.cjs +178 -0
- package/dist/cjs/frame/b24.cjs.map +1 -0
- package/dist/cjs/frame/dialog.cjs +120 -0
- package/dist/cjs/frame/dialog.cjs.map +1 -0
- package/dist/cjs/frame/frame.cjs +103 -0
- package/dist/cjs/frame/frame.cjs.map +1 -0
- package/dist/cjs/frame/message/commands.cjs +39 -0
- package/dist/cjs/frame/message/commands.cjs.map +1 -0
- package/dist/cjs/frame/message/controller.cjs +191 -0
- package/dist/cjs/frame/message/controller.cjs.map +1 -0
- package/dist/cjs/frame/options.cjs +108 -0
- package/dist/cjs/frame/options.cjs.map +1 -0
- package/dist/cjs/frame/parent.cjs +259 -0
- package/dist/cjs/frame/parent.cjs.map +1 -0
- package/dist/cjs/frame/placement.cjs +156 -0
- package/dist/cjs/frame/placement.cjs.map +1 -0
- package/dist/cjs/frame/slider.cjs +162 -0
- package/dist/cjs/frame/slider.cjs.map +1 -0
- package/dist/cjs/helper/abstract-helper.cjs +55 -0
- package/dist/cjs/helper/abstract-helper.cjs.map +1 -0
- package/dist/cjs/helper/app-manager.cjs +39 -0
- package/dist/cjs/helper/app-manager.cjs.map +1 -0
- package/dist/cjs/helper/currency-manager.cjs +215 -0
- package/dist/cjs/helper/currency-manager.cjs.map +1 -0
- package/dist/cjs/helper/helper-manager.cjs +397 -0
- package/dist/cjs/helper/helper-manager.cjs.map +1 -0
- package/dist/cjs/helper/license-manager.cjs +52 -0
- package/dist/cjs/helper/license-manager.cjs.map +1 -0
- package/dist/cjs/helper/options-manager.cjs +205 -0
- package/dist/cjs/helper/options-manager.cjs.map +1 -0
- package/dist/cjs/helper/payment-manager.cjs +35 -0
- package/dist/cjs/helper/payment-manager.cjs.map +1 -0
- package/dist/cjs/helper/profile-manager.cjs +35 -0
- package/dist/cjs/helper/profile-manager.cjs.map +1 -0
- package/dist/cjs/helper/use-b24-helper.cjs +85 -0
- package/dist/cjs/helper/use-b24-helper.cjs.map +1 -0
- package/dist/cjs/hook/auth.cjs +79 -0
- package/dist/cjs/hook/auth.cjs.map +1 -0
- package/dist/cjs/hook/b24.cjs +117 -0
- package/dist/cjs/hook/b24.cjs.map +1 -0
- package/dist/cjs/index.cjs +176 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +6415 -0
- package/dist/cjs/index.d.mts +6415 -0
- package/dist/cjs/index.d.ts +6415 -0
- package/dist/cjs/loader-b24frame.cjs +103 -0
- package/dist/cjs/loader-b24frame.cjs.map +1 -0
- package/dist/cjs/logger/abstract-logger.cjs +71 -0
- package/dist/cjs/logger/abstract-logger.cjs.map +1 -0
- package/dist/cjs/logger/browser.cjs +165 -0
- package/dist/cjs/logger/browser.cjs.map +1 -0
- package/dist/cjs/logger/formatter/abstract-formatter.cjs +36 -0
- package/dist/cjs/logger/formatter/abstract-formatter.cjs.map +1 -0
- package/dist/cjs/logger/formatter/json-formatter.cjs +36 -0
- package/dist/cjs/logger/formatter/json-formatter.cjs.map +1 -0
- package/dist/cjs/logger/formatter/line-formatter.cjs +43 -0
- package/dist/cjs/logger/formatter/line-formatter.cjs.map +1 -0
- package/dist/cjs/logger/formatter/telegram-formatter.cjs +105 -0
- package/dist/cjs/logger/formatter/telegram-formatter.cjs.map +1 -0
- package/dist/cjs/logger/handler/abstract-handler.cjs +41 -0
- package/dist/cjs/logger/handler/abstract-handler.cjs.map +1 -0
- package/dist/cjs/logger/handler/consola-adapter.cjs +64 -0
- package/dist/cjs/logger/handler/consola-adapter.cjs.map +1 -0
- package/dist/cjs/logger/handler/console-handler.cjs +100 -0
- package/dist/cjs/logger/handler/console-handler.cjs.map +1 -0
- package/dist/cjs/logger/handler/console-v2-handler.cjs +53 -0
- package/dist/cjs/logger/handler/console-v2-handler.cjs.map +1 -0
- package/dist/cjs/logger/handler/memory-handler.cjs +50 -0
- package/dist/cjs/logger/handler/memory-handler.cjs.map +1 -0
- package/dist/cjs/logger/handler/stream-handler.cjs +75 -0
- package/dist/cjs/logger/handler/stream-handler.cjs.map +1 -0
- package/dist/cjs/logger/handler/telegram-handler.cjs +159 -0
- package/dist/cjs/logger/handler/telegram-handler.cjs.map +1 -0
- package/dist/cjs/logger/handler/winston-adapter.cjs +59 -0
- package/dist/cjs/logger/handler/winston-adapter.cjs.map +1 -0
- package/dist/cjs/logger/logger-factory.cjs +69 -0
- package/dist/cjs/logger/logger-factory.cjs.map +1 -0
- package/dist/cjs/logger/logger.cjs +78 -0
- package/dist/cjs/logger/logger.cjs.map +1 -0
- package/dist/cjs/logger/null-logger.cjs +34 -0
- package/dist/cjs/logger/null-logger.cjs.map +1 -0
- package/dist/cjs/logger/processor/memory-usage-processor.cjs +22 -0
- package/dist/cjs/logger/processor/memory-usage-processor.cjs.map +1 -0
- package/dist/cjs/logger/processor/pid-processor.cjs +22 -0
- package/dist/cjs/logger/processor/pid-processor.cjs.map +1 -0
- package/dist/cjs/oauth/auth.cjs +214 -0
- package/dist/cjs/oauth/auth.cjs.map +1 -0
- package/dist/cjs/oauth/b24.cjs +119 -0
- package/dist/cjs/oauth/b24.cjs.map +1 -0
- package/dist/cjs/oauth/refresh-token-error.cjs +22 -0
- package/dist/cjs/oauth/refresh-token-error.cjs.map +1 -0
- package/dist/cjs/pullClient/abstract-connector.cjs +80 -0
- package/dist/cjs/pullClient/abstract-connector.cjs.map +1 -0
- package/dist/cjs/pullClient/channel-manager.cjs +91 -0
- package/dist/cjs/pullClient/channel-manager.cjs.map +1 -0
- package/dist/cjs/pullClient/client.cjs +2177 -0
- package/dist/cjs/pullClient/client.cjs.map +1 -0
- package/dist/cjs/pullClient/errors.cjs +34 -0
- package/dist/cjs/pullClient/errors.cjs.map +1 -0
- package/dist/cjs/pullClient/json-rpc.cjs +213 -0
- package/dist/cjs/pullClient/json-rpc.cjs.map +1 -0
- package/dist/cjs/pullClient/long-polling-connector.cjs +159 -0
- package/dist/cjs/pullClient/long-polling-connector.cjs.map +1 -0
- package/dist/cjs/pullClient/protobuf/index.cjs +22 -0
- package/dist/cjs/pullClient/protobuf/index.cjs.map +1 -0
- package/dist/cjs/pullClient/protobuf/model.cjs +1060 -0
- package/dist/cjs/pullClient/protobuf/model.cjs.map +1 -0
- package/dist/cjs/pullClient/protobuf/protobuf.cjs +4655 -0
- package/dist/cjs/pullClient/protobuf/protobuf.cjs.map +1 -0
- package/dist/cjs/pullClient/shared-config.cjs +135 -0
- package/dist/cjs/pullClient/shared-config.cjs.map +1 -0
- package/dist/cjs/pullClient/storage-manager.cjs +74 -0
- package/dist/cjs/pullClient/storage-manager.cjs.map +1 -0
- package/dist/cjs/pullClient/web-socket-connector.cjs +131 -0
- package/dist/cjs/pullClient/web-socket-connector.cjs.map +1 -0
- package/dist/cjs/tools/batch-ref-v3.cjs +54 -0
- package/dist/cjs/tools/batch-ref-v3.cjs.map +1 -0
- package/dist/cjs/tools/browser.cjs +156 -0
- package/dist/cjs/tools/browser.cjs.map +1 -0
- package/dist/cjs/tools/environment.cjs +32 -0
- package/dist/cjs/tools/environment.cjs.map +1 -0
- package/dist/cjs/tools/filter-v3.cjs +139 -0
- package/dist/cjs/tools/filter-v3.cjs.map +1 -0
- package/dist/cjs/tools/formatters/iban.cjs +307 -0
- package/dist/cjs/tools/formatters/iban.cjs.map +1 -0
- package/dist/cjs/tools/formatters/numbers.cjs +68 -0
- package/dist/cjs/tools/formatters/numbers.cjs.map +1 -0
- package/dist/cjs/tools/index.cjs +42 -0
- package/dist/cjs/tools/index.cjs.map +1 -0
- package/dist/cjs/tools/scroll-size.cjs +29 -0
- package/dist/cjs/tools/scroll-size.cjs.map +1 -0
- package/dist/cjs/tools/text.cjs +210 -0
- package/dist/cjs/tools/text.cjs.map +1 -0
- package/dist/cjs/tools/type.cjs +339 -0
- package/dist/cjs/tools/type.cjs.map +1 -0
- package/dist/cjs/tools/use-formatters.cjs +462 -0
- package/dist/cjs/tools/use-formatters.cjs.map +1 -0
- package/dist/cjs/tools/uuidv7.cjs +58 -0
- package/dist/cjs/tools/uuidv7.cjs.map +1 -0
- package/dist/cjs/types/b24-helper.cjs +62 -0
- package/dist/cjs/types/b24-helper.cjs.map +1 -0
- package/dist/cjs/types/b24.cjs +18 -0
- package/dist/cjs/types/b24.cjs.map +1 -0
- package/dist/cjs/types/bizproc/index.cjs +195 -0
- package/dist/cjs/types/bizproc/index.cjs.map +1 -0
- package/dist/cjs/types/catalog/index.cjs +39 -0
- package/dist/cjs/types/catalog/index.cjs.map +1 -0
- package/dist/cjs/types/common.cjs +33 -0
- package/dist/cjs/types/common.cjs.map +1 -0
- package/dist/cjs/types/crm/entity-type.cjs +62 -0
- package/dist/cjs/types/crm/entity-type.cjs.map +1 -0
- package/dist/cjs/types/crm/productrow.cjs +19 -0
- package/dist/cjs/types/crm/productrow.cjs.map +1 -0
- package/dist/cjs/types/logger.cjs +24 -0
- package/dist/cjs/types/logger.cjs.map +1 -0
- package/dist/cjs/types/pull.cjs +94 -0
- package/dist/cjs/types/pull.cjs.map +1 -0
- package/dist/esm/_virtual/_commonjsHelpers.mjs +1 -1
- package/dist/esm/_virtual/protobuf.mjs +1 -1
- package/dist/esm/_virtual/protobuf2.mjs +1 -1
- package/dist/esm/core/abstract-b24.mjs +1 -1
- package/dist/esm/core/actions/abstract-action.mjs +1 -1
- package/dist/esm/core/actions/abstract-batch.mjs +1 -1
- package/dist/esm/core/actions/manager.mjs +1 -1
- package/dist/esm/core/actions/v2/batch-by-chunk.mjs +1 -1
- package/dist/esm/core/actions/v2/batch.mjs +1 -1
- package/dist/esm/core/actions/v2/call-list.mjs +1 -1
- package/dist/esm/core/actions/v2/call.mjs +1 -15
- package/dist/esm/core/actions/v2/call.mjs.map +1 -1
- package/dist/esm/core/actions/v2/fetch-list.mjs +1 -1
- package/dist/esm/core/actions/v2/manager-v2.mjs +1 -1
- package/dist/esm/core/actions/v3/_keyset-paginate.mjs +66 -0
- package/dist/esm/core/actions/v3/_keyset-paginate.mjs.map +1 -0
- package/dist/esm/core/actions/v3/aggregate.mjs +94 -0
- package/dist/esm/core/actions/v3/aggregate.mjs.map +1 -0
- package/dist/esm/core/actions/v3/batch-by-chunk.mjs +1 -1
- package/dist/esm/core/actions/v3/batch.mjs +1 -10
- package/dist/esm/core/actions/v3/batch.mjs.map +1 -1
- package/dist/esm/core/actions/v3/call-list.mjs +30 -44
- package/dist/esm/core/actions/v3/call-list.mjs.map +1 -1
- package/dist/esm/core/actions/v3/call-tail.mjs +116 -0
- package/dist/esm/core/actions/v3/call-tail.mjs.map +1 -0
- package/dist/esm/core/actions/v3/call.mjs +1 -10
- package/dist/esm/core/actions/v3/call.mjs.map +1 -1
- package/dist/esm/core/actions/v3/fetch-list.mjs +24 -41
- package/dist/esm/core/actions/v3/fetch-list.mjs.map +1 -1
- package/dist/esm/core/actions/v3/fetch-tail.mjs +110 -0
- package/dist/esm/core/actions/v3/fetch-tail.mjs.map +1 -0
- package/dist/esm/core/actions/v3/manager-v3.mjs +25 -1
- package/dist/esm/core/actions/v3/manager-v3.mjs.map +1 -1
- package/dist/esm/core/http/abstract-http.mjs +68 -17
- package/dist/esm/core/http/abstract-http.mjs.map +1 -1
- package/dist/esm/core/http/ajax-error.mjs +1 -1
- package/dist/esm/core/http/ajax-result.mjs +9 -8
- package/dist/esm/core/http/ajax-result.mjs.map +1 -1
- package/dist/esm/core/http/limiters/adaptive-delayer.mjs +1 -1
- package/dist/esm/core/http/limiters/manager.mjs +1 -1
- package/dist/esm/core/http/limiters/operating-limiter.mjs +1 -1
- package/dist/esm/core/http/limiters/params-factory.mjs +1 -1
- package/dist/esm/core/http/limiters/rate-limiter.mjs +1 -1
- package/dist/esm/core/http/redact.mjs +41 -13
- package/dist/esm/core/http/redact.mjs.map +1 -1
- package/dist/esm/core/http/v2.mjs +1 -18
- package/dist/esm/core/http/v2.mjs.map +1 -1
- package/dist/esm/core/http/v3.mjs +1 -15
- package/dist/esm/core/http/v3.mjs.map +1 -1
- package/dist/esm/core/interaction/batch/abstract-interaction-batch.mjs +1 -1
- package/dist/esm/core/interaction/batch/parse-row.mjs +1 -1
- package/dist/esm/core/interaction/batch/processing/interface-strategy.mjs +44 -1
- package/dist/esm/core/interaction/batch/processing/interface-strategy.mjs.map +1 -1
- package/dist/esm/core/interaction/batch/processing/v2/abstract-processing.mjs +7 -6
- package/dist/esm/core/interaction/batch/processing/v2/abstract-processing.mjs.map +1 -1
- package/dist/esm/core/interaction/batch/processing/v2/as-array.mjs +3 -3
- package/dist/esm/core/interaction/batch/processing/v2/as-array.mjs.map +1 -1
- package/dist/esm/core/interaction/batch/processing/v2/as-object.mjs +1 -1
- package/dist/esm/core/interaction/batch/processing/v3/abstract-processing.mjs +7 -19
- package/dist/esm/core/interaction/batch/processing/v3/abstract-processing.mjs.map +1 -1
- package/dist/esm/core/interaction/batch/processing/v3/as-array.mjs +3 -3
- package/dist/esm/core/interaction/batch/processing/v3/as-array.mjs.map +1 -1
- package/dist/esm/core/interaction/batch/processing/v3/as-object.mjs +1 -1
- package/dist/esm/core/interaction/batch/v2.mjs +1 -1
- package/dist/esm/core/interaction/batch/v3.mjs +1 -1
- package/dist/esm/core/language/list.mjs +1 -1
- package/dist/esm/core/request-id-generator.mjs +1 -1
- package/dist/esm/core/result.mjs +11 -4
- package/dist/esm/core/result.mjs.map +1 -1
- package/dist/esm/core/sdk-error.mjs +1 -1
- package/dist/esm/core/tools/abstract-tool.mjs +1 -1
- package/dist/esm/core/tools/healthcheck.mjs +1 -1
- package/dist/esm/core/tools/manager.mjs +1 -1
- package/dist/esm/core/tools/ping.mjs +1 -1
- package/dist/esm/core/version-manager.mjs +19 -157
- package/dist/esm/core/version-manager.mjs.map +1 -1
- package/dist/esm/frame/auth.mjs +1 -1
- package/dist/esm/frame/b24.mjs +8 -2
- package/dist/esm/frame/b24.mjs.map +1 -1
- package/dist/esm/frame/dialog.mjs +1 -1
- package/dist/esm/frame/frame.mjs +1 -1
- package/dist/esm/frame/message/commands.mjs +1 -1
- package/dist/esm/frame/message/controller.mjs +17 -6
- package/dist/esm/frame/message/controller.mjs.map +1 -1
- package/dist/esm/frame/options.mjs +1 -1
- package/dist/esm/frame/parent.mjs +1 -1
- package/dist/esm/frame/placement.mjs +1 -1
- package/dist/esm/frame/slider.mjs +1 -1
- package/dist/esm/helper/abstract-helper.mjs +1 -1
- package/dist/esm/helper/app-manager.mjs +1 -1
- package/dist/esm/helper/currency-manager.mjs +1 -1
- package/dist/esm/helper/helper-manager.mjs +1 -1
- package/dist/esm/helper/license-manager.mjs +1 -1
- package/dist/esm/helper/options-manager.mjs +1 -1
- package/dist/esm/helper/payment-manager.mjs +1 -1
- package/dist/esm/helper/profile-manager.mjs +1 -1
- package/dist/esm/helper/use-b24-helper.mjs +1 -1
- package/dist/esm/hook/auth.mjs +1 -1
- package/dist/esm/hook/b24.mjs +3 -3
- package/dist/esm/hook/b24.mjs.map +1 -1
- package/dist/esm/index.d.mts +412 -39
- package/dist/esm/index.d.ts +412 -39
- package/dist/esm/index.mjs +3 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/loader-b24frame.mjs +1 -1
- package/dist/esm/logger/abstract-logger.mjs +1 -1
- package/dist/esm/logger/browser.mjs +1 -1
- package/dist/esm/logger/formatter/abstract-formatter.mjs +1 -1
- package/dist/esm/logger/formatter/json-formatter.mjs +1 -1
- package/dist/esm/logger/formatter/line-formatter.mjs +1 -1
- package/dist/esm/logger/formatter/telegram-formatter.mjs +1 -1
- package/dist/esm/logger/handler/abstract-handler.mjs +1 -1
- package/dist/esm/logger/handler/consola-adapter.mjs +1 -1
- package/dist/esm/logger/handler/console-handler.mjs +1 -1
- package/dist/esm/logger/handler/console-v2-handler.mjs +1 -1
- package/dist/esm/logger/handler/memory-handler.mjs +1 -1
- package/dist/esm/logger/handler/stream-handler.mjs +1 -1
- package/dist/esm/logger/handler/telegram-handler.mjs +1 -1
- package/dist/esm/logger/handler/winston-adapter.mjs +1 -1
- package/dist/esm/logger/logger-factory.mjs +1 -1
- package/dist/esm/logger/logger.mjs +1 -1
- package/dist/esm/logger/null-logger.mjs +1 -1
- package/dist/esm/logger/processor/memory-usage-processor.mjs +1 -1
- package/dist/esm/logger/processor/pid-processor.mjs +1 -1
- package/dist/esm/oauth/auth.mjs +13 -16
- package/dist/esm/oauth/auth.mjs.map +1 -1
- package/dist/esm/oauth/b24.mjs +1 -1
- package/dist/esm/oauth/refresh-token-error.mjs +1 -1
- package/dist/esm/pullClient/abstract-connector.mjs +1 -1
- package/dist/esm/pullClient/channel-manager.mjs +1 -1
- package/dist/esm/pullClient/client.mjs +141 -30
- package/dist/esm/pullClient/client.mjs.map +1 -1
- package/dist/esm/pullClient/errors.mjs +1 -1
- package/dist/esm/pullClient/json-rpc.mjs +5 -4
- package/dist/esm/pullClient/json-rpc.mjs.map +1 -1
- package/dist/esm/pullClient/long-polling-connector.mjs +1 -1
- package/dist/esm/pullClient/protobuf/index.mjs +1 -1
- package/dist/esm/pullClient/protobuf/model.mjs +1 -1
- package/dist/esm/pullClient/protobuf/protobuf.mjs +1 -1
- package/dist/esm/pullClient/shared-config.mjs +1 -1
- package/dist/esm/pullClient/storage-manager.mjs +1 -1
- package/dist/esm/pullClient/web-socket-connector.mjs +1 -1
- package/dist/esm/tools/batch-ref-v3.mjs +52 -0
- package/dist/esm/tools/batch-ref-v3.mjs.map +1 -0
- package/dist/esm/tools/browser.mjs +1 -1
- package/dist/esm/tools/environment.mjs +1 -1
- package/dist/esm/tools/filter-v3.mjs +137 -0
- package/dist/esm/tools/filter-v3.mjs.map +1 -0
- package/dist/esm/tools/formatters/iban.mjs +1 -1
- package/dist/esm/tools/formatters/numbers.mjs +1 -1
- package/dist/esm/tools/index.mjs +1 -1
- package/dist/esm/tools/scroll-size.mjs +1 -1
- package/dist/esm/tools/text.mjs +1 -1
- package/dist/esm/tools/type.mjs +1 -1
- package/dist/esm/tools/use-formatters.mjs +1 -1
- package/dist/esm/tools/uuidv7.mjs +1 -1
- package/dist/esm/types/b24-helper.mjs +1 -1
- package/dist/esm/types/b24.mjs +1 -1
- package/dist/esm/types/bizproc/index.mjs +1 -1
- package/dist/esm/types/catalog/index.mjs +1 -1
- package/dist/esm/types/common.mjs +1 -1
- package/dist/esm/types/crm/entity-type.mjs +1 -1
- package/dist/esm/types/crm/productrow.mjs +1 -1
- package/dist/esm/types/logger.mjs +1 -1
- package/dist/esm/types/pull.mjs +1 -1
- package/dist/umd/index.js +1258 -719
- package/dist/umd/index.js.map +1 -1
- package/dist/umd/index.min.js +26 -26
- package/dist/umd/index.min.js.map +1 -1
- package/dist/umd/package.json +3 -0
- package/package.json +12 -4
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @package @bitrix24/b24jssdk
|
|
3
|
+
* @version 2.0.0
|
|
4
|
+
* @copyright (c) 2026 Bitrix24
|
|
5
|
+
* @license MIT
|
|
6
|
+
* @see https://github.com/bitrix24/b24jssdk
|
|
7
|
+
* @see https://bitrix24.github.io/b24jssdk/
|
|
8
|
+
*/
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const rateLimiter = require('./rate-limiter.cjs');
|
|
12
|
+
const operatingLimiter = require('./operating-limiter.cjs');
|
|
13
|
+
const adaptiveDelayer = require('./adaptive-delayer.cjs');
|
|
14
|
+
const loggerFactory = require('../../../logger/logger-factory.cjs');
|
|
15
|
+
|
|
16
|
+
var __defProp = Object.defineProperty;
|
|
17
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
18
|
+
class RestrictionManager {
|
|
19
|
+
static {
|
|
20
|
+
__name(this, "RestrictionManager");
|
|
21
|
+
}
|
|
22
|
+
#rateLimiter;
|
|
23
|
+
#operatingLimiter;
|
|
24
|
+
#adaptiveDelayer;
|
|
25
|
+
#config;
|
|
26
|
+
#stats = {
|
|
27
|
+
/** Retry attempts */
|
|
28
|
+
retries: 0,
|
|
29
|
+
/** Consecutive errors */
|
|
30
|
+
consecutiveErrors: 0,
|
|
31
|
+
/** Limit triggers */
|
|
32
|
+
limitHits: 0
|
|
33
|
+
};
|
|
34
|
+
#errorCounts = /* @__PURE__ */ new Map();
|
|
35
|
+
_logger;
|
|
36
|
+
constructor(params) {
|
|
37
|
+
this._logger = loggerFactory.LoggerFactory.createNullLogger();
|
|
38
|
+
this.#config = params;
|
|
39
|
+
this.#rateLimiter = new rateLimiter.RateLimiter(params.rateLimit);
|
|
40
|
+
this.#operatingLimiter = new operatingLimiter.OperatingLimiter(params.operatingLimit);
|
|
41
|
+
this.#adaptiveDelayer = new adaptiveDelayer.AdaptiveDelayer(params.adaptiveConfig, this.#operatingLimiter);
|
|
42
|
+
}
|
|
43
|
+
// region Logger ////
|
|
44
|
+
setLogger(logger) {
|
|
45
|
+
this._logger = logger;
|
|
46
|
+
this.#rateLimiter.setLogger(this._logger);
|
|
47
|
+
this.#operatingLimiter.setLogger(this._logger);
|
|
48
|
+
this.#adaptiveDelayer.setLogger(this._logger);
|
|
49
|
+
}
|
|
50
|
+
getLogger() {
|
|
51
|
+
return this._logger;
|
|
52
|
+
}
|
|
53
|
+
// endregion ////
|
|
54
|
+
async applyOperatingLimits(requestId, method, params) {
|
|
55
|
+
const operatingWait = await this.#operatingLimiter.waitIfNeeded(requestId, method, params);
|
|
56
|
+
if (operatingWait > 0) {
|
|
57
|
+
this.incrementStats("limitHits");
|
|
58
|
+
this.#logMethodBlocked(this.#operatingLimiter.getTitle(), requestId, method, operatingWait);
|
|
59
|
+
await this.#delay(operatingWait);
|
|
60
|
+
} else {
|
|
61
|
+
const adaptiveDelay = await this.#adaptiveDelayer.waitIfNeeded(requestId, method, params);
|
|
62
|
+
if (adaptiveDelay > 0) {
|
|
63
|
+
this.incrementStats("limitHits");
|
|
64
|
+
this.#logMethodBlocked(this.#adaptiveDelayer.getTitle(), requestId, method, adaptiveDelay);
|
|
65
|
+
await this.#delay(adaptiveDelay);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Checks and waits for the rate limit
|
|
71
|
+
* The loop is needed for parallel requests (Promise.all())
|
|
72
|
+
*/
|
|
73
|
+
async checkRateLimit(requestId, method) {
|
|
74
|
+
let waitTime;
|
|
75
|
+
let times = 1;
|
|
76
|
+
do {
|
|
77
|
+
waitTime = await this.#rateLimiter.waitIfNeeded(requestId, method);
|
|
78
|
+
if (waitTime > 0) {
|
|
79
|
+
this.incrementStats("limitHits");
|
|
80
|
+
this.#logMethodBlockedWithTimes(this.#rateLimiter.getTitle(), requestId, method, waitTime, times);
|
|
81
|
+
await this.#delay(waitTime);
|
|
82
|
+
times++;
|
|
83
|
+
}
|
|
84
|
+
} while (waitTime > 0);
|
|
85
|
+
}
|
|
86
|
+
async updateStats(requestId, method, timeData) {
|
|
87
|
+
await this.#operatingLimiter.updateStats(requestId, method, timeData);
|
|
88
|
+
await this.#adaptiveDelayer.updateStats(requestId, method, timeData);
|
|
89
|
+
await this.#rateLimiter.updateStats(requestId, method, timeData);
|
|
90
|
+
}
|
|
91
|
+
async handleError(requestId, method, params, error, attempt) {
|
|
92
|
+
if (this.#isRateLimitError(error)) {
|
|
93
|
+
const wait = await this.#handleRateLimitExceeded(requestId) * Math.pow(1.5, attempt);
|
|
94
|
+
this.#logError(this.#rateLimiter.getTitle(), requestId, "QUERY_LIMIT_EXCEEDED", error.message, method, wait);
|
|
95
|
+
return wait;
|
|
96
|
+
}
|
|
97
|
+
if (this.#isOperatingLimitError(error)) {
|
|
98
|
+
const wait = Math.max(1e4, await this.#handleOperatingLimitError(requestId, method, params, error));
|
|
99
|
+
this.#logError(this.#operatingLimiter.getTitle(), requestId, "OPERATION_TIME_LIMIT", error.message, method, wait);
|
|
100
|
+
return wait;
|
|
101
|
+
}
|
|
102
|
+
if (this.#isNonRetryableClientError(error)) {
|
|
103
|
+
this.#logNonRetryableClientError(requestId, error?.code ? `${error.code}` : "?", error?.message ?? "", method, Number(error?.status ?? 0));
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
if (!this.#isNeedThrowError(error)) {
|
|
107
|
+
const baseDelay = await this.#getErrorBackoff(requestId);
|
|
108
|
+
const maxDelay = Math.max(3e4, baseDelay);
|
|
109
|
+
const delay = Math.min(maxDelay, baseDelay * Math.pow(2, attempt));
|
|
110
|
+
const jitter = delay * 0.1 * (Math.random() * 2 - 1);
|
|
111
|
+
const wait = Math.max(100, delay + jitter);
|
|
112
|
+
this.#logSomeError(requestId, error?.code ? `${error.code}` : "?", error.message, method, wait);
|
|
113
|
+
return wait;
|
|
114
|
+
}
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Checks if the error is a rate limit
|
|
119
|
+
*/
|
|
120
|
+
#isRateLimitError(error) {
|
|
121
|
+
return error.status === 503 || error.code === "QUERY_LIMIT_EXCEEDED";
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Delay when exceeding the rate limit
|
|
125
|
+
*/
|
|
126
|
+
async #handleRateLimitExceeded(requestId) {
|
|
127
|
+
return this.#rateLimiter.handleExceeded(requestId);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Checks if the error is an operating limit
|
|
131
|
+
*
|
|
132
|
+
* @memo `OPERATION_TIME_LIMIT` && `429` - obtained through practical means
|
|
133
|
+
* @memo This doesn't work for `batch` queries.
|
|
134
|
+
*/
|
|
135
|
+
#isOperatingLimitError(error) {
|
|
136
|
+
return error.status === 429 || error.code === "OPERATION_TIME_LIMIT";
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Operating limit error delay
|
|
140
|
+
*
|
|
141
|
+
* @memo Currently, the errors don't include timings for operations.
|
|
142
|
+
* For this reason, we will take data from the previous request
|
|
143
|
+
*/
|
|
144
|
+
async #handleOperatingLimitError(requestId, method, params, _error) {
|
|
145
|
+
return this.#operatingLimiter.getTimeToFree(requestId, method, params, _error);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Checks if the error is a non-retryable client error (HTTP 4xx).
|
|
149
|
+
*
|
|
150
|
+
* `429` is excluded — it is handled as a rate/operating limit and is retried
|
|
151
|
+
* with backoff. `408` (request timeout) is excluded — it is transient and is
|
|
152
|
+
* governed by `retryOnNetworkError`.
|
|
153
|
+
*/
|
|
154
|
+
#isNonRetryableClientError(error) {
|
|
155
|
+
const status = Number(error?.status ?? 0);
|
|
156
|
+
if (Number.isNaN(status)) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
return status >= 400 && status < 500 && status !== 408 && status !== 429;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Checks whether attempts should be stopped if errors are encountered that are unclear.
|
|
163
|
+
*/
|
|
164
|
+
#isNeedThrowError(error) {
|
|
165
|
+
const answerError = {
|
|
166
|
+
code: error?.code ?? "-1",
|
|
167
|
+
description: error?.message ?? ""
|
|
168
|
+
};
|
|
169
|
+
return [
|
|
170
|
+
...this.exceptionCodeForHard,
|
|
171
|
+
...this.exceptionCodeForSoft
|
|
172
|
+
].includes(answerError.code) || (answerError.description ?? "").includes("Could not find value for parameter");
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Built-in hard error codes (always throw, never retry).
|
|
176
|
+
*
|
|
177
|
+
* Includes authorization and fatal codes that must never be silently retried.
|
|
178
|
+
* Use `RestrictionParams.hardErrorCodes` to extend this list with custom codes.
|
|
179
|
+
*/
|
|
180
|
+
static BUILT_IN_HARD_ERROR_CODES = [
|
|
181
|
+
"ERR_BAD_REQUEST",
|
|
182
|
+
"JSSDK_UNKNOWN_ERROR",
|
|
183
|
+
"100",
|
|
184
|
+
"INTERNAL_SERVER_ERROR",
|
|
185
|
+
"ERROR_UNEXPECTED_ANSWER",
|
|
186
|
+
"PORTAL_DELETED",
|
|
187
|
+
"ERROR_BATCH_METHOD_NOT_ALLOWED",
|
|
188
|
+
"ERROR_BATCH_LENGTH_EXCEEDED",
|
|
189
|
+
"NO_AUTH_FOUND",
|
|
190
|
+
"INVALID_REQUEST",
|
|
191
|
+
"OVERLOAD_LIMIT",
|
|
192
|
+
"expired_token",
|
|
193
|
+
"invalid_token",
|
|
194
|
+
"ACCESS_DENIED",
|
|
195
|
+
"INVALID_CREDENTIALS",
|
|
196
|
+
"user_access_error",
|
|
197
|
+
"insufficient_scope",
|
|
198
|
+
"ERROR_MANIFEST_IS_NOT_AVAILABLE",
|
|
199
|
+
"allowed_only_intranet_user",
|
|
200
|
+
"NOT_FOUND",
|
|
201
|
+
"INVALID_ARG_VALUE"
|
|
202
|
+
];
|
|
203
|
+
/**
|
|
204
|
+
* Built-in soft error codes (returned as `AjaxResult` with error, never thrown).
|
|
205
|
+
*
|
|
206
|
+
* Use `RestrictionParams.softErrorCodes` to extend this list with custom codes.
|
|
207
|
+
*/
|
|
208
|
+
static BUILT_IN_SOFT_ERROR_CODES = [
|
|
209
|
+
"ERROR_ENTITY_NOT_FOUND",
|
|
210
|
+
"BITRIX_REST_V3_EXCEPTION_ACCESSDENIEDEXCEPTION",
|
|
211
|
+
"BITRIX_REST_V3_EXCEPTION_INVALIDJSONEXCEPTION",
|
|
212
|
+
"BITRIX_REST_V3_EXCEPTION_INVALIDFILTEREXCEPTION",
|
|
213
|
+
"BITRIX_REST_V3_EXCEPTION_INVALIDSELECTEXCEPTION",
|
|
214
|
+
"BITRIX_REST_V3_EXCEPTION_ENTITYNOTFOUNDEXCEPTION",
|
|
215
|
+
"BITRIX_REST_V3_EXCEPTION_METHODNOTFOUNDEXCEPTION",
|
|
216
|
+
"BITRIX_REST_V3_EXCEPTION_UNKNOWNDTOPROPERTYEXCEPTION",
|
|
217
|
+
"BITRIX_REST_V3_EXCEPTION_VALIDATION_REQUESTVALIDATIONEXCEPTION",
|
|
218
|
+
"BITRIX_REST_V3_EXCEPTION_VALIDATION_DTOVALIDATIONEXCEPTION"
|
|
219
|
+
];
|
|
220
|
+
/**
|
|
221
|
+
* Codes that cause the SDK to throw immediately.
|
|
222
|
+
*
|
|
223
|
+
* Composed of:
|
|
224
|
+
* - `BUILT_IN_HARD_ERROR_CODES` (always included)
|
|
225
|
+
* - `NETWORK_ERROR` and `REQUEST_TIMEOUT` when `retryOnNetworkError === false`
|
|
226
|
+
* - `RestrictionParams.hardErrorCodes` (user-provided extensions)
|
|
227
|
+
*/
|
|
228
|
+
get exceptionCodeForHard() {
|
|
229
|
+
const codes = [...RestrictionManager.BUILT_IN_HARD_ERROR_CODES];
|
|
230
|
+
if (this.#config.retryOnNetworkError === false) {
|
|
231
|
+
codes.push("NETWORK_ERROR", "REQUEST_TIMEOUT");
|
|
232
|
+
}
|
|
233
|
+
if (this.#config.hardErrorCodes && this.#config.hardErrorCodes.length > 0) {
|
|
234
|
+
codes.push(...this.#config.hardErrorCodes);
|
|
235
|
+
}
|
|
236
|
+
return codes;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Codes returned as `AjaxResult` with an `AjaxError` payload instead of thrown.
|
|
240
|
+
*
|
|
241
|
+
* Composed of:
|
|
242
|
+
* - `BUILT_IN_SOFT_ERROR_CODES` (always included)
|
|
243
|
+
* - `RestrictionParams.softErrorCodes` (user-provided extensions)
|
|
244
|
+
*/
|
|
245
|
+
get exceptionCodeForSoft() {
|
|
246
|
+
const codes = [...RestrictionManager.BUILT_IN_SOFT_ERROR_CODES];
|
|
247
|
+
if (this.#config.softErrorCodes && this.#config.softErrorCodes.length > 0) {
|
|
248
|
+
codes.push(...this.#config.softErrorCodes);
|
|
249
|
+
}
|
|
250
|
+
return codes;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Delay due to unknown errors
|
|
254
|
+
*/
|
|
255
|
+
async #getErrorBackoff(_requestId) {
|
|
256
|
+
return this.#config.retryDelay;
|
|
257
|
+
}
|
|
258
|
+
incrementError(method) {
|
|
259
|
+
const current = this.#errorCounts.get(method) || 0;
|
|
260
|
+
this.#errorCounts.set(method, current + 1);
|
|
261
|
+
this.incrementStats("consecutiveErrors");
|
|
262
|
+
}
|
|
263
|
+
resetErrors(method) {
|
|
264
|
+
this.#errorCounts.delete(method);
|
|
265
|
+
this.#stats.consecutiveErrors = 0;
|
|
266
|
+
}
|
|
267
|
+
incrementStats(stat) {
|
|
268
|
+
this.#stats[stat]++;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Returns job statistics
|
|
272
|
+
*/
|
|
273
|
+
getStats() {
|
|
274
|
+
return {
|
|
275
|
+
...this.#stats,
|
|
276
|
+
...this.#rateLimiter.getStats(),
|
|
277
|
+
...this.#adaptiveDelayer.getStats(),
|
|
278
|
+
...this.#operatingLimiter.getStats(),
|
|
279
|
+
errorCounts: Object.fromEntries(this.#errorCounts)
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Resets limiters and statistics
|
|
284
|
+
*/
|
|
285
|
+
async reset() {
|
|
286
|
+
await this.#rateLimiter.reset();
|
|
287
|
+
await this.#operatingLimiter.reset();
|
|
288
|
+
await this.#adaptiveDelayer.reset();
|
|
289
|
+
this.#errorCounts.clear();
|
|
290
|
+
this.#stats = {
|
|
291
|
+
retries: 0,
|
|
292
|
+
consecutiveErrors: 0,
|
|
293
|
+
limitHits: 0
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
async setConfig(params) {
|
|
297
|
+
this.#config = params;
|
|
298
|
+
await this.#rateLimiter.setConfig(params.rateLimit);
|
|
299
|
+
await this.#operatingLimiter.setConfig(params.operatingLimit);
|
|
300
|
+
await this.#adaptiveDelayer.setConfig(params.adaptiveConfig);
|
|
301
|
+
}
|
|
302
|
+
getParams() {
|
|
303
|
+
return { ...this.#config };
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Delay function
|
|
307
|
+
*/
|
|
308
|
+
async #delay(ms) {
|
|
309
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Public access to the delay function
|
|
313
|
+
*/
|
|
314
|
+
async waiteDelay(ms) {
|
|
315
|
+
return this.#delay(ms);
|
|
316
|
+
}
|
|
317
|
+
// region Log ////
|
|
318
|
+
#logMethodBlocked(limiter, requestId, method, wait) {
|
|
319
|
+
this.getLogger().notice(`${limiter} blocked method ${method}`, {
|
|
320
|
+
requestId,
|
|
321
|
+
method,
|
|
322
|
+
wait,
|
|
323
|
+
limiter
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
#logMethodBlockedWithTimes(limiter, requestId, method, wait, times) {
|
|
327
|
+
this.getLogger().notice(`${limiter} blocked method ${method} | ${times} times`, {
|
|
328
|
+
requestId,
|
|
329
|
+
method,
|
|
330
|
+
times,
|
|
331
|
+
wait,
|
|
332
|
+
limiter
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
#logError(limiter, requestId, code, message, method, wait) {
|
|
336
|
+
this.getLogger().error(`${limiter} recognized the ${code} error for the ${method} method`, {
|
|
337
|
+
requestId,
|
|
338
|
+
method,
|
|
339
|
+
wait,
|
|
340
|
+
limiter,
|
|
341
|
+
error: {
|
|
342
|
+
code,
|
|
343
|
+
message
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
#logSomeError(requestId, code, message, method, wait) {
|
|
348
|
+
this.getLogger().error(`recognized the ${code} error for the ${method} method`, {
|
|
349
|
+
requestId,
|
|
350
|
+
method,
|
|
351
|
+
wait,
|
|
352
|
+
error: {
|
|
353
|
+
code,
|
|
354
|
+
message
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
#logNonRetryableClientError(requestId, code, message, method, status) {
|
|
359
|
+
this.getLogger().error(`client error ${status} (${code}) for the ${method} method is not retryable`, {
|
|
360
|
+
requestId,
|
|
361
|
+
method,
|
|
362
|
+
status,
|
|
363
|
+
error: {
|
|
364
|
+
code,
|
|
365
|
+
message
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
// endregion ////
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
exports.RestrictionManager = RestrictionManager;
|
|
373
|
+
//# sourceMappingURL=manager.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.cjs","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 // Client errors (HTTP 4xx) are deterministic — retrying cannot change the\n // outcome, so fail fast regardless of whether the error code is enumerated.\n // 429 (rate/operating limit) is handled above; 408 (timeout) stays retryable.\n if (this.#isNonRetryableClientError(error)) {\n this.#logNonRetryableClientError(requestId, error?.code ? `${error.code}` : '?', error?.message ?? '', method, Number(error?.status ?? 0))\n return 0\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 if the error is a non-retryable client error (HTTP 4xx).\n *\n * `429` is excluded — it is handled as a rate/operating limit and is retried\n * with backoff. `408` (request timeout) is excluded — it is transient and is\n * governed by `retryOnNetworkError`.\n */\n #isNonRetryableClientError(error: any): boolean {\n const status = Number(error?.status ?? 0)\n if (Number.isNaN(status)) {\n return false\n }\n return status >= 400 && status < 500 && status !== 408 && status !== 429\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 * Built-in hard error codes (always throw, never retry).\n *\n * Includes authorization and fatal codes that must never be silently retried.\n * Use `RestrictionParams.hardErrorCodes` to extend this list with custom codes.\n */\n static readonly BUILT_IN_HARD_ERROR_CODES: readonly string[] = [\n 'ERR_BAD_REQUEST',\n 'JSSDK_UNKNOWN_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', 'invalid_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 * Built-in soft error codes (returned as `AjaxResult` with error, never thrown).\n *\n * Use `RestrictionParams.softErrorCodes` to extend this list with custom codes.\n */\n static readonly BUILT_IN_SOFT_ERROR_CODES: readonly string[] = [\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 * Codes that cause the SDK to throw immediately.\n *\n * Composed of:\n * - `BUILT_IN_HARD_ERROR_CODES` (always included)\n * - `NETWORK_ERROR` and `REQUEST_TIMEOUT` when `retryOnNetworkError === false`\n * - `RestrictionParams.hardErrorCodes` (user-provided extensions)\n */\n get exceptionCodeForHard(): string[] {\n const codes = [...RestrictionManager.BUILT_IN_HARD_ERROR_CODES]\n\n if (this.#config.retryOnNetworkError === false) {\n codes.push('NETWORK_ERROR', 'REQUEST_TIMEOUT')\n }\n\n if (this.#config.hardErrorCodes && this.#config.hardErrorCodes.length > 0) {\n codes.push(...this.#config.hardErrorCodes)\n }\n\n return codes\n }\n\n /**\n * Codes returned as `AjaxResult` with an `AjaxError` payload instead of thrown.\n *\n * Composed of:\n * - `BUILT_IN_SOFT_ERROR_CODES` (always included)\n * - `RestrictionParams.softErrorCodes` (user-provided extensions)\n */\n get exceptionCodeForSoft(): string[] {\n const codes = [...RestrictionManager.BUILT_IN_SOFT_ERROR_CODES]\n\n if (this.#config.softErrorCodes && this.#config.softErrorCodes.length > 0) {\n codes.push(...this.#config.softErrorCodes)\n }\n\n return codes\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\n #logNonRetryableClientError(requestId: string, code: string, message: string, method: string, status: number) {\n this.getLogger().error(`client error ${status} (${code}) for the ${method} method is not retryable`, {\n requestId,\n method,\n status,\n error: {\n code,\n message\n }\n })\n }\n // endregion ////\n}\n"],"names":["LoggerFactory","RateLimiter","OperatingLimiter","AdaptiveDelayer"],"mappings":";;;;;;;;;;;;;;;;;AAYO,MAAM,kBAAA,CAAmB;AAAA,EAZhC;AAYgC,IAAA,MAAA,CAAA,IAAA,EAAA,oBAAA,CAAA;AAAA;AAAA,EAC9B,YAAA;AAAA,EACA,iBAAA;AAAA,EACA,gBAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA,GAAuF;AAAA;AAAA,IAErF,OAAA,EAAS,CAAA;AAAA;AAAA,IAET,iBAAA,EAAmB,CAAA;AAAA;AAAA,IAEnB,SAAA,EAAW;AAAA,GACb;AAAA,EAEA,YAAA,uBAAmB,GAAA,EAAoB;AAAA,EAE/B,OAAA;AAAA,EAER,YAAY,MAAA,EAA2B;AACrC,IAAA,IAAA,CAAK,OAAA,GAAUA,4BAAc,gBAAA,EAAiB;AAC9C,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,IAAA,IAAA,CAAK,YAAA,GAAe,IAAIC,uBAAA,CAAY,MAAA,CAAO,SAAU,CAAA;AACrD,IAAA,IAAA,CAAK,iBAAA,GAAoB,IAAIC,iCAAA,CAAiB,MAAA,CAAO,cAAe,CAAA;AACpE,IAAA,IAAA,CAAK,mBAAmB,IAAIC,+BAAA,CAAgB,MAAA,CAAO,cAAA,EAAiB,KAAK,iBAAiB,CAAA;AAAA,EAC5F;AAAA;AAAA,EAGA,UAAU,MAAA,EAA+B;AACvC,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,IAAA,IAAA,CAAK,YAAA,CAAa,SAAA,CAAU,IAAA,CAAK,OAAO,CAAA;AACxC,IAAA,IAAA,CAAK,iBAAA,CAAkB,SAAA,CAAU,IAAA,CAAK,OAAO,CAAA;AAC7C,IAAA,IAAA,CAAK,gBAAA,CAAiB,SAAA,CAAU,IAAA,CAAK,OAAO,CAAA;AAAA,EAC9C;AAAA,EAEA,SAAA,GAA6B;AAC3B,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd;AAAA;AAAA,EAGA,MAAM,oBAAA,CAAqB,SAAA,EAAmB,MAAA,EAAgB,MAAA,EAA6B;AAEzF,IAAA,MAAM,gBAAgB,MAAM,IAAA,CAAK,kBAAkB,YAAA,CAAa,SAAA,EAAW,QAAQ,MAAM,CAAA;AACzF,IAAA,IAAI,gBAAgB,CAAA,EAAG;AACrB,MAAA,IAAA,CAAK,eAAe,WAAW,CAAA;AAC/B,MAAA,IAAA,CAAK,kBAAkB,IAAA,CAAK,iBAAA,CAAkB,UAAS,EAAG,SAAA,EAAW,QAAQ,aAAa,CAAA;AAC1F,MAAA,MAAM,IAAA,CAAK,OAAO,aAAa,CAAA;AAAA,IACjC,CAAA,MAAO;AAEL,MAAA,MAAM,gBAAgB,MAAM,IAAA,CAAK,iBAAiB,YAAA,CAAa,SAAA,EAAW,QAAQ,MAAM,CAAA;AACxF,MAAA,IAAI,gBAAgB,CAAA,EAAG;AACrB,QAAA,IAAA,CAAK,eAAe,WAAW,CAAA;AAC/B,QAAA,IAAA,CAAK,kBAAkB,IAAA,CAAK,gBAAA,CAAiB,UAAS,EAAG,SAAA,EAAW,QAAQ,aAAa,CAAA;AACzF,QAAA,MAAM,IAAA,CAAK,OAAO,aAAa,CAAA;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAA,CAAe,SAAA,EAAmB,MAAA,EAA+B;AAErE,IAAA,IAAI,QAAA;AACJ,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,GAAG;AACD,MAAA,QAAA,GAAW,MAAM,IAAA,CAAK,YAAA,CAAa,YAAA,CAAa,WAAW,MAAM,CAAA;AACjE,MAAA,IAAI,WAAW,CAAA,EAAG;AAChB,QAAA,IAAA,CAAK,eAAe,WAAW,CAAA;AAC/B,QAAA,IAAA,CAAK,0BAAA,CAA2B,KAAK,YAAA,CAAa,QAAA,IAAY,SAAA,EAAW,MAAA,EAAQ,UAAU,KAAK,CAAA;AAChG,QAAA,MAAM,IAAA,CAAK,OAAO,QAAQ,CAAA;AAC1B,QAAA,KAAA,EAAA;AAAA,MACF;AAAA,IACF,SAAS,QAAA,GAAW,CAAA;AAAA,EACtB;AAAA,EAEA,MAAM,WAAA,CACJ,SAAA,EACA,MAAA,EACA,QAAA,EACe;AACf,IAAA,MAAM,IAAA,CAAK,iBAAA,CAAkB,WAAA,CAAY,SAAA,EAAW,QAAQ,QAAQ,CAAA;AACpE,IAAA,MAAM,IAAA,CAAK,gBAAA,CAAiB,WAAA,CAAY,SAAA,EAAW,QAAQ,QAAQ,CAAA;AACnE,IAAA,MAAM,IAAA,CAAK,YAAA,CAAa,WAAA,CAAY,SAAA,EAAW,QAAQ,QAAQ,CAAA;AAAA,EACjE;AAAA,EAEA,MAAM,WAAA,CACJ,SAAA,EACA,MAAA,EACA,MAAA,EACA,OACA,OAAA,EACiB;AAEjB,IAAA,IAAI,IAAA,CAAK,iBAAA,CAAkB,KAAK,CAAA,EAAG;AAEjC,MAAA,MAAM,IAAA,GAAQ,MAAM,IAAA,CAAK,wBAAA,CAAyB,SAAS,CAAA,GAAK,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,OAAO,CAAA;AACrF,MAAA,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,YAAA,CAAa,QAAA,EAAS,EAAG,WAAW,sBAAA,EAAwB,KAAA,CAAM,OAAA,EAAS,MAAA,EAAQ,IAAI,CAAA;AAC3G,MAAA,OAAO,IAAA;AAAA,IACT;AAGA,IAAA,IAAI,IAAA,CAAK,sBAAA,CAAuB,KAAK,CAAA,EAAG;AAEtC,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,GAAA,EAAQ,MAAM,IAAA,CAAK,0BAAA,CAA2B,SAAA,EAAW,MAAA,EAAQ,MAAA,EAAQ,KAAK,CAAC,CAAA;AACrG,MAAA,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,iBAAA,CAAkB,QAAA,EAAS,EAAG,WAAW,sBAAA,EAAwB,KAAA,CAAM,OAAA,EAAS,MAAA,EAAQ,IAAI,CAAA;AAChH,MAAA,OAAO,IAAA;AAAA,IACT;AAKA,IAAA,IAAI,IAAA,CAAK,0BAAA,CAA2B,KAAK,CAAA,EAAG;AAC1C,MAAA,IAAA,CAAK,4BAA4B,SAAA,EAAW,KAAA,EAAO,IAAA,GAAO,CAAA,EAAG,MAAM,IAAI,CAAA,CAAA,GAAK,GAAA,EAAK,KAAA,EAAO,WAAW,EAAA,EAAI,MAAA,EAAQ,OAAO,KAAA,EAAO,MAAA,IAAU,CAAC,CAAC,CAAA;AACzI,MAAA,OAAO,CAAA;AAAA,IACT;AAGA,IAAA,IAAI,CAAC,IAAA,CAAK,iBAAA,CAAkB,KAAK,CAAA,EAAG;AAElC,MAAA,MAAM,SAAA,GAAY,MAAM,IAAA,CAAK,gBAAA,CAAiB,SAAS,CAAA;AACvD,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,GAAA,EAAQ,SAAS,CAAA;AAC3C,MAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,CAAI,QAAA,EAAU,YAAY,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAO,CAAC,CAAA;AAGjE,MAAA,MAAM,SAAS,KAAA,GAAQ,GAAA,IAAO,IAAA,CAAK,MAAA,KAAW,CAAA,GAAI,CAAA,CAAA;AAClD,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,QAAQ,MAAM,CAAA;AAEzC,MAAA,IAAA,CAAK,aAAA,CAAc,SAAA,EAAW,KAAA,EAAO,IAAA,GAAO,CAAA,EAAG,KAAA,CAAM,IAAI,CAAA,CAAA,GAAK,GAAA,EAAK,KAAA,CAAM,OAAA,EAAS,MAAA,EAAQ,IAAI,CAAA;AAE9F,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,OAAO,CAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,KAAA,EAAqB;AACrC,IAAA,OAAO,KAAA,CAAM,MAAA,KAAW,GAAA,IACnB,KAAA,CAAM,IAAA,KAAS,sBAAA;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,yBAAyB,SAAA,EAAoC;AACjE,IAAA,OAAO,IAAA,CAAK,YAAA,CAAa,cAAA,CAAe,SAAS,CAAA;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,uBAAuB,KAAA,EAAqB;AAC1C,IAAA,OAAO,KAAA,CAAM,MAAA,KAAW,GAAA,IACnB,KAAA,CAAM,IAAA,KAAS,sBAAA;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,0BAAA,CAA2B,SAAA,EAAmB,MAAA,EAAgB,QAAc,MAAA,EAA+B;AAC/G,IAAA,OAAO,KAAK,iBAAA,CAAkB,aAAA,CAAc,SAAA,EAAW,MAAA,EAAQ,QAAQ,MAAM,CAAA;AAAA,EAC/E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,2BAA2B,KAAA,EAAqB;AAC9C,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,KAAA,EAAO,MAAA,IAAU,CAAC,CAAA;AACxC,IAAA,IAAI,MAAA,CAAO,KAAA,CAAM,MAAM,CAAA,EAAG;AACxB,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,OAAO,UAAU,GAAA,IAAO,MAAA,GAAS,GAAA,IAAO,MAAA,KAAW,OAAO,MAAA,KAAW,GAAA;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,KAAA,EAAqB;AACrC,IAAA,MAAM,WAAA,GAAc;AAAA,MAClB,IAAA,EAAM,OAAO,IAAA,IAAQ,IAAA;AAAA,MACrB,WAAA,EAAa,OAAO,OAAA,IAAW;AAAA,KACjC;AAEA,IAAA,OAAO;AAAA,MACL,GAAG,IAAA,CAAK,oBAAA;AAAA,MACR,GAAG,IAAA,CAAK;AAAA,KACV,CAAE,SAAS,WAAA,CAAY,IAAI,MACvB,WAAA,CAAY,WAAA,IAAe,EAAA,EAAI,QAAA,CAAS,oCAAoC,CAAA;AAAA,EAClF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAgB,yBAAA,GAA+C;AAAA,IAC7D,iBAAA;AAAA,IACA,qBAAA;AAAA,IACA,KAAA;AAAA,IACA,uBAAA;AAAA,IAAyB,yBAAA;AAAA,IAA2B,gBAAA;AAAA,IACpD,gCAAA;AAAA,IAAkC,6BAAA;AAAA,IAClC,eAAA;AAAA,IACA,iBAAA;AAAA,IACA,gBAAA;AAAA,IAAkB,eAAA;AAAA,IAAiB,eAAA;AAAA,IACnC,eAAA;AAAA,IAAiB,qBAAA;AAAA,IAAuB,mBAAA;AAAA,IAAqB,oBAAA;AAAA,IAC7D,iCAAA;AAAA,IACA,4BAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAgB,yBAAA,GAA+C;AAAA,IAC7D,wBAAA;AAAA,IACA,gDAAA;AAAA,IACA,+CAAA;AAAA,IACA,iDAAA;AAAA,IACA,iDAAA;AAAA,IACA,kDAAA;AAAA,IACA,kDAAA;AAAA,IACA,sDAAA;AAAA,IACA,gEAAA;AAAA,IACA;AAAA,GACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,IAAI,oBAAA,GAAiC;AACnC,IAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,kBAAA,CAAmB,yBAAyB,CAAA;AAE9D,IAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,mBAAA,KAAwB,KAAA,EAAO;AAC9C,MAAA,KAAA,CAAM,IAAA,CAAK,iBAAiB,iBAAiB,CAAA;AAAA,IAC/C;AAEA,IAAA,IAAI,KAAK,OAAA,CAAQ,cAAA,IAAkB,KAAK,OAAA,CAAQ,cAAA,CAAe,SAAS,CAAA,EAAG;AACzE,MAAA,KAAA,CAAM,IAAA,CAAK,GAAG,IAAA,CAAK,OAAA,CAAQ,cAAc,CAAA;AAAA,IAC3C;AAEA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,IAAI,oBAAA,GAAiC;AACnC,IAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,kBAAA,CAAmB,yBAAyB,CAAA;AAE9D,IAAA,IAAI,KAAK,OAAA,CAAQ,cAAA,IAAkB,KAAK,OAAA,CAAQ,cAAA,CAAe,SAAS,CAAA,EAAG;AACzE,MAAA,KAAA,CAAM,IAAA,CAAK,GAAG,IAAA,CAAK,OAAA,CAAQ,cAAc,CAAA;AAAA,IAC3C;AAEA,IAAA,OAAO,KAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAiB,UAAA,EAAqC;AAC1D,IAAA,OAAO,KAAK,OAAA,CAAQ,UAAA;AAAA,EACtB;AAAA,EAEA,eAAe,MAAA,EAAsB;AACnC,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA,IAAK,CAAA;AACjD,IAAA,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,MAAA,EAAQ,OAAA,GAAU,CAAC,CAAA;AACzC,IAAA,IAAA,CAAK,eAAe,mBAAmB,CAAA;AAAA,EACzC;AAAA,EAEA,YAAY,MAAA,EAAsB;AAChC,IAAA,IAAA,CAAK,YAAA,CAAa,OAAO,MAAM,CAAA;AAC/B,IAAA,IAAA,CAAK,OAAO,iBAAA,GAAoB,CAAA;AAAA,EAClC;AAAA,EAEA,eAAe,IAAA,EAAgG;AAC7G,IAAA,IAAA,CAAK,OAAO,IAAI,CAAA,EAAA;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAA,GAGE;AACA,IAAA,OAAO;AAAA,MACL,GAAG,IAAA,CAAK,MAAA;AAAA,MACR,GAAG,IAAA,CAAK,YAAA,CAAa,QAAA,EAAS;AAAA,MAC9B,GAAG,IAAA,CAAK,gBAAA,CAAiB,QAAA,EAAS;AAAA,MAClC,GAAG,IAAA,CAAK,iBAAA,CAAkB,QAAA,EAAS;AAAA,MACnC,WAAA,EAAa,MAAA,CAAO,WAAA,CAAY,IAAA,CAAK,YAAY;AAAA,KACnD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAA,GAAuB;AAC3B,IAAA,MAAM,IAAA,CAAK,aAAa,KAAA,EAAM;AAC9B,IAAA,MAAM,IAAA,CAAK,kBAAkB,KAAA,EAAM;AACnC,IAAA,MAAM,IAAA,CAAK,iBAAiB,KAAA,EAAM;AAClC,IAAA,IAAA,CAAK,aAAa,KAAA,EAAM;AAExB,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,OAAA,EAAS,CAAA;AAAA,MACT,iBAAA,EAAmB,CAAA;AAAA,MACnB,SAAA,EAAW;AAAA,KACb;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,MAAA,EAA0C;AACxD,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,IAAA,MAAM,IAAA,CAAK,YAAA,CAAa,SAAA,CAAU,MAAA,CAAO,SAAU,CAAA;AACnD,IAAA,MAAM,IAAA,CAAK,iBAAA,CAAkB,SAAA,CAAU,MAAA,CAAO,cAAe,CAAA;AAC7D,IAAA,MAAM,IAAA,CAAK,gBAAA,CAAiB,SAAA,CAAU,MAAA,CAAO,cAAe,CAAA;AAAA,EAC9D;AAAA,EAEA,SAAA,GAA+B;AAC7B,IAAA,OAAO,EAAE,GAAG,IAAA,CAAK,OAAA,EAAQ;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,EAAA,EAA2B;AACtC,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW,EAAA,EAA2B;AAC1C,IAAA,OAAO,IAAA,CAAK,OAAO,EAAE,CAAA;AAAA,EACvB;AAAA;AAAA,EAGA,iBAAA,CAAkB,OAAA,EAAiB,SAAA,EAAmB,MAAA,EAAgB,IAAA,EAAc;AAClF,IAAA,IAAA,CAAK,WAAU,CAAE,MAAA,CAAO,GAAG,OAAO,CAAA,gBAAA,EAAmB,MAAM,CAAA,CAAA,EAAI;AAAA,MAC7D,SAAA;AAAA,MACA,MAAA;AAAA,MACA,IAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH;AAAA,EAEA,0BAAA,CAA2B,OAAA,EAAiB,SAAA,EAAmB,MAAA,EAAgB,MAAc,KAAA,EAAe;AAC1G,IAAA,IAAA,CAAK,SAAA,GAAY,MAAA,CAAO,CAAA,EAAG,OAAO,CAAA,gBAAA,EAAmB,MAAM,CAAA,GAAA,EAAM,KAAK,CAAA,MAAA,CAAA,EAAU;AAAA,MAC9E,SAAA;AAAA,MACA,MAAA;AAAA,MACA,KAAA;AAAA,MACA,IAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH;AAAA,EAEA,UAAU,OAAA,EAAiB,SAAA,EAAmB,IAAA,EAAc,OAAA,EAAiB,QAAgB,IAAA,EAAc;AACzG,IAAA,IAAA,CAAK,SAAA,GAAY,KAAA,CAAM,CAAA,EAAG,OAAO,CAAA,gBAAA,EAAmB,IAAI,CAAA,eAAA,EAAkB,MAAM,CAAA,OAAA,CAAA,EAAW;AAAA,MACzF,SAAA;AAAA,MACA,MAAA;AAAA,MACA,IAAA;AAAA,MACA,OAAA;AAAA,MACA,KAAA,EAAO;AAAA,QACL,IAAA;AAAA,QACA;AAAA;AACF,KACD,CAAA;AAAA,EACH;AAAA,EAEA,aAAA,CAAc,SAAA,EAAmB,IAAA,EAAc,OAAA,EAAiB,QAAgB,IAAA,EAAc;AAC5F,IAAA,IAAA,CAAK,WAAU,CAAE,KAAA,CAAM,kBAAkB,IAAI,CAAA,eAAA,EAAkB,MAAM,CAAA,OAAA,CAAA,EAAW;AAAA,MAC9E,SAAA;AAAA,MACA,MAAA;AAAA,MACA,IAAA;AAAA,MACA,KAAA,EAAO;AAAA,QACL,IAAA;AAAA,QACA;AAAA;AACF,KACD,CAAA;AAAA,EACH;AAAA,EAEA,2BAAA,CAA4B,SAAA,EAAmB,IAAA,EAAc,OAAA,EAAiB,QAAgB,MAAA,EAAgB;AAC5G,IAAA,IAAA,CAAK,SAAA,GAAY,KAAA,CAAM,CAAA,aAAA,EAAgB,MAAM,CAAA,EAAA,EAAK,IAAI,CAAA,UAAA,EAAa,MAAM,CAAA,wBAAA,CAAA,EAA4B;AAAA,MACnG,SAAA;AAAA,MACA,MAAA;AAAA,MACA,MAAA;AAAA,MACA,KAAA,EAAO;AAAA,QACL,IAAA;AAAA,QACA;AAAA;AACF,KACD,CAAA;AAAA,EACH;AAAA;AAEF;;;;"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @package @bitrix24/b24jssdk
|
|
3
|
+
* @version 2.0.0
|
|
4
|
+
* @copyright (c) 2026 Bitrix24
|
|
5
|
+
* @license MIT
|
|
6
|
+
* @see https://github.com/bitrix24/b24jssdk
|
|
7
|
+
* @see https://bitrix24.github.io/b24jssdk/
|
|
8
|
+
*/
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const loggerFactory = require('../../../logger/logger-factory.cjs');
|
|
12
|
+
|
|
13
|
+
var __defProp = Object.defineProperty;
|
|
14
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
15
|
+
class OperatingLimiter {
|
|
16
|
+
static {
|
|
17
|
+
__name(this, "OperatingLimiter");
|
|
18
|
+
}
|
|
19
|
+
#config;
|
|
20
|
+
#methodStats = /* @__PURE__ */ new Map();
|
|
21
|
+
#stats = {
|
|
22
|
+
/** Heavy requests */
|
|
23
|
+
heavyRequestCount: 0
|
|
24
|
+
};
|
|
25
|
+
_logger;
|
|
26
|
+
getTitle() {
|
|
27
|
+
return "operatingLimiter";
|
|
28
|
+
}
|
|
29
|
+
constructor(config) {
|
|
30
|
+
this._logger = loggerFactory.LoggerFactory.createNullLogger();
|
|
31
|
+
this.#config = config;
|
|
32
|
+
}
|
|
33
|
+
// region Logger ////
|
|
34
|
+
setLogger(logger) {
|
|
35
|
+
this._logger = logger;
|
|
36
|
+
}
|
|
37
|
+
getLogger() {
|
|
38
|
+
return this._logger;
|
|
39
|
+
}
|
|
40
|
+
// endregion ////
|
|
41
|
+
get limitMs() {
|
|
42
|
+
return this.#config.limitMs;
|
|
43
|
+
}
|
|
44
|
+
getMethodStat(method) {
|
|
45
|
+
const stats = this.#methodStats.get(method);
|
|
46
|
+
if (!stats) {
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
49
|
+
return stats;
|
|
50
|
+
}
|
|
51
|
+
async canProceed(requestId, method, params) {
|
|
52
|
+
const timeToFree = await this.getTimeToFree(requestId, method, params);
|
|
53
|
+
return timeToFree === 0;
|
|
54
|
+
}
|
|
55
|
+
async waitIfNeeded(requestId, method, params) {
|
|
56
|
+
return this.getTimeToFree(requestId, method, params);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Returns the time until the method's operating limit is released (in ms)
|
|
60
|
+
* The analysis is based on the previous function call.
|
|
61
|
+
* It's important to understand that we're talking about locks of up to 10 minutes.
|
|
62
|
+
* This is a fairly strict lock based on the limit:
|
|
63
|
+
* - not reached - no lock
|
|
64
|
+
* - reached - lock until the unlock time + 1 second
|
|
65
|
+
*/
|
|
66
|
+
async getTimeToFree(requestId, method, params, _error) {
|
|
67
|
+
this.#cleanupOldStats();
|
|
68
|
+
if (method === "batch") {
|
|
69
|
+
return this.#getTimeToFreeBatch(requestId, params);
|
|
70
|
+
}
|
|
71
|
+
const stats = this.#methodStats.get(method);
|
|
72
|
+
if (!stats) {
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
const limitWithBuffer = Math.max(1e3, this.#config.limitMs - 5e3);
|
|
76
|
+
if (stats.operating >= limitWithBuffer) {
|
|
77
|
+
const now = Date.now();
|
|
78
|
+
if (stats.operating_reset_at > now) {
|
|
79
|
+
return stats.operating_reset_at - now + 1e3;
|
|
80
|
+
}
|
|
81
|
+
return 5e3;
|
|
82
|
+
}
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* For `batch` commands, returns the maximum time until the method reaches the operating limit (in ms)
|
|
87
|
+
*/
|
|
88
|
+
async #getTimeToFreeBatch(requestId, params) {
|
|
89
|
+
let maxWait = 0;
|
|
90
|
+
if (!params?.cmd || !Array.isArray(params.cmd)) {
|
|
91
|
+
return maxWait;
|
|
92
|
+
}
|
|
93
|
+
const batchMethods = params.cmd.map((row) => row.split("?")[0]).filter(Boolean);
|
|
94
|
+
for (const methodName of batchMethods) {
|
|
95
|
+
const waitTime = await this.getTimeToFree(requestId, `batch::${methodName}`, {});
|
|
96
|
+
maxWait = Math.max(maxWait, waitTime);
|
|
97
|
+
}
|
|
98
|
+
return maxWait;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Updates operating time statistics for the method
|
|
102
|
+
*/
|
|
103
|
+
async updateStats(requestId, method, data) {
|
|
104
|
+
this.#cleanupOldStats();
|
|
105
|
+
const { operating, operating_reset_at } = data;
|
|
106
|
+
if (operating === void 0 || operating === null) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (!this.#methodStats.has(method)) {
|
|
110
|
+
this.#methodStats.set(method, {
|
|
111
|
+
operating: 0,
|
|
112
|
+
operating_reset_at: 0,
|
|
113
|
+
lastUpdated: Date.now()
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const stats = this.#methodStats.get(method);
|
|
117
|
+
stats.operating = operating * 1e3;
|
|
118
|
+
stats.operating_reset_at = operating_reset_at * 1e3;
|
|
119
|
+
stats.lastUpdated = Date.now();
|
|
120
|
+
const usagePercent = stats.operating / this.#config.limitMs * 100;
|
|
121
|
+
if (usagePercent > this.#config.heavyPercent) {
|
|
122
|
+
this.#stats.heavyRequestCount++;
|
|
123
|
+
this.#logStat(requestId, method, usagePercent, stats.operating);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Clearing outdated operating limit data
|
|
128
|
+
*/
|
|
129
|
+
#cleanupOldStats() {
|
|
130
|
+
const now = Date.now();
|
|
131
|
+
const maxAge = this.#config.windowMs + 1e4;
|
|
132
|
+
for (const [method, stats] of this.#methodStats.entries()) {
|
|
133
|
+
if (now - stats.lastUpdated > maxAge) {
|
|
134
|
+
this.#methodStats.delete(method);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async reset() {
|
|
139
|
+
this.#methodStats.clear();
|
|
140
|
+
this.#stats = {
|
|
141
|
+
heavyRequestCount: 0
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
getStats() {
|
|
145
|
+
const operatingStats = {};
|
|
146
|
+
for (const [method, stats] of this.#methodStats.entries()) {
|
|
147
|
+
operatingStats[method] = Number.parseFloat((stats.operating / 1e3).toFixed(2));
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
...this.#stats,
|
|
151
|
+
operatingStats
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
async setConfig(config) {
|
|
155
|
+
this.#config = config;
|
|
156
|
+
}
|
|
157
|
+
// region Log ////
|
|
158
|
+
#logStat(requestId, method, percent, operating) {
|
|
159
|
+
this.getLogger().debug(`${this.getTitle()} detected limit for method ${method}`, {
|
|
160
|
+
requestId,
|
|
161
|
+
method,
|
|
162
|
+
operating: {
|
|
163
|
+
percent: Number.parseFloat(percent.toFixed(2)),
|
|
164
|
+
current: Number.parseFloat((operating / 1e3).toFixed(0)),
|
|
165
|
+
max: Number.parseFloat((this.#config.limitMs / 1e3).toFixed(0))
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
// endregion ////
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
exports.OperatingLimiter = OperatingLimiter;
|
|
173
|
+
//# sourceMappingURL=operating-limiter.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operating-limiter.cjs","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":["LoggerFactory"],"mappings":"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"}
|