@wildix/xbees-conversations-utils 1.3.0 → 1.3.1

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.md CHANGED
@@ -1,118 +1,18 @@
1
- # `streamRateLimitHandlingProxy`
1
+ # `xbees-conversations-utils`
2
2
 
3
- This package wraps a `StreamChat` client into a proxy that adds shared rate-limit protection around Stream SDK calls without changing the normal sync API contract. Async calls go through retry / cooldown handling, while sync methods stay sync. If a proxied call returns a channel-like object, that object is wrapped too, so the same protection continues on nested channel operations.
3
+ Utility helpers for working with x-bees conversations data.
4
4
 
5
- ## Public entry points
5
+ ## Included modules
6
6
 
7
- - `createRateLimitedStreamProxy(stream, {redis, logger})`
8
- Creates the proxy, attaches response interceptors once, and returns a rate-limit-aware `StreamChat` instance.
9
- Code: `src/streamRateLimitHandlingProxy/createRateLimitedStreamProxy.ts`
10
- - `withStreamRateLimitOptions(options)`
11
- Builds a marker token that can be passed as the last argument of a proxied async call to override retry behavior for that single call.
12
- Code: `src/streamRateLimitHandlingProxy/withStreamRateLimitOptions.ts`
13
- - Public exports are re-exported from `src/streamRateLimitHandlingProxy/index.ts` and then from `src/index.ts`.
7
+ - `anonymousEmail`
8
+ Helpers for generating and validating anonymous user emails.
9
+ - `normalization`
10
+ Helpers for normalizing and localizing Stream payloads into `@wildix/xbees-conversations-client` models.
11
+ - `stream`
12
+ Shared Stream Chat types used by normalization helpers and downstream consumers.
13
+ - `types`
14
+ Localized conversation and presence-related TypeScript types.
14
15
 
15
- ## How it works
16
+ ## Notes
16
17
 
17
- 1. `createRateLimitedStreamProxy(...)` tries to register axios response interceptors on the underlying Stream transport.
18
- 2. The proxy classifies Stream methods into groups generated in `generatedMethodNames.ts`:
19
- - pure sync methods: returned as-is;
20
- - sync methods returning channel/client objects: returned sync, but results are re-wrapped;
21
- - async methods: executed through the rate-limit handler.
22
- 3. Every async call is normalized through `executeWithRateLimitHandling(...)`.
23
- 4. Returned channel-like objects are detected and wrapped again, so calls like `stream.channel(...).sendMessage(...)` stay protected end to end.
24
-
25
- If the underlying Stream SDK transport does not expose an axios instance, the proxy still works, but shared protection driven by response headers becomes less effective because no interceptors can be attached.
26
-
27
- ## Protection layers
28
-
29
- ### 1. Soft global throttle
30
-
31
- The interceptor reads `x-ratelimit-limit` and `x-ratelimit-remaining`. When usage becomes high, it enables a short shared Redis cooldown before real 429 responses start happening. This smooths bursts instead of waiting for hard throttling.
32
-
33
- - Trigger source: response headers on successful or failed requests
34
- - Effect:
35
- - usage `>= 95%`: delay next requests by `3000ms`;
36
- - usage between `85%` and `95%`: delay by `1500ms`;
37
- - usage between `70%` and `85%`: delay by `500ms`;
38
- - usage `< 70%`: clear soft throttle.
39
- - Scope: global shared throttle
40
- - Code: `helpers/processStreamRateLimitHeaders.ts`
41
-
42
- ### 2. Hard per-operation 429 cooldown
43
-
44
- If Stream returns HTTP 429, the handler converts that error into `RateLimitExceededException`, calculates retry delay from `retry-after` or fallback values, stores a Redis cooldown for the specific operation, and optionally retries the call.
45
-
46
- If another worker hits the same operation while that cooldown is still active, the request is short-circuited locally before touching Stream. To keep that synthetic error useful, the latest real `x-ratelimit-*` snapshot is cached in Redis next to the cooldown and reused in the locally generated exception.
47
-
48
- - Trigger source: HTTP 429 / `retry-after` / `x-ratelimit-*`
49
- - Effect: per-operation block, optional retry, synthetic local short-circuit when cooldown is already known
50
- - Scope: operation-level
51
- - Code:
52
- - execution flow: `helpers/executeWithRateLimitHandling.ts`
53
- - 429 parsing: `helpers/processStreamRateLimitException.ts`
54
- - exception creation: `helpers/createRateLimitExceededException.ts`
55
- - snapshot serialization: `helpers/rateLimitSnapshot.ts`
56
-
57
- ### 3. App-wide budget cooldown
58
-
59
- The interceptor also reads `x-budget-*` headers. If overall Stream app budget usage becomes high, it enables a global Redis cooldown. While this cooldown is active, requests are delayed in small sleep chunks so they can resume early if a fresher response lowers the cooldown.
60
-
61
- - Trigger source: `x-budget-limit-ms`, `x-budget-remaining-ms`, `x-budget-used-ms`
62
- - Effect:
63
- - usage `>= 80%`: enable strong cooldown (`30s-60s`);
64
- - usage between `70%` and `80%`: keep a relaxed cooldown (`5s-10s`);
65
- - usage between `60%` and `70%`: keep a minimal cooldown (`1s-2s`);
66
- - usage `< 60%`: clear cooldown.
67
- - Scope: whole application, not a single operation
68
- - Code: `helpers/processStreamBudgetHeaders.ts`
69
-
70
- ## Retry and cooldown behavior
71
-
72
- - Local preflight checks happen before request execution when `enableCooldown` is on:
73
- - active per-operation cooldown: fail fast with a synthetic `RateLimitExceededException`;
74
- - active soft throttle: delay request briefly;
75
- - active budget cooldown: delay request globally.
76
- - Real 429 responses can still be retried if:
77
- - `attempt < maxAttempts`;
78
- - computed delay `<= maxRetryableDelayMs`.
79
- - Delay calculation rules:
80
- - if Stream provides `Retry-After` / reset information, that server value is preferred even if it is larger than `maxDelayMs`;
81
- - `maxDelayMs` only caps fallback delay when server retry timing is missing or malformed;
82
- - `maxRetryableDelayMs` decides whether that computed delay is still retryable or should be propagated immediately.
83
- - If retry is not allowed, the processed rate-limit exception is propagated to the caller.
84
-
85
- Core logic: `src/streamRateLimitHandlingProxy/helpers/executeWithRateLimitHandling.ts`
86
-
87
- ## Configuration
88
-
89
- Default behavior is defined in `src/streamRateLimitHandlingProxy/constants.ts`:
90
-
91
- - `maxAttempts = 3`
92
- - `enableCooldown = true`
93
- - `maxDelayMs = 5000`
94
- - `maxRetryableDelayMs = 10000`
95
-
96
- The same file also contains:
97
-
98
- - Redis key prefixes for hard cooldown, soft throttle, and budget cooldown
99
- - fallback retry values and jitter
100
- - budget thresholds and cooldown ranges
101
- - soft-throttle thresholds and delays
102
-
103
- Notes:
104
-
105
- - `enableCooldown` controls local Redis-based preflight checks and shared cooldown reuse.
106
- - `maxDelayMs` is a fallback cap, not a hard upper bound for server-provided `Retry-After`.
107
- - Missing / invalid rate-limit headers do not break the proxy, but they reduce how much shared throttling state can be inferred.
108
-
109
- Per-call overrides are passed as the last argument:
110
-
111
- ```ts
112
- stream.queryChannels(filters, sort, options, withStreamRateLimitOptions({
113
- maxAttempts: 1,
114
- maxRetryableDelayMs: 0,
115
- }));
116
- ```
117
-
118
- Argument extraction is implemented in `helpers/splitCallArgsAndOptions.ts`.
18
+ The Stream rate-limit handling proxy was moved into the dedicated `@wildix/stream-proxy` package.
package/dist-cjs/index.js CHANGED
@@ -4,5 +4,4 @@ const tslib_1 = require("tslib");
4
4
  tslib_1.__exportStar(require("./anonymousEmail"), exports);
5
5
  tslib_1.__exportStar(require("./normalization"), exports);
6
6
  tslib_1.__exportStar(require("./stream"), exports);
7
- tslib_1.__exportStar(require("./streamRateLimitHandlingProxy"), exports);
8
7
  tslib_1.__exportStar(require("./types"), exports);
package/dist-es/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from './anonymousEmail';
2
2
  export * from './normalization';
3
3
  export * from './stream';
4
- export * from './streamRateLimitHandlingProxy';
5
4
  export * from './types';
@@ -1,5 +1,4 @@
1
1
  export * from './anonymousEmail';
2
2
  export * from './normalization';
3
3
  export * from './stream';
4
- export * from './streamRateLimitHandlingProxy';
5
4
  export * from './types';
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "@wildix/xbees-conversations-utils",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "",
5
5
  "main": "./dist-cjs/index.js",
6
6
  "module": "./dist-es/index.js",
7
7
  "types": "./dist-types/index.d.ts",
8
8
  "scripts": {
9
- "prebuild": "node ./scripts/generateRateLimitMethodNames.mjs",
10
9
  "build": "concurrently 'yarn:build:cjs' 'yarn:build:es' 'yarn:build:types'",
11
10
  "build:cjs": "tsc -p tsconfig.cjs.json",
12
11
  "build:es": "tsc -p tsconfig.es.json",
@@ -25,9 +24,7 @@
25
24
  },
26
25
  "license": "Apache-2.0",
27
26
  "dependencies": {
28
- "@aws-lambda-powertools/logger": "2.18.0",
29
27
  "@wildix/xbees-conversations-client": "1.2.13",
30
- "ioredis": "5.10.0",
31
28
  "stream-chat": "8.12.1",
32
29
  "tslib": "2.5.0"
33
30
  },