@wildix/xbees-conversations-utils 1.1.77 → 1.1.79

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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_OPTIONS = exports.SOFT_THROTTLE_DELAY_HIGH_MS = exports.SOFT_THROTTLE_DELAY_MEDIUM_MS = exports.SOFT_THROTTLE_DELAY_LOW_MS = exports.SOFT_THROTTLE_USAGE_HIGH = exports.SOFT_THROTTLE_USAGE_MEDIUM = exports.SOFT_THROTTLE_USAGE_LOW = exports.BUDGET_COOLDOWN_SLEEP_CHUNK_MS = exports.BUDGET_MINIMAL_DELAY_MAX_MS = exports.BUDGET_MINIMAL_DELAY_MIN_MS = exports.BUDGET_RELAXED_DELAY_MAX_MS = exports.BUDGET_RELAXED_DELAY_MIN_MS = exports.BUDGET_RELAXED_USAGE_THRESHOLD = exports.BUDGET_CLEAR_USAGE_THRESHOLD = exports.BUDGET_DELAY_MAX_MS = exports.BUDGET_DELAY_MIN_MS = exports.BUDGET_THRESHOLD = exports.STREAM_BUDGET_COOLDOWN_KEY = exports.STREAM_RATE_LIMIT_SOFT_COOLDOWN_KEY = exports.STREAM_RATE_LIMIT_OPTIONS_MARKER = exports.STREAM_BUDGET_COOLDOWN_KEY_PREFIX = exports.STREAM_RATE_LIMIT_COOLDOWN_KEY_PREFIX = exports.RETRY_AFTER_BUFFER_MS = exports.DEFAULT_JITTER_MS = exports.DEFAULT_RETRY_AFTER_MS = exports.DEFAULT_MAX_DELAY_MS = exports.STREAM_SYNC_METHOD_NAMES = exports.STREAM_SYNC_CHANNEL_RESULT_METHOD_NAMES = exports.STREAM_METHOD_NAMES = exports.STREAM_CHANNEL_RESULT_METHOD_NAMES = exports.CHANNEL_SYNC_PROXY_RESULT_METHOD_NAMES = exports.CHANNEL_SYNC_METHOD_NAMES = exports.CHANNEL_METHOD_NAMES = void 0;
3
+ exports.DEFAULT_OPTIONS = exports.SOFT_THROTTLE_DELAY_HIGH_MS = exports.SOFT_THROTTLE_DELAY_MEDIUM_MS = exports.SOFT_THROTTLE_DELAY_LOW_MS = exports.SOFT_THROTTLE_USAGE_HIGH = exports.SOFT_THROTTLE_USAGE_MEDIUM = exports.SOFT_THROTTLE_USAGE_LOW = exports.BUDGET_COOLDOWN_SLEEP_CHUNK_MS = exports.BUDGET_MINIMAL_DELAY_MAX_MS = exports.BUDGET_MINIMAL_DELAY_MIN_MS = exports.BUDGET_RELAXED_DELAY_MAX_MS = exports.BUDGET_RELAXED_DELAY_MIN_MS = exports.BUDGET_RELAXED_USAGE_THRESHOLD = exports.BUDGET_CLEAR_USAGE_THRESHOLD = exports.BUDGET_DELAY_MAX_MS = exports.BUDGET_DELAY_MIN_MS = exports.BUDGET_THRESHOLD = exports.STREAM_BUDGET_COOLDOWN_KEY = exports.STREAM_RATE_LIMIT_METADATA_KEY_SUFFIX = exports.STREAM_RATE_LIMIT_SOFT_COOLDOWN_KEY = exports.STREAM_RATE_LIMIT_OPTIONS_MARKER = exports.STREAM_BUDGET_COOLDOWN_KEY_PREFIX = exports.STREAM_RATE_LIMIT_COOLDOWN_KEY_PREFIX = exports.RETRY_AFTER_BUFFER_MS = exports.DEFAULT_JITTER_MS = exports.DEFAULT_RETRY_AFTER_MS = exports.DEFAULT_MAX_DELAY_MS = exports.STREAM_SYNC_METHOD_NAMES = exports.STREAM_SYNC_CHANNEL_RESULT_METHOD_NAMES = exports.STREAM_METHOD_NAMES = exports.STREAM_CHANNEL_RESULT_METHOD_NAMES = exports.CHANNEL_SYNC_PROXY_RESULT_METHOD_NAMES = exports.CHANNEL_SYNC_METHOD_NAMES = exports.CHANNEL_METHOD_NAMES = void 0;
4
4
  var generatedMethodNames_1 = require("./generatedMethodNames");
5
5
  Object.defineProperty(exports, "CHANNEL_METHOD_NAMES", { enumerable: true, get: function () { return generatedMethodNames_1.CHANNEL_METHOD_NAMES; } });
6
6
  Object.defineProperty(exports, "CHANNEL_SYNC_METHOD_NAMES", { enumerable: true, get: function () { return generatedMethodNames_1.CHANNEL_SYNC_METHOD_NAMES; } });
@@ -17,6 +17,7 @@ exports.STREAM_RATE_LIMIT_COOLDOWN_KEY_PREFIX = 'stream-rate-limit-cooldown:';
17
17
  exports.STREAM_BUDGET_COOLDOWN_KEY_PREFIX = 'stream-budget-cooldown:';
18
18
  exports.STREAM_RATE_LIMIT_OPTIONS_MARKER = '__xbsRateLimitOptions';
19
19
  exports.STREAM_RATE_LIMIT_SOFT_COOLDOWN_KEY = 'stream-rate-limit-soft-global';
20
+ exports.STREAM_RATE_LIMIT_METADATA_KEY_SUFFIX = ':meta';
20
21
  exports.STREAM_BUDGET_COOLDOWN_KEY = 'stream-budget-global';
21
22
  exports.BUDGET_THRESHOLD = 0.8;
22
23
  exports.BUDGET_DELAY_MIN_MS = 30000;
@@ -72,6 +72,55 @@ class RedisCooldown {
72
72
  });
73
73
  }
74
74
  }
75
+ static async getValue(cooldownKey, context, options) {
76
+ const { redis, logger } = context;
77
+ try {
78
+ const value = await redis.get(RedisCooldown.resolveRedisKey(cooldownKey, options));
79
+ if (typeof value === 'string' && value.length > 0) {
80
+ return value;
81
+ }
82
+ }
83
+ catch (error) {
84
+ logger.warn('Failed to read stream rate-limit metadata from Redis', {
85
+ cooldownKey,
86
+ error,
87
+ });
88
+ }
89
+ }
90
+ static async setValueWithRemainingMs(cooldownKey, value, cooldownMs, context, options) {
91
+ if (value.length === 0 || cooldownMs <= 0) {
92
+ return;
93
+ }
94
+ const { redis, logger } = context;
95
+ try {
96
+ await redis.eval(`
97
+ local key = KEYS[1]
98
+ local value = ARGV[1]
99
+ local new_ttl = tonumber(ARGV[2])
100
+ local current_ttl = redis.call('PTTL', key)
101
+
102
+ if current_ttl == -2 then
103
+ redis.call('SET', key, value, 'PX', new_ttl)
104
+ return 1
105
+ end
106
+
107
+ if current_ttl == -1 or current_ttl < new_ttl then
108
+ redis.call('SET', key, value, 'PX', new_ttl)
109
+ return 2
110
+ end
111
+
112
+ redis.call('SET', key, value, 'KEEPTTL')
113
+ return 0
114
+ `, 1, RedisCooldown.resolveRedisKey(cooldownKey, options), value, cooldownMs.toString());
115
+ }
116
+ catch (error) {
117
+ logger.warn('Failed to write stream rate-limit metadata to Redis', {
118
+ cooldownKey,
119
+ cooldownMs,
120
+ error,
121
+ });
122
+ }
123
+ }
75
124
  static async clear(cooldownKey, context, options) {
76
125
  const { redis, logger } = context;
77
126
  try {
@@ -4,6 +4,7 @@ exports.executeWithRateLimitHandling = void 0;
4
4
  const promises_1 = require("node:timers/promises");
5
5
  const constants_1 = require("../constants");
6
6
  const createRateLimitExceededException_1 = require("./createRateLimitExceededException");
7
+ const rateLimitSnapshot_1 = require("./rateLimitSnapshot");
7
8
  const processStreamRateLimitException_1 = require("./processStreamRateLimitException");
8
9
  const RedisCooldown_1 = require("./RedisCooldown");
9
10
  function calculateRateLimitDelayMs(error, maxDelayMs) {
@@ -20,6 +21,34 @@ function calculateRateLimitDelayMs(error, maxDelayMs) {
20
21
  }
21
22
  return Math.min(maxDelayMs, constants_1.DEFAULT_MAX_DELAY_MS);
22
23
  }
24
+ function getRateLimitMetadataKey(operation) {
25
+ return `${operation}${constants_1.STREAM_RATE_LIMIT_METADATA_KEY_SUFFIX}`;
26
+ }
27
+ function toCooldownRateLimit(snapshot, cooldownMs) {
28
+ return {
29
+ limit: snapshot.limit,
30
+ remaining: snapshot.remaining,
31
+ reset: Math.max(snapshot.reset, Date.now() + cooldownMs),
32
+ };
33
+ }
34
+ function toRateLimitSnapshot(error) {
35
+ const limit = Number(error.rateLimit);
36
+ const remaining = error.rateLimitRemaining;
37
+ const resetMs = error.rateLimitReset;
38
+ if (!Number.isFinite(limit) ||
39
+ typeof remaining !== 'number' ||
40
+ !Number.isFinite(remaining) ||
41
+ typeof resetMs !== 'number' ||
42
+ !Number.isFinite(resetMs) ||
43
+ resetMs <= 0) {
44
+ return;
45
+ }
46
+ return {
47
+ limit,
48
+ remaining,
49
+ reset: Date.now() + resetMs,
50
+ };
51
+ }
23
52
  async function executeWithRateLimitHandling(execute, operation, context, options) {
24
53
  const { logger, redis } = context;
25
54
  const { enableCooldown, maxAttempts, maxDelayMs, maxRetryableDelayMs } = options;
@@ -27,11 +56,17 @@ async function executeWithRateLimitHandling(execute, operation, context, options
27
56
  if (enableCooldown) {
28
57
  const cooldownMs = await RedisCooldown_1.RedisCooldown.getRemainingMs(operation, { redis, logger });
29
58
  if (cooldownMs > 0) {
59
+ const rateLimitSnapshot = (0, rateLimitSnapshot_1.parseRateLimitSnapshot)(await RedisCooldown_1.RedisCooldown.getValue(getRateLimitMetadataKey(operation), { redis, logger }));
30
60
  logger.warn('Skipping stream request due to active rate-limit cooldown', {
31
61
  operation,
32
62
  cooldown: cooldownMs,
63
+ rateLimitSnapshot,
64
+ });
65
+ throw (0, createRateLimitExceededException_1.createRateLimitExceededException)({
66
+ operation,
67
+ retryAfterMs: cooldownMs,
68
+ rateLimit: rateLimitSnapshot ? toCooldownRateLimit(rateLimitSnapshot, cooldownMs) : undefined,
33
69
  });
34
- throw (0, createRateLimitExceededException_1.createRateLimitExceededException)({ operation, retryAfterMs: cooldownMs });
35
70
  }
36
71
  const softCooldownMs = await RedisCooldown_1.RedisCooldown.getRemainingMs(constants_1.STREAM_RATE_LIMIT_SOFT_COOLDOWN_KEY, { redis, logger }, { keyPrefix: constants_1.STREAM_RATE_LIMIT_COOLDOWN_KEY_PREFIX });
37
72
  if (softCooldownMs > 0) {
@@ -70,7 +105,11 @@ async function executeWithRateLimitHandling(execute, operation, context, options
70
105
  }
71
106
  const retryAfterMs = calculateRateLimitDelayMs(rateLimitError, maxDelayMs);
72
107
  if (enableCooldown) {
108
+ const rateLimitSnapshot = toRateLimitSnapshot(rateLimitError);
73
109
  await RedisCooldown_1.RedisCooldown.setRemainingMs(operation, retryAfterMs, { redis, logger });
110
+ if (rateLimitSnapshot) {
111
+ await RedisCooldown_1.RedisCooldown.setValueWithRemainingMs(getRateLimitMetadataKey(operation), (0, rateLimitSnapshot_1.serializeRateLimitSnapshot)(rateLimitSnapshot), retryAfterMs, { redis, logger });
112
+ }
74
113
  }
75
114
  if (attempt < maxAttempts && retryAfterMs <= maxRetryableDelayMs) {
76
115
  logger.warn('Retrying stream request after rate limit', {
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseRateLimitSnapshot = exports.serializeRateLimitSnapshot = void 0;
4
+ const RATE_LIMIT_SNAPSHOT_PARTS_COUNT = 3;
5
+ function serializeRateLimitSnapshot(snapshot) {
6
+ return `${snapshot.limit},${snapshot.remaining},${snapshot.reset}`;
7
+ }
8
+ exports.serializeRateLimitSnapshot = serializeRateLimitSnapshot;
9
+ function parseRateLimitSnapshot(snapshot) {
10
+ if (typeof snapshot !== 'string' || snapshot.length === 0) {
11
+ return;
12
+ }
13
+ const parts = snapshot.split(',');
14
+ if (parts.length !== RATE_LIMIT_SNAPSHOT_PARTS_COUNT) {
15
+ return;
16
+ }
17
+ const [limitRaw, remainingRaw, resetRaw] = parts;
18
+ const limit = Number(limitRaw);
19
+ const remaining = Number(remainingRaw);
20
+ const reset = Number(resetRaw);
21
+ if (!Number.isFinite(limit) ||
22
+ !Number.isFinite(remaining) ||
23
+ !Number.isFinite(reset) ||
24
+ limit < 0 ||
25
+ remaining < 0 ||
26
+ reset <= 0) {
27
+ return;
28
+ }
29
+ return { limit, remaining, reset };
30
+ }
31
+ exports.parseRateLimitSnapshot = parseRateLimitSnapshot;
@@ -7,6 +7,7 @@ export const STREAM_RATE_LIMIT_COOLDOWN_KEY_PREFIX = 'stream-rate-limit-cooldown
7
7
  export const STREAM_BUDGET_COOLDOWN_KEY_PREFIX = 'stream-budget-cooldown:';
8
8
  export const STREAM_RATE_LIMIT_OPTIONS_MARKER = '__xbsRateLimitOptions';
9
9
  export const STREAM_RATE_LIMIT_SOFT_COOLDOWN_KEY = 'stream-rate-limit-soft-global';
10
+ export const STREAM_RATE_LIMIT_METADATA_KEY_SUFFIX = ':meta';
10
11
  export const STREAM_BUDGET_COOLDOWN_KEY = 'stream-budget-global';
11
12
  export const BUDGET_THRESHOLD = 0.8;
12
13
  export const BUDGET_DELAY_MIN_MS = 30000;
@@ -69,6 +69,55 @@ export class RedisCooldown {
69
69
  });
70
70
  }
71
71
  }
72
+ static async getValue(cooldownKey, context, options) {
73
+ const { redis, logger } = context;
74
+ try {
75
+ const value = await redis.get(RedisCooldown.resolveRedisKey(cooldownKey, options));
76
+ if (typeof value === 'string' && value.length > 0) {
77
+ return value;
78
+ }
79
+ }
80
+ catch (error) {
81
+ logger.warn('Failed to read stream rate-limit metadata from Redis', {
82
+ cooldownKey,
83
+ error,
84
+ });
85
+ }
86
+ }
87
+ static async setValueWithRemainingMs(cooldownKey, value, cooldownMs, context, options) {
88
+ if (value.length === 0 || cooldownMs <= 0) {
89
+ return;
90
+ }
91
+ const { redis, logger } = context;
92
+ try {
93
+ await redis.eval(`
94
+ local key = KEYS[1]
95
+ local value = ARGV[1]
96
+ local new_ttl = tonumber(ARGV[2])
97
+ local current_ttl = redis.call('PTTL', key)
98
+
99
+ if current_ttl == -2 then
100
+ redis.call('SET', key, value, 'PX', new_ttl)
101
+ return 1
102
+ end
103
+
104
+ if current_ttl == -1 or current_ttl < new_ttl then
105
+ redis.call('SET', key, value, 'PX', new_ttl)
106
+ return 2
107
+ end
108
+
109
+ redis.call('SET', key, value, 'KEEPTTL')
110
+ return 0
111
+ `, 1, RedisCooldown.resolveRedisKey(cooldownKey, options), value, cooldownMs.toString());
112
+ }
113
+ catch (error) {
114
+ logger.warn('Failed to write stream rate-limit metadata to Redis', {
115
+ cooldownKey,
116
+ cooldownMs,
117
+ error,
118
+ });
119
+ }
120
+ }
72
121
  static async clear(cooldownKey, context, options) {
73
122
  const { redis, logger } = context;
74
123
  try {
@@ -1,6 +1,7 @@
1
1
  import { setTimeout as sleep } from 'node:timers/promises';
2
- import { BUDGET_COOLDOWN_SLEEP_CHUNK_MS, BUDGET_DELAY_MAX_MS, DEFAULT_JITTER_MS, DEFAULT_MAX_DELAY_MS, DEFAULT_RETRY_AFTER_MS, RETRY_AFTER_BUFFER_MS, STREAM_BUDGET_COOLDOWN_KEY, STREAM_BUDGET_COOLDOWN_KEY_PREFIX, STREAM_RATE_LIMIT_COOLDOWN_KEY_PREFIX, STREAM_RATE_LIMIT_SOFT_COOLDOWN_KEY, } from '../constants';
2
+ import { BUDGET_COOLDOWN_SLEEP_CHUNK_MS, BUDGET_DELAY_MAX_MS, DEFAULT_JITTER_MS, DEFAULT_MAX_DELAY_MS, DEFAULT_RETRY_AFTER_MS, RETRY_AFTER_BUFFER_MS, STREAM_BUDGET_COOLDOWN_KEY, STREAM_BUDGET_COOLDOWN_KEY_PREFIX, STREAM_RATE_LIMIT_COOLDOWN_KEY_PREFIX, STREAM_RATE_LIMIT_METADATA_KEY_SUFFIX, STREAM_RATE_LIMIT_SOFT_COOLDOWN_KEY, } from '../constants';
3
3
  import { createRateLimitExceededException } from './createRateLimitExceededException';
4
+ import { parseRateLimitSnapshot, serializeRateLimitSnapshot } from './rateLimitSnapshot';
4
5
  import { processStreamRateLimitException } from './processStreamRateLimitException';
5
6
  import { RedisCooldown } from './RedisCooldown';
6
7
  function calculateRateLimitDelayMs(error, maxDelayMs) {
@@ -17,6 +18,34 @@ function calculateRateLimitDelayMs(error, maxDelayMs) {
17
18
  }
18
19
  return Math.min(maxDelayMs, DEFAULT_MAX_DELAY_MS);
19
20
  }
21
+ function getRateLimitMetadataKey(operation) {
22
+ return `${operation}${STREAM_RATE_LIMIT_METADATA_KEY_SUFFIX}`;
23
+ }
24
+ function toCooldownRateLimit(snapshot, cooldownMs) {
25
+ return {
26
+ limit: snapshot.limit,
27
+ remaining: snapshot.remaining,
28
+ reset: Math.max(snapshot.reset, Date.now() + cooldownMs),
29
+ };
30
+ }
31
+ function toRateLimitSnapshot(error) {
32
+ const limit = Number(error.rateLimit);
33
+ const remaining = error.rateLimitRemaining;
34
+ const resetMs = error.rateLimitReset;
35
+ if (!Number.isFinite(limit) ||
36
+ typeof remaining !== 'number' ||
37
+ !Number.isFinite(remaining) ||
38
+ typeof resetMs !== 'number' ||
39
+ !Number.isFinite(resetMs) ||
40
+ resetMs <= 0) {
41
+ return;
42
+ }
43
+ return {
44
+ limit,
45
+ remaining,
46
+ reset: Date.now() + resetMs,
47
+ };
48
+ }
20
49
  export async function executeWithRateLimitHandling(execute, operation, context, options) {
21
50
  const { logger, redis } = context;
22
51
  const { enableCooldown, maxAttempts, maxDelayMs, maxRetryableDelayMs } = options;
@@ -24,11 +53,17 @@ export async function executeWithRateLimitHandling(execute, operation, context,
24
53
  if (enableCooldown) {
25
54
  const cooldownMs = await RedisCooldown.getRemainingMs(operation, { redis, logger });
26
55
  if (cooldownMs > 0) {
56
+ const rateLimitSnapshot = parseRateLimitSnapshot(await RedisCooldown.getValue(getRateLimitMetadataKey(operation), { redis, logger }));
27
57
  logger.warn('Skipping stream request due to active rate-limit cooldown', {
28
58
  operation,
29
59
  cooldown: cooldownMs,
60
+ rateLimitSnapshot,
61
+ });
62
+ throw createRateLimitExceededException({
63
+ operation,
64
+ retryAfterMs: cooldownMs,
65
+ rateLimit: rateLimitSnapshot ? toCooldownRateLimit(rateLimitSnapshot, cooldownMs) : undefined,
30
66
  });
31
- throw createRateLimitExceededException({ operation, retryAfterMs: cooldownMs });
32
67
  }
33
68
  const softCooldownMs = await RedisCooldown.getRemainingMs(STREAM_RATE_LIMIT_SOFT_COOLDOWN_KEY, { redis, logger }, { keyPrefix: STREAM_RATE_LIMIT_COOLDOWN_KEY_PREFIX });
34
69
  if (softCooldownMs > 0) {
@@ -67,7 +102,11 @@ export async function executeWithRateLimitHandling(execute, operation, context,
67
102
  }
68
103
  const retryAfterMs = calculateRateLimitDelayMs(rateLimitError, maxDelayMs);
69
104
  if (enableCooldown) {
105
+ const rateLimitSnapshot = toRateLimitSnapshot(rateLimitError);
70
106
  await RedisCooldown.setRemainingMs(operation, retryAfterMs, { redis, logger });
107
+ if (rateLimitSnapshot) {
108
+ await RedisCooldown.setValueWithRemainingMs(getRateLimitMetadataKey(operation), serializeRateLimitSnapshot(rateLimitSnapshot), retryAfterMs, { redis, logger });
109
+ }
71
110
  }
72
111
  if (attempt < maxAttempts && retryAfterMs <= maxRetryableDelayMs) {
73
112
  logger.warn('Retrying stream request after rate limit', {
@@ -0,0 +1,26 @@
1
+ const RATE_LIMIT_SNAPSHOT_PARTS_COUNT = 3;
2
+ export function serializeRateLimitSnapshot(snapshot) {
3
+ return `${snapshot.limit},${snapshot.remaining},${snapshot.reset}`;
4
+ }
5
+ export function parseRateLimitSnapshot(snapshot) {
6
+ if (typeof snapshot !== 'string' || snapshot.length === 0) {
7
+ return;
8
+ }
9
+ const parts = snapshot.split(',');
10
+ if (parts.length !== RATE_LIMIT_SNAPSHOT_PARTS_COUNT) {
11
+ return;
12
+ }
13
+ const [limitRaw, remainingRaw, resetRaw] = parts;
14
+ const limit = Number(limitRaw);
15
+ const remaining = Number(remainingRaw);
16
+ const reset = Number(resetRaw);
17
+ if (!Number.isFinite(limit) ||
18
+ !Number.isFinite(remaining) ||
19
+ !Number.isFinite(reset) ||
20
+ limit < 0 ||
21
+ remaining < 0 ||
22
+ reset <= 0) {
23
+ return;
24
+ }
25
+ return { limit, remaining, reset };
26
+ }
@@ -8,6 +8,7 @@ export declare const STREAM_RATE_LIMIT_COOLDOWN_KEY_PREFIX = "stream-rate-limit-
8
8
  export declare const STREAM_BUDGET_COOLDOWN_KEY_PREFIX = "stream-budget-cooldown:";
9
9
  export declare const STREAM_RATE_LIMIT_OPTIONS_MARKER = "__xbsRateLimitOptions";
10
10
  export declare const STREAM_RATE_LIMIT_SOFT_COOLDOWN_KEY = "stream-rate-limit-soft-global";
11
+ export declare const STREAM_RATE_LIMIT_METADATA_KEY_SUFFIX = ":meta";
11
12
  export declare const STREAM_BUDGET_COOLDOWN_KEY = "stream-budget-global";
12
13
  export declare const BUDGET_THRESHOLD = 0.8;
13
14
  export declare const BUDGET_DELAY_MIN_MS = 30000;
@@ -4,5 +4,7 @@ export declare class RedisCooldown {
4
4
  static getRemainingMs(cooldownKey: string, context: RedisContext & LoggerContext, options?: RedisCooldownOptions): Promise<number>;
5
5
  static setRemainingMs(cooldownKey: string, cooldownMs: number, context: RedisContext & LoggerContext, options?: RedisCooldownOptions): Promise<void>;
6
6
  static setRemainingMsExact(cooldownKey: string, cooldownMs: number, context: RedisContext & LoggerContext, options?: RedisCooldownOptions): Promise<void>;
7
+ static getValue(cooldownKey: string, context: RedisContext & LoggerContext, options?: RedisCooldownOptions): Promise<string | undefined>;
8
+ static setValueWithRemainingMs(cooldownKey: string, value: string, cooldownMs: number, context: RedisContext & LoggerContext, options?: RedisCooldownOptions): Promise<void>;
7
9
  static clear(cooldownKey: string, context: RedisContext & LoggerContext, options?: RedisCooldownOptions): Promise<void>;
8
10
  }
@@ -0,0 +1,3 @@
1
+ import { StreamRateLimitSnapshot } from '../types';
2
+ export declare function serializeRateLimitSnapshot(snapshot: StreamRateLimitSnapshot): string;
3
+ export declare function parseRateLimitSnapshot(snapshot: string | null | undefined): StreamRateLimitSnapshot | undefined;
@@ -36,6 +36,11 @@ export type StreamBudgetHeaders = {
36
36
  remainingMs?: number;
37
37
  usedMs?: number;
38
38
  };
39
+ export type StreamRateLimitSnapshot = {
40
+ limit: number;
41
+ remaining: number;
42
+ reset: number;
43
+ };
39
44
  /** Axios response shape used by budget interceptor. */
40
45
  export type StreamBudgetInterceptorResponse = {
41
46
  headers?: StreamHeaders;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wildix/xbees-conversations-utils",
3
- "version": "1.1.77",
3
+ "version": "1.1.79",
4
4
  "description": "",
5
5
  "main": "./dist-cjs/index.js",
6
6
  "module": "./dist-es/index.js",