@wildix/xbees-conversations-utils 1.1.76 → 1.1.77

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist-cjs/rateLimits/constants.js +17 -62
  2. package/dist-cjs/rateLimits/createRateLimitedStreamProxy.js +20 -7
  3. package/dist-cjs/rateLimits/generatedMethodNames.js +320 -0
  4. package/dist-cjs/rateLimits/helpers/RedisCooldown.js +16 -0
  5. package/dist-cjs/rateLimits/helpers/createRateLimitExceededException.js +5 -7
  6. package/dist-cjs/rateLimits/helpers/executeWithRateLimitHandling.js +21 -35
  7. package/dist-cjs/rateLimits/helpers/headerUtils.js +40 -0
  8. package/dist-cjs/rateLimits/helpers/isStreamChannelLike.js +9 -1
  9. package/dist-cjs/rateLimits/helpers/processStreamBudgetHeaders.js +41 -35
  10. package/dist-cjs/rateLimits/helpers/processStreamRateLimitException.js +7 -18
  11. package/dist-cjs/rateLimits/helpers/processStreamRateLimitHeaders.js +4 -28
  12. package/dist-cjs/rateLimits/helpers/registerStreamInterceptors.js +48 -0
  13. package/dist-es/rateLimits/constants.js +9 -61
  14. package/dist-es/rateLimits/createRateLimitedStreamProxy.js +21 -8
  15. package/dist-es/rateLimits/generatedMethodNames.js +317 -0
  16. package/dist-es/rateLimits/helpers/RedisCooldown.js +16 -0
  17. package/dist-es/rateLimits/helpers/createRateLimitExceededException.js +5 -7
  18. package/dist-es/rateLimits/helpers/executeWithRateLimitHandling.js +22 -36
  19. package/dist-es/rateLimits/helpers/headerUtils.js +34 -0
  20. package/dist-es/rateLimits/helpers/isStreamChannelLike.js +9 -1
  21. package/dist-es/rateLimits/helpers/processStreamBudgetHeaders.js +42 -36
  22. package/dist-es/rateLimits/helpers/processStreamRateLimitException.js +5 -16
  23. package/dist-es/rateLimits/helpers/processStreamRateLimitHeaders.js +4 -28
  24. package/dist-es/rateLimits/helpers/registerStreamInterceptors.js +44 -0
  25. package/dist-types/rateLimits/constants.d.ts +8 -4
  26. package/dist-types/rateLimits/generatedMethodNames.d.ts +11 -0
  27. package/dist-types/rateLimits/helpers/RedisCooldown.d.ts +1 -0
  28. package/dist-types/rateLimits/helpers/headerUtils.d.ts +4 -0
  29. package/dist-types/rateLimits/helpers/processStreamBudgetHeaders.d.ts +2 -1
  30. package/dist-types/rateLimits/helpers/registerStreamInterceptors.d.ts +2 -0
  31. package/package.json +2 -1
@@ -1,6 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_OPTIONS = exports.CHANNEL_SYNC_PROXY_RESULT_METHOD_NAMES = exports.CHANNEL_SYNC_METHOD_NAMES = exports.STREAM_SYNC_METHOD_NAMES = exports.STREAM_SYNC_CHANNEL_RESULT_METHOD_NAMES = 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_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 = 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_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
+ var generatedMethodNames_1 = require("./generatedMethodNames");
5
+ Object.defineProperty(exports, "CHANNEL_METHOD_NAMES", { enumerable: true, get: function () { return generatedMethodNames_1.CHANNEL_METHOD_NAMES; } });
6
+ Object.defineProperty(exports, "CHANNEL_SYNC_METHOD_NAMES", { enumerable: true, get: function () { return generatedMethodNames_1.CHANNEL_SYNC_METHOD_NAMES; } });
7
+ Object.defineProperty(exports, "CHANNEL_SYNC_PROXY_RESULT_METHOD_NAMES", { enumerable: true, get: function () { return generatedMethodNames_1.CHANNEL_SYNC_PROXY_RESULT_METHOD_NAMES; } });
8
+ Object.defineProperty(exports, "STREAM_CHANNEL_RESULT_METHOD_NAMES", { enumerable: true, get: function () { return generatedMethodNames_1.STREAM_CHANNEL_RESULT_METHOD_NAMES; } });
9
+ Object.defineProperty(exports, "STREAM_METHOD_NAMES", { enumerable: true, get: function () { return generatedMethodNames_1.STREAM_METHOD_NAMES; } });
10
+ Object.defineProperty(exports, "STREAM_SYNC_CHANNEL_RESULT_METHOD_NAMES", { enumerable: true, get: function () { return generatedMethodNames_1.STREAM_SYNC_CHANNEL_RESULT_METHOD_NAMES; } });
11
+ Object.defineProperty(exports, "STREAM_SYNC_METHOD_NAMES", { enumerable: true, get: function () { return generatedMethodNames_1.STREAM_SYNC_METHOD_NAMES; } });
4
12
  exports.DEFAULT_MAX_DELAY_MS = 5000;
5
13
  exports.DEFAULT_RETRY_AFTER_MS = 10000;
6
14
  exports.DEFAULT_JITTER_MS = 150;
@@ -13,75 +21,22 @@ exports.STREAM_BUDGET_COOLDOWN_KEY = 'stream-budget-global';
13
21
  exports.BUDGET_THRESHOLD = 0.8;
14
22
  exports.BUDGET_DELAY_MIN_MS = 30000;
15
23
  exports.BUDGET_DELAY_MAX_MS = 60000;
24
+ exports.BUDGET_CLEAR_USAGE_THRESHOLD = 0.6;
25
+ exports.BUDGET_RELAXED_USAGE_THRESHOLD = 0.7;
26
+ exports.BUDGET_RELAXED_DELAY_MIN_MS = 5000;
27
+ exports.BUDGET_RELAXED_DELAY_MAX_MS = 10000;
28
+ exports.BUDGET_MINIMAL_DELAY_MIN_MS = 1000;
29
+ exports.BUDGET_MINIMAL_DELAY_MAX_MS = 2000;
30
+ exports.BUDGET_COOLDOWN_SLEEP_CHUNK_MS = 3000;
16
31
  exports.SOFT_THROTTLE_USAGE_LOW = 0.7;
17
32
  exports.SOFT_THROTTLE_USAGE_MEDIUM = 0.85;
18
33
  exports.SOFT_THROTTLE_USAGE_HIGH = 0.95;
19
34
  exports.SOFT_THROTTLE_DELAY_LOW_MS = 500;
20
35
  exports.SOFT_THROTTLE_DELAY_MEDIUM_MS = 1500;
21
36
  exports.SOFT_THROTTLE_DELAY_HIGH_MS = 3000;
22
- exports.STREAM_SYNC_CHANNEL_RESULT_METHOD_NAMES = [
23
- 'channel',
24
- 'getChannelById',
25
- 'getChannelByMembers',
26
- 'hydrateActiveChannels',
27
- ];
28
- exports.STREAM_SYNC_METHOD_NAMES = [
29
- '_addChannelConfig',
30
- '_buildWSPayload',
31
- '_callClientListeners',
32
- '_deleteUserMessageReference',
33
- '_enrichAxiosOptions',
34
- '_getConnectionID',
35
- '_getToken',
36
- '_handleClientEvent',
37
- '_handleUserEvent',
38
- '_hasConnectionID',
39
- '_isUsingServerAuth',
40
- '_logApiError',
41
- '_logApiRequest',
42
- '_logApiResponse',
43
- '_muteStatus',
44
- '_normalizeDate',
45
- '_normalizeExpiration',
46
- '_sayHi',
47
- '_setUser',
48
- '_startCleaning',
49
- '_updateMemberWatcherReferences',
50
- '_updateUserMessageReferences',
51
- '_updateUserReferences',
52
- '_validateAndGetMessageId',
53
- 'createAbortControllerForNextRequest',
54
- 'createToken',
55
- 'devToken',
56
- 'dispatchEvent',
57
- 'errorFromResponse',
58
- 'getAuthType',
59
- 'getUserAgent',
60
- 'handleEvent',
61
- 'handleResponse',
62
- 'off',
63
- 'on',
64
- 'setBaseURL',
65
- 'setLocalDevice',
66
- 'setUserAgent',
67
- 'userMuteStatus',
68
- 'verifyWebhook',
69
- ];
70
- exports.CHANNEL_SYNC_METHOD_NAMES = [
71
- '_channelURL',
72
- 'countUnread',
73
- 'countUnreadMentions',
74
- 'getConfig',
75
- 'lastMessage',
76
- 'lastRead',
77
- 'muteStatus',
78
- 'off',
79
- 'on',
80
- ];
81
- exports.CHANNEL_SYNC_PROXY_RESULT_METHOD_NAMES = ['getClient'];
82
37
  exports.DEFAULT_OPTIONS = {
83
38
  maxAttempts: 3,
84
39
  enableCooldown: true,
85
- maxDelayMs: exports.DEFAULT_MAX_DELAY_MS,
40
+ maxDelayMs: 5000,
86
41
  maxRetryableDelayMs: 10000,
87
42
  };
@@ -4,13 +4,26 @@ exports.createRateLimitedStreamProxy = void 0;
4
4
  const constants_1 = require("./constants");
5
5
  const executeWithRateLimitHandling_1 = require("./helpers/executeWithRateLimitHandling");
6
6
  const isStreamChannelLike_1 = require("./helpers/isStreamChannelLike");
7
- const registerStreamBudgetInterceptors_1 = require("./helpers/registerStreamBudgetInterceptors");
7
+ const registerStreamInterceptors_1 = require("./helpers/registerStreamInterceptors");
8
8
  const splitCallArgsAndOptions_1 = require("./helpers/splitCallArgsAndOptions");
9
9
  const STREAM_SYNC_METHODS = new Set(constants_1.STREAM_SYNC_METHOD_NAMES);
10
+ const STREAM_CHANNEL_RESULT_METHODS = new Set(constants_1.STREAM_CHANNEL_RESULT_METHOD_NAMES);
10
11
  const STREAM_SYNC_CHANNEL_RESULT_METHODS = new Set(constants_1.STREAM_SYNC_CHANNEL_RESULT_METHOD_NAMES);
11
12
  const CHANNEL_SYNC_METHODS = new Set(constants_1.CHANNEL_SYNC_METHOD_NAMES);
12
13
  const CHANNEL_SYNC_PROXY_RESULT_METHODS = new Set(constants_1.CHANNEL_SYNC_PROXY_RESULT_METHOD_NAMES);
13
- function normalizeStreamCallResult(result, dependencies) {
14
+ function wrapKnownChannelResult(result, dependencies) {
15
+ if (Array.isArray(result)) {
16
+ return result.map((item) => wrapKnownChannelResult(item, dependencies));
17
+ }
18
+ if (typeof result !== 'object' || result === null) {
19
+ return result;
20
+ }
21
+ return wrapTarget(result, dependencies);
22
+ }
23
+ function normalizeStreamCallResult(result, dependencies, wrapAsChannelResult = false) {
24
+ if (wrapAsChannelResult) {
25
+ return wrapKnownChannelResult(result, dependencies);
26
+ }
14
27
  if (Array.isArray(result)) {
15
28
  return result.map((item) => normalizeStreamCallResult(item, dependencies));
16
29
  }
@@ -19,14 +32,14 @@ function normalizeStreamCallResult(result, dependencies) {
19
32
  }
20
33
  return wrapTarget(result, dependencies);
21
34
  }
22
- function createRateLimitedMethodWrapper(target, value, operation, dependencies) {
35
+ function createRateLimitedMethodWrapper(target, value, operation, dependencies, wrapAsChannelResult) {
23
36
  return async (...args) => {
24
37
  const { callArgs, callOptions } = (0, splitCallArgsAndOptions_1.splitCallArgsAndOptions)(args);
25
38
  const result = await (0, executeWithRateLimitHandling_1.executeWithRateLimitHandling)(() => Reflect.apply(value, target, callArgs), operation, dependencies.context, {
26
39
  ...constants_1.DEFAULT_OPTIONS,
27
40
  ...callOptions,
28
41
  });
29
- return normalizeStreamCallResult(result, dependencies);
42
+ return normalizeStreamCallResult(result, dependencies, wrapAsChannelResult);
30
43
  };
31
44
  }
32
45
  function wrapTarget(target, dependencies) {
@@ -43,7 +56,7 @@ function wrapTarget(target, dependencies) {
43
56
  if (STREAM_SYNC_CHANNEL_RESULT_METHODS.has(property)) {
44
57
  return (...args) => {
45
58
  const result = Reflect.apply(value, originalTarget, args);
46
- return normalizeStreamCallResult(result, dependencies);
59
+ return normalizeStreamCallResult(result, dependencies, true);
47
60
  };
48
61
  }
49
62
  if (CHANNEL_SYNC_PROXY_RESULT_METHODS.has(property)) {
@@ -58,14 +71,14 @@ function wrapTarget(target, dependencies) {
58
71
  if (STREAM_SYNC_METHODS.has(property) || CHANNEL_SYNC_METHODS.has(property)) {
59
72
  return (...args) => Reflect.apply(value, originalTarget, args);
60
73
  }
61
- return createRateLimitedMethodWrapper(originalTarget, value, property, dependencies);
74
+ return createRateLimitedMethodWrapper(originalTarget, value, property, dependencies, STREAM_CHANNEL_RESULT_METHODS.has(property));
62
75
  },
63
76
  });
64
77
  dependencies.cache.set(target, proxy);
65
78
  return proxy;
66
79
  }
67
80
  function createRateLimitedStreamProxy(stream, context) {
68
- (0, registerStreamBudgetInterceptors_1.registerStreamBudgetInterceptors)(stream, context);
81
+ (0, registerStreamInterceptors_1.registerStreamInterceptors)(stream, context);
69
82
  return wrapTarget(stream, {
70
83
  context,
71
84
  cache: new WeakMap(),
@@ -0,0 +1,320 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CHANNEL_SYNC_PROXY_RESULT_METHOD_NAMES = exports.CHANNEL_SYNC_METHOD_NAMES = exports.CHANNEL_METHOD_NAMES = exports.STREAM_SYNC_CHANNEL_RESULT_METHOD_NAMES = exports.STREAM_CHANNEL_RESULT_METHOD_NAMES = exports.STREAM_SYNC_METHOD_NAMES = exports.STREAM_METHOD_NAMES = void 0;
4
+ exports.STREAM_METHOD_NAMES = [
5
+ '_addChannelConfig',
6
+ '_buildWSPayload',
7
+ '_callClientListeners',
8
+ '_createImport',
9
+ '_createImportURL',
10
+ '_deleteUserMessageReference',
11
+ '_enrichAxiosOptions',
12
+ '_getConnectionID',
13
+ '_getImport',
14
+ '_getToken',
15
+ '_handleClientEvent',
16
+ '_handleUserEvent',
17
+ '_hasConnectionID',
18
+ '_isUsingServerAuth',
19
+ '_listImports',
20
+ '_logApiError',
21
+ '_logApiRequest',
22
+ '_logApiResponse',
23
+ '_muteStatus',
24
+ '_normalizeDate',
25
+ '_normalizeExpiration',
26
+ '_queryFlagReports',
27
+ '_queryFlags',
28
+ '_reviewFlagReport',
29
+ '_sayHi',
30
+ '_setToken',
31
+ '_setupConnection',
32
+ '_setUser',
33
+ '_startCleaning',
34
+ '_unblockMessage',
35
+ '_updateMemberWatcherReferences',
36
+ '_updateUserMessageReferences',
37
+ '_updateUserReferences',
38
+ '_validateAndGetMessageId',
39
+ 'addDevice',
40
+ 'banUser',
41
+ 'channel',
42
+ 'closeConnection',
43
+ 'commitMessage',
44
+ 'connect',
45
+ 'connectAnonymousUser',
46
+ 'connectUser',
47
+ 'createAbortControllerForNextRequest',
48
+ 'createBlockList',
49
+ 'createCampaign',
50
+ 'createChannelType',
51
+ 'createCommand',
52
+ 'createPermission',
53
+ 'createRole',
54
+ 'createSegment',
55
+ 'createToken',
56
+ 'deactivateUser',
57
+ 'deactivateUsers',
58
+ 'delete',
59
+ 'deleteBlockList',
60
+ 'deleteCampaign',
61
+ 'deleteChannels',
62
+ 'deleteChannelType',
63
+ 'deleteCommand',
64
+ 'deleteMessage',
65
+ 'deletePermission',
66
+ 'deletePushProvider',
67
+ 'deleteRole',
68
+ 'deleteSegment',
69
+ 'deleteUser',
70
+ 'deleteUsers',
71
+ 'devToken',
72
+ 'disconnect',
73
+ 'disconnectUser',
74
+ 'dispatchEvent',
75
+ 'doAxiosRequest',
76
+ 'enrichURL',
77
+ 'errorFromResponse',
78
+ 'exportChannel',
79
+ 'exportChannels',
80
+ 'exportUser',
81
+ 'exportUsers',
82
+ 'flagMessage',
83
+ 'flagUser',
84
+ 'get',
85
+ 'getAppSettings',
86
+ 'getAuthType',
87
+ 'getBlockList',
88
+ 'getCallToken',
89
+ 'getChannelById',
90
+ 'getChannelByMembers',
91
+ 'getChannelType',
92
+ 'getCommand',
93
+ 'getDevices',
94
+ 'getExportChannelStatus',
95
+ 'getMessage',
96
+ 'getPermission',
97
+ 'getRateLimits',
98
+ 'getTask',
99
+ 'getUnreadCount',
100
+ 'getUserAgent',
101
+ 'handleEvent',
102
+ 'handleResponse',
103
+ 'hydrateActiveChannels',
104
+ 'listBlockLists',
105
+ 'listChannelTypes',
106
+ 'listCommands',
107
+ 'listPermissions',
108
+ 'listPushProviders',
109
+ 'listRoles',
110
+ 'markAllRead',
111
+ 'markChannelsRead',
112
+ 'muteUser',
113
+ 'off',
114
+ 'on',
115
+ 'openConnection',
116
+ 'partialUpdateMessage',
117
+ 'partialUpdateUser',
118
+ 'partialUpdateUsers',
119
+ 'patch',
120
+ 'pinMessage',
121
+ 'post',
122
+ 'put',
123
+ 'queryBannedUsers',
124
+ 'queryCampaigns',
125
+ 'queryChannels',
126
+ 'queryMessageFlags',
127
+ 'queryRecipients',
128
+ 'querySegments',
129
+ 'queryUsers',
130
+ 'reactivateUser',
131
+ 'reactivateUsers',
132
+ 'recoverState',
133
+ 'removeDevice',
134
+ 'removeShadowBan',
135
+ 'restoreUsers',
136
+ 'resumeCampaign',
137
+ 'revokeTokens',
138
+ 'revokeUsersToken',
139
+ 'revokeUserToken',
140
+ 'scheduleCampaign',
141
+ 'search',
142
+ 'sendFile',
143
+ 'sendUserCustomEvent',
144
+ 'setAnonymousUser',
145
+ 'setBaseURL',
146
+ 'setGuestUser',
147
+ 'setLocalDevice',
148
+ 'setUser',
149
+ 'setUserAgent',
150
+ 'shadowBan',
151
+ 'stopCampaign',
152
+ 'sync',
153
+ 'testCampaign',
154
+ 'testPushSettings',
155
+ 'testSQSSettings',
156
+ 'translateMessage',
157
+ 'unbanUser',
158
+ 'unblockMessage',
159
+ 'unflagMessage',
160
+ 'unflagUser',
161
+ 'unmuteUser',
162
+ 'unpinMessage',
163
+ 'updateAppSettings',
164
+ 'updateBlockList',
165
+ 'updateCampaign',
166
+ 'updateChannelType',
167
+ 'updateCommand',
168
+ 'updateMessage',
169
+ 'updatePermission',
170
+ 'updateSegment',
171
+ 'updateUser',
172
+ 'updateUsers',
173
+ 'upsertPushProvider',
174
+ 'upsertUser',
175
+ 'upsertUsers',
176
+ 'userMuteStatus',
177
+ 'verifyWebhook',
178
+ ];
179
+ exports.STREAM_SYNC_METHOD_NAMES = [
180
+ '_addChannelConfig',
181
+ '_buildWSPayload',
182
+ '_callClientListeners',
183
+ '_deleteUserMessageReference',
184
+ '_enrichAxiosOptions',
185
+ '_getConnectionID',
186
+ '_getToken',
187
+ '_handleClientEvent',
188
+ '_handleUserEvent',
189
+ '_hasConnectionID',
190
+ '_isUsingServerAuth',
191
+ '_logApiError',
192
+ '_logApiRequest',
193
+ '_logApiResponse',
194
+ '_muteStatus',
195
+ '_normalizeDate',
196
+ '_normalizeExpiration',
197
+ '_sayHi',
198
+ '_setUser',
199
+ '_startCleaning',
200
+ '_updateMemberWatcherReferences',
201
+ '_updateUserMessageReferences',
202
+ '_updateUserReferences',
203
+ '_validateAndGetMessageId',
204
+ 'createAbortControllerForNextRequest',
205
+ 'createToken',
206
+ 'devToken',
207
+ 'dispatchEvent',
208
+ 'errorFromResponse',
209
+ 'getAuthType',
210
+ 'getUserAgent',
211
+ 'handleEvent',
212
+ 'handleResponse',
213
+ 'off',
214
+ 'on',
215
+ 'setBaseURL',
216
+ 'setLocalDevice',
217
+ 'setUserAgent',
218
+ 'userMuteStatus',
219
+ 'verifyWebhook',
220
+ ];
221
+ exports.STREAM_CHANNEL_RESULT_METHOD_NAMES = [
222
+ 'channel',
223
+ 'getChannelById',
224
+ 'getChannelByMembers',
225
+ 'hydrateActiveChannels',
226
+ 'queryChannels',
227
+ ];
228
+ exports.STREAM_SYNC_CHANNEL_RESULT_METHOD_NAMES = [
229
+ 'channel',
230
+ 'getChannelById',
231
+ 'getChannelByMembers',
232
+ 'hydrateActiveChannels',
233
+ ];
234
+ exports.CHANNEL_METHOD_NAMES = [
235
+ '_callChannelListeners',
236
+ '_channelURL',
237
+ '_checkInitialized',
238
+ '_countMessageAsUnread',
239
+ '_disconnect',
240
+ '_extendEventWithOwnReactions',
241
+ '_handleChannelEvent',
242
+ '_initializeState',
243
+ '_update',
244
+ 'acceptInvite',
245
+ 'addMembers',
246
+ 'addModerators',
247
+ 'assignRoles',
248
+ 'banUser',
249
+ 'clean',
250
+ 'countUnread',
251
+ 'countUnreadMentions',
252
+ 'create',
253
+ 'createCall',
254
+ 'delete',
255
+ 'deleteFile',
256
+ 'deleteImage',
257
+ 'deleteReaction',
258
+ 'demoteModerators',
259
+ 'disableSlowMode',
260
+ 'enableSlowMode',
261
+ 'getClient',
262
+ 'getConfig',
263
+ 'getMessagesById',
264
+ 'getPinnedMessages',
265
+ 'getReactions',
266
+ 'getReplies',
267
+ 'hide',
268
+ 'inviteMembers',
269
+ 'keystroke',
270
+ 'lastMessage',
271
+ 'lastRead',
272
+ 'markRead',
273
+ 'markUnread',
274
+ 'mute',
275
+ 'muteStatus',
276
+ 'off',
277
+ 'on',
278
+ 'query',
279
+ 'queryMembers',
280
+ 'rejectInvite',
281
+ 'removeMembers',
282
+ 'removeShadowBan',
283
+ 'search',
284
+ 'sendAction',
285
+ 'sendEvent',
286
+ 'sendFile',
287
+ 'sendImage',
288
+ 'sendMessage',
289
+ 'sendReaction',
290
+ 'shadowBan',
291
+ 'show',
292
+ 'stopTyping',
293
+ 'stopWatching',
294
+ 'truncate',
295
+ 'unbanUser',
296
+ 'unmute',
297
+ 'update',
298
+ 'updatePartial',
299
+ 'watch',
300
+ ];
301
+ exports.CHANNEL_SYNC_METHOD_NAMES = [
302
+ '_callChannelListeners',
303
+ '_channelURL',
304
+ '_checkInitialized',
305
+ '_countMessageAsUnread',
306
+ '_disconnect',
307
+ '_extendEventWithOwnReactions',
308
+ '_handleChannelEvent',
309
+ '_initializeState',
310
+ 'clean',
311
+ 'countUnread',
312
+ 'countUnreadMentions',
313
+ 'getConfig',
314
+ 'lastMessage',
315
+ 'lastRead',
316
+ 'muteStatus',
317
+ 'off',
318
+ 'on',
319
+ ];
320
+ exports.CHANNEL_SYNC_PROXY_RESULT_METHOD_NAMES = ['getClient'];
@@ -56,6 +56,22 @@ class RedisCooldown {
56
56
  });
57
57
  }
58
58
  }
59
+ static async setRemainingMsExact(cooldownKey, cooldownMs, context, options) {
60
+ if (cooldownMs <= 0) {
61
+ return;
62
+ }
63
+ const { redis, logger } = context;
64
+ try {
65
+ await redis.set(RedisCooldown.resolveRedisKey(cooldownKey, options), '1', 'PX', cooldownMs);
66
+ }
67
+ catch (error) {
68
+ logger.warn('Failed to write exact stream rate-limit cooldown to Redis', {
69
+ cooldownKey,
70
+ cooldownMs,
71
+ error,
72
+ });
73
+ }
74
+ }
59
75
  static async clear(cooldownKey, context, options) {
60
76
  const { redis, logger } = context;
61
77
  try {
@@ -3,30 +3,28 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createRateLimitExceededException = void 0;
4
4
  const xbees_conversations_client_1 = require("@wildix/xbees-conversations-client");
5
5
  const constants_1 = require("../constants");
6
- const RETRY_AFTER_HEADER_PADDING_MS = 1500;
6
+ const RETRY_AFTER_HEADER_PADDING_MS = 3000;
7
7
  function toPositiveMilliseconds(milliseconds) {
8
8
  return Math.max(0, Math.ceil(milliseconds));
9
9
  }
10
- function toRetryAfterSecondsFromDelayMs(delayMs) {
11
- const positiveDelayMs = toPositiveMilliseconds(delayMs);
12
- return Math.ceil(positiveDelayMs / 1000);
10
+ function toEpochSecondsFromNow(delayMs) {
11
+ return Math.ceil((Date.now() + toPositiveMilliseconds(delayMs)) / 1000);
13
12
  }
14
13
  function createRateLimitExceededException(options = {}) {
15
14
  const { rateLimit, message, operation, retryAfterMs = constants_1.DEFAULT_RETRY_AFTER_MS } = options;
16
15
  const defaultMessage = operation ? `Rate limit exceeded for ${operation}` : 'Rate limit exceeded';
17
16
  const retryAfterFromResetMs = rateLimit?.reset ? rateLimit.reset - Date.now() : undefined;
18
17
  const effectiveRetryAfterMs = retryAfterFromResetMs ?? retryAfterMs;
19
- const paddedRetryAfterMs = effectiveRetryAfterMs + RETRY_AFTER_HEADER_PADDING_MS;
20
18
  const retryAfterMilliseconds = toPositiveMilliseconds(effectiveRetryAfterMs);
21
- const retryAfterSeconds = toRetryAfterSecondsFromDelayMs(paddedRetryAfterMs);
22
19
  const rateLimitResetMilliseconds = rateLimit?.reset
23
20
  ? toPositiveMilliseconds(retryAfterFromResetMs ?? 0)
24
21
  : retryAfterMilliseconds;
22
+ const retryAfterEpochSeconds = toEpochSecondsFromNow(effectiveRetryAfterMs + RETRY_AFTER_HEADER_PADDING_MS);
25
23
  return new xbees_conversations_client_1.RateLimitExceededException({
26
24
  $metadata: {},
27
25
  message: message || defaultMessage,
28
26
  rateLimitRemaining: rateLimit?.remaining || 0,
29
- retryAfter: retryAfterSeconds,
27
+ retryAfter: retryAfterEpochSeconds,
30
28
  rateLimit: rateLimit?.limit?.toString() || 'unknown',
31
29
  rateLimitReset: rateLimitResetMilliseconds,
32
30
  });
@@ -6,33 +6,10 @@ const constants_1 = require("../constants");
6
6
  const createRateLimitExceededException_1 = require("./createRateLimitExceededException");
7
7
  const processStreamRateLimitException_1 = require("./processStreamRateLimitException");
8
8
  const RedisCooldown_1 = require("./RedisCooldown");
9
- function normalizeRetryAfterToDelayMs(retryAfter) {
10
- if (typeof retryAfter === 'string') {
11
- const asDateMs = Date.parse(retryAfter);
12
- if (!Number.isNaN(asDateMs)) {
13
- return Math.max(0, Math.round(asDateMs - Date.now()));
14
- }
15
- const asSeconds = Number(retryAfter);
16
- if (Number.isFinite(asSeconds) && asSeconds > 0) {
17
- return Math.max(0, Math.round(asSeconds * 1000));
18
- }
19
- return 0;
20
- }
21
- if (typeof retryAfter !== 'number' || !Number.isFinite(retryAfter) || retryAfter <= 0) {
22
- return 0;
23
- }
24
- if (retryAfter > 1000000000) {
25
- return Math.max(0, Math.round(retryAfter * 1000 - Date.now()));
26
- }
27
- if (retryAfter >= 1000) {
28
- return Math.max(0, Math.round(retryAfter));
29
- }
30
- return Math.max(0, Math.round(retryAfter * 1000));
31
- }
32
9
  function calculateRateLimitDelayMs(error, maxDelayMs) {
33
- const retryAfterMsFromError = normalizeRetryAfterToDelayMs(error.retryAfter);
34
- const hasServerRetryAfter = retryAfterMsFromError > 0;
35
- const baseDelayMs = hasServerRetryAfter ? retryAfterMsFromError + constants_1.RETRY_AFTER_BUFFER_MS : constants_1.DEFAULT_RETRY_AFTER_MS;
10
+ const retryAfterMs = typeof error.rateLimitReset === 'number' && error.rateLimitReset > 0 ? error.rateLimitReset : 0;
11
+ const hasServerRetryAfter = retryAfterMs > 0;
12
+ const baseDelayMs = hasServerRetryAfter ? retryAfterMs + constants_1.RETRY_AFTER_BUFFER_MS : constants_1.DEFAULT_RETRY_AFTER_MS;
36
13
  if (baseDelayMs > 0) {
37
14
  const jitterMs = Math.floor(Math.random() * constants_1.DEFAULT_JITTER_MS);
38
15
  const computedDelayMs = baseDelayMs + jitterMs;
@@ -48,6 +25,14 @@ async function executeWithRateLimitHandling(execute, operation, context, options
48
25
  const { enableCooldown, maxAttempts, maxDelayMs, maxRetryableDelayMs } = options;
49
26
  let attempt = 1;
50
27
  if (enableCooldown) {
28
+ const cooldownMs = await RedisCooldown_1.RedisCooldown.getRemainingMs(operation, { redis, logger });
29
+ if (cooldownMs > 0) {
30
+ logger.warn('Skipping stream request due to active rate-limit cooldown', {
31
+ operation,
32
+ cooldown: cooldownMs,
33
+ });
34
+ throw (0, createRateLimitExceededException_1.createRateLimitExceededException)({ operation, retryAfterMs: cooldownMs });
35
+ }
51
36
  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 });
52
37
  if (softCooldownMs > 0) {
53
38
  logger.debug('Delaying stream request due to active soft rate-limit cooldown', {
@@ -62,15 +47,16 @@ async function executeWithRateLimitHandling(execute, operation, context, options
62
47
  operation,
63
48
  cooldown: budgetCooldownMs,
64
49
  });
65
- await (0, promises_1.setTimeout)(budgetCooldownMs);
66
- }
67
- const cooldownMs = await RedisCooldown_1.RedisCooldown.getRemainingMs(operation, { redis, logger });
68
- if (cooldownMs > 0) {
69
- logger.warn('Skipping stream request due to active rate-limit cooldown', {
70
- operation,
71
- cooldown: cooldownMs,
72
- });
73
- throw (0, createRateLimitExceededException_1.createRateLimitExceededException)({ operation, retryAfterMs: cooldownMs });
50
+ let totalBudgetWaitMs = 0;
51
+ for (;;) {
52
+ const waitMs = await RedisCooldown_1.RedisCooldown.getRemainingMs(constants_1.STREAM_BUDGET_COOLDOWN_KEY, { redis, logger }, { keyPrefix: constants_1.STREAM_BUDGET_COOLDOWN_KEY_PREFIX });
53
+ if (waitMs <= 0 || totalBudgetWaitMs >= constants_1.BUDGET_DELAY_MAX_MS) {
54
+ break;
55
+ }
56
+ const chunkMs = Math.min(waitMs, constants_1.BUDGET_COOLDOWN_SLEEP_CHUNK_MS);
57
+ await (0, promises_1.setTimeout)(chunkMs);
58
+ totalBudgetWaitMs += chunkMs;
59
+ }
74
60
  }
75
61
  }
76
62
  for (;;) {
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeResetToEpochMs = exports.parseHeaderNumber = exports.getHeaderCaseInsensitive = void 0;
4
+ function getHeaderCaseInsensitive(headers, key) {
5
+ if (!headers) {
6
+ return;
7
+ }
8
+ const direct = headers[key];
9
+ if (direct !== undefined) {
10
+ return direct;
11
+ }
12
+ const normalizedKey = key.toLowerCase();
13
+ for (const [headerKey, headerValue] of Object.entries(headers)) {
14
+ if (headerKey.toLowerCase() === normalizedKey) {
15
+ return headerValue;
16
+ }
17
+ }
18
+ }
19
+ exports.getHeaderCaseInsensitive = getHeaderCaseInsensitive;
20
+ function parseHeaderNumber(headers, key) {
21
+ const raw = getHeaderCaseInsensitive(headers, key);
22
+ if (typeof raw === 'number' && Number.isFinite(raw)) {
23
+ return raw;
24
+ }
25
+ if (typeof raw === 'string') {
26
+ const parsed = Number(raw);
27
+ if (Number.isFinite(parsed)) {
28
+ return parsed;
29
+ }
30
+ }
31
+ }
32
+ exports.parseHeaderNumber = parseHeaderNumber;
33
+ function normalizeResetToEpochMs(reset) {
34
+ if (reset < 10000)
35
+ return Date.now() + Math.round(reset * 1000);
36
+ if (reset < 10000000000)
37
+ return Math.round(reset * 1000);
38
+ return Math.round(reset);
39
+ }
40
+ exports.normalizeResetToEpochMs = normalizeResetToEpochMs;