ioredis-toolkit 0.0.9 → 0.5.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/CHANGELOG.md +67 -0
- package/LICENSE +1 -1
- package/README.md +68 -1058
- package/dist/cache/cache.d.ts +30 -0
- package/dist/cache/cache.d.ts.map +1 -0
- package/dist/cache/cache.js +59 -0
- package/dist/cache/cache.js.map +1 -0
- package/dist/cache/config.d.ts +12 -0
- package/dist/cache/config.d.ts.map +1 -0
- package/dist/cache/config.js +13 -0
- package/dist/cache/config.js.map +1 -0
- package/dist/cache/types.d.ts +32 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +5 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/index.d.ts +43 -51
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -44
- package/dist/index.js.map +1 -0
- package/dist/lock/config.d.ts +12 -0
- package/dist/lock/config.d.ts.map +1 -0
- package/dist/lock/config.js +8 -0
- package/dist/lock/config.js.map +1 -0
- package/dist/lock/lock.d.ts +20 -0
- package/dist/lock/lock.d.ts.map +1 -0
- package/dist/lock/lock.js +44 -0
- package/dist/lock/lock.js.map +1 -0
- package/dist/lock/types.d.ts +19 -0
- package/dist/lock/types.d.ts.map +1 -0
- package/dist/lock/types.js +2 -0
- package/dist/lock/types.js.map +1 -0
- package/dist/modules-config.d.ts +3 -0
- package/dist/modules-config.d.ts.map +1 -0
- package/dist/modules-config.js +2 -0
- package/dist/modules-config.js.map +1 -0
- package/dist/pubsub/config.d.ts +11 -0
- package/dist/pubsub/config.d.ts.map +1 -0
- package/dist/pubsub/config.js +6 -0
- package/dist/pubsub/config.js.map +1 -0
- package/dist/pubsub/pubsub.d.ts +20 -0
- package/dist/pubsub/pubsub.d.ts.map +1 -0
- package/dist/pubsub/pubsub.js +54 -0
- package/dist/pubsub/pubsub.js.map +1 -0
- package/dist/pubsub/types.d.ts +24 -0
- package/dist/pubsub/types.d.ts.map +1 -0
- package/dist/pubsub/types.js +2 -0
- package/dist/pubsub/types.js.map +1 -0
- package/dist/rate-limit/config.d.ts +12 -0
- package/dist/rate-limit/config.d.ts.map +1 -0
- package/dist/rate-limit/config.js +6 -0
- package/dist/rate-limit/config.js.map +1 -0
- package/dist/rate-limit/rate-limiter.d.ts +18 -0
- package/dist/rate-limit/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limit/rate-limiter.js +37 -0
- package/dist/rate-limit/rate-limiter.js.map +1 -0
- package/dist/rate-limit/types.d.ts +27 -0
- package/dist/rate-limit/types.d.ts.map +1 -0
- package/dist/rate-limit/types.js +2 -0
- package/dist/rate-limit/types.js.map +1 -0
- package/dist/redis/client-facade.d.ts +77 -0
- package/dist/redis/client-facade.d.ts.map +1 -0
- package/dist/redis/client-facade.js +102 -0
- package/dist/redis/client-facade.js.map +1 -0
- package/dist/redis/client.d.ts +10 -0
- package/dist/redis/client.d.ts.map +1 -0
- package/dist/redis/client.js +29 -0
- package/dist/redis/client.js.map +1 -0
- package/dist/redis/cluster.d.ts +7 -0
- package/dist/redis/cluster.d.ts.map +1 -0
- package/dist/redis/cluster.js +47 -0
- package/dist/redis/cluster.js.map +1 -0
- package/dist/redis/config.d.ts +39 -0
- package/dist/redis/config.d.ts.map +1 -0
- package/dist/redis/config.js +52 -0
- package/dist/redis/config.js.map +1 -0
- package/dist/redis/errors.d.ts +5 -0
- package/dist/redis/errors.d.ts.map +1 -0
- package/dist/redis/errors.js +5 -0
- package/dist/redis/errors.js.map +1 -0
- package/dist/redis/types.d.ts +135 -0
- package/dist/redis/types.d.ts.map +1 -0
- package/dist/redis/types.js +2 -0
- package/dist/redis/types.js.map +1 -0
- package/dist/redis/wrapper.d.ts +88 -0
- package/dist/redis/wrapper.d.ts.map +1 -0
- package/dist/redis/wrapper.js +206 -0
- package/dist/redis/wrapper.js.map +1 -0
- package/dist/session/config.d.ts +47 -0
- package/dist/session/config.d.ts.map +1 -0
- package/dist/session/config.js +101 -0
- package/dist/session/config.js.map +1 -0
- package/dist/session/cookie.d.ts +16 -0
- package/dist/session/cookie.d.ts.map +1 -0
- package/dist/session/cookie.js +28 -0
- package/dist/session/cookie.js.map +1 -0
- package/dist/session/errors.d.ts +56 -0
- package/dist/session/errors.d.ts.map +1 -0
- package/dist/session/errors.js +58 -0
- package/dist/session/errors.js.map +1 -0
- package/dist/session/factory.d.ts +21 -0
- package/dist/session/factory.d.ts.map +1 -0
- package/dist/session/factory.js +30 -0
- package/dist/session/factory.js.map +1 -0
- package/dist/session/health.d.ts +12 -0
- package/dist/session/health.d.ts.map +1 -0
- package/dist/session/health.js +23 -0
- package/dist/session/health.js.map +1 -0
- package/dist/session/keys.d.ts +23 -0
- package/dist/session/keys.d.ts.map +1 -0
- package/dist/session/keys.js +27 -0
- package/dist/session/keys.js.map +1 -0
- package/dist/session/manager.d.ts +34 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/session/manager.js +31 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/session/metrics.d.ts +11 -0
- package/dist/session/metrics.d.ts.map +1 -0
- package/dist/session/metrics.js +10 -0
- package/dist/session/metrics.js.map +1 -0
- package/dist/session/repository.d.ts +49 -0
- package/dist/session/repository.d.ts.map +1 -0
- package/dist/session/repository.js +203 -0
- package/dist/session/repository.js.map +1 -0
- package/dist/session/revocation.d.ts +22 -0
- package/dist/session/revocation.d.ts.map +1 -0
- package/dist/session/revocation.js +41 -0
- package/dist/session/revocation.js.map +1 -0
- package/dist/session/script-sources.d.ts +11 -0
- package/dist/session/script-sources.d.ts.map +1 -0
- package/dist/session/script-sources.js +140 -0
- package/dist/session/script-sources.js.map +1 -0
- package/dist/session/scripts.d.ts +15 -0
- package/dist/session/scripts.d.ts.map +1 -0
- package/dist/session/scripts.js +41 -0
- package/dist/session/scripts.js.map +1 -0
- package/dist/session/serializer.d.ts +12 -0
- package/dist/session/serializer.d.ts.map +1 -0
- package/dist/session/serializer.js +77 -0
- package/dist/session/serializer.js.map +1 -0
- package/dist/session/service.d.ts +48 -0
- package/dist/session/service.d.ts.map +1 -0
- package/dist/session/service.js +235 -0
- package/dist/session/service.js.map +1 -0
- package/dist/session/token.d.ts +16 -0
- package/dist/session/token.d.ts.map +1 -0
- package/dist/session/token.js +32 -0
- package/dist/session/token.js.map +1 -0
- package/dist/session/types.d.ts +134 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +2 -0
- package/dist/session/types.js.map +1 -0
- package/dist/streams/config.d.ts +12 -0
- package/dist/streams/config.d.ts.map +1 -0
- package/dist/streams/config.js +6 -0
- package/dist/streams/config.js.map +1 -0
- package/dist/streams/streams.d.ts +24 -0
- package/dist/streams/streams.d.ts.map +1 -0
- package/dist/streams/streams.js +55 -0
- package/dist/streams/streams.js.map +1 -0
- package/dist/streams/types.d.ts +32 -0
- package/dist/streams/types.d.ts.map +1 -0
- package/dist/streams/types.js +2 -0
- package/dist/streams/types.js.map +1 -0
- package/docs/ACCEPTANCE-REPORT.md +70 -0
- package/docs/ARCHITECTURE.md +61 -0
- package/docs/CAPACITY.md +33 -0
- package/docs/DEPLOYMENT.md +22 -0
- package/docs/README-API.md +15 -0
- package/docs/STATE-MACHINE.md +38 -0
- package/docs/TESTING.md +37 -0
- package/docs/THREAT-MODEL.md +23 -0
- package/docs/TYPE-SAFETY.md +34 -0
- package/docs/modules/cache/README.md +7 -0
- package/docs/modules/cache/usage.md +156 -0
- package/docs/modules/lock/README.md +7 -0
- package/docs/modules/lock/usage.md +105 -0
- package/docs/modules/pubsub/README.md +7 -0
- package/docs/modules/pubsub/usage.md +106 -0
- package/docs/modules/rate-limit/README.md +7 -0
- package/docs/modules/rate-limit/usage.md +100 -0
- package/docs/modules/sessions/README.md +7 -0
- package/docs/modules/sessions/usage.md +262 -0
- package/docs/modules/streams/README.md +7 -0
- package/docs/modules/streams/usage.md +141 -0
- package/package.json +50 -60
- package/src/scripts/cleanup-index.lua +4 -0
- package/src/scripts/conditional-update.lua +21 -0
- package/src/scripts/consume-session.lua +21 -0
- package/src/scripts/create-session.lua +28 -0
- package/src/scripts/delete.lua +2 -0
- package/src/scripts/destroy-user.lua +13 -0
- package/src/scripts/enforce-limit.lua +17 -0
- package/src/scripts/revoke-session.lua +13 -0
- package/src/scripts/rotate.lua +24 -0
- package/src/scripts/touch-session.lua +28 -0
- package/src/scripts/update-session.lua +18 -0
- package/dist/cache.d.ts +0 -796
- package/dist/cache.js +0 -1120
- package/dist/client.d.ts +0 -284
- package/dist/client.js +0 -1114
- package/dist/cluster-slot.d.ts +0 -4
- package/dist/cluster-slot.js +0 -31
- package/dist/cluster.d.ts +0 -79
- package/dist/cluster.js +0 -156
- package/dist/errors.d.ts +0 -30
- package/dist/errors.js +0 -63
- package/dist/health.d.ts +0 -180
- package/dist/health.js +0 -239
- package/dist/lock.d.ts +0 -248
- package/dist/lock.js +0 -397
- package/dist/logger.d.ts +0 -12
- package/dist/logger.js +0 -40
- package/dist/pubsub.d.ts +0 -423
- package/dist/pubsub.js +0 -537
- package/dist/ratelimiter.d.ts +0 -441
- package/dist/ratelimiter.js +0 -539
- package/dist/session/index.d.ts +0 -23
- package/dist/session/index.js +0 -16
- package/dist/session/revocation-store.d.ts +0 -176
- package/dist/session/revocation-store.js +0 -318
- package/dist/session/scripts/cleanup-index.lua +0 -21
- package/dist/session/scripts/conditional-update-encrypted.lua +0 -60
- package/dist/session/scripts/conditional-update.lua +0 -63
- package/dist/session/scripts/create.lua +0 -83
- package/dist/session/scripts/delete-by-user.lua +0 -29
- package/dist/session/scripts/delete.lua +0 -15
- package/dist/session/scripts/enforce-limit.lua +0 -38
- package/dist/session/scripts/revoke.lua +0 -61
- package/dist/session/scripts/rotate-encrypted.lua +0 -110
- package/dist/session/scripts/rotate.lua +0 -122
- package/dist/session/scripts/touch-encrypted.lua +0 -89
- package/dist/session/scripts/touch.lua +0 -72
- package/dist/session/scripts/validate.lua +0 -90
- package/dist/session/session-circuit-breaker.d.ts +0 -42
- package/dist/session/session-circuit-breaker.js +0 -129
- package/dist/session/session-config.d.ts +0 -335
- package/dist/session/session-config.js +0 -162
- package/dist/session/session-cookie.d.ts +0 -72
- package/dist/session/session-cookie.js +0 -101
- package/dist/session/session-encryption.d.ts +0 -87
- package/dist/session/session-encryption.js +0 -139
- package/dist/session/session-errors.d.ts +0 -85
- package/dist/session/session-errors.js +0 -145
- package/dist/session/session-health.d.ts +0 -38
- package/dist/session/session-health.js +0 -60
- package/dist/session/session-keys.d.ts +0 -51
- package/dist/session/session-keys.js +0 -113
- package/dist/session/session-manager.d.ts +0 -73
- package/dist/session/session-manager.js +0 -94
- package/dist/session/session-metrics.d.ts +0 -33
- package/dist/session/session-metrics.js +0 -112
- package/dist/session/session-repository.d.ts +0 -161
- package/dist/session/session-repository.js +0 -683
- package/dist/session/session-scripts.d.ts +0 -36
- package/dist/session/session-scripts.js +0 -130
- package/dist/session/session-serializer.d.ts +0 -42
- package/dist/session/session-serializer.js +0 -248
- package/dist/session/session-service.d.ts +0 -104
- package/dist/session/session-service.js +0 -611
- package/dist/session/session-token.d.ts +0 -38
- package/dist/session/session-token.js +0 -86
- package/dist/session/session-types.d.ts +0 -253
- package/dist/session/session-types.js +0 -16
- package/dist/types.d.ts +0 -924
- package/dist/types.js +0 -151
- package/dist/utils/deepmerge.d.ts +0 -9
- package/dist/utils/deepmerge.js +0 -61
package/dist/pubsub.js
DELETED
|
@@ -1,537 +0,0 @@
|
|
|
1
|
-
import { RedisClientWrapper } from './client.js';
|
|
2
|
-
import { EventEmitter } from 'node:events';
|
|
3
|
-
import { defaultLogger } from './logger.js';
|
|
4
|
-
/**
|
|
5
|
-
* Redis Pub/Sub with a dedicated publisher and subscriber connection.
|
|
6
|
-
*
|
|
7
|
-
* **Description:**
|
|
8
|
-
* Provides a higher-level interface over native Redis Pub/Sub with the following features:
|
|
9
|
-
* - Dedicated publisher connection (configured at construction)
|
|
10
|
-
* - Dedicated subscriber connection (opened via {@link connectSubscriber})
|
|
11
|
-
* - JSON serialization on publish, auto-parsing on delivery
|
|
12
|
-
* - Pattern subscription support (`psubscribe`, `punsubscribe`)
|
|
13
|
-
* - Extends Node.js `EventEmitter` for event-based handling
|
|
14
|
-
* - Emits `'error'` events on subscriber failures
|
|
15
|
-
*
|
|
16
|
-
* **Type Parameters:**
|
|
17
|
-
* - `T` - The type of message payload. When publishing non-string values, they are
|
|
18
|
-
* JSON-serialized. When subscribing, messages are auto-parsed from JSON when possible.
|
|
19
|
-
*
|
|
20
|
-
* **Mode Support:**
|
|
21
|
-
* - Standalone, Sentinel, and Cluster modes are all supported.
|
|
22
|
-
* - The subscriber connection is created per the configured mode.
|
|
23
|
-
*
|
|
24
|
-
* **Example:**
|
|
25
|
-
* ```ts
|
|
26
|
-
* const pubsub = new PubSub(client);
|
|
27
|
-
* await pubsub.connectSubscriber({ mode: 'standalone', host: 'localhost', port: 6379 });
|
|
28
|
-
*
|
|
29
|
-
* // Subscribe to a channel
|
|
30
|
-
* await pubsub.subscribe('orders:created', (message) => {
|
|
31
|
-
* console.log(message); // { id: 1 } - JSON-parsed
|
|
32
|
-
* });
|
|
33
|
-
*
|
|
34
|
-
* // Publish a message
|
|
35
|
-
* const receivers = await pubsub.publish('orders:created', { id: 1 });
|
|
36
|
-
* // receivers === number of subscribers that received the message
|
|
37
|
-
*
|
|
38
|
-
* // Pattern subscription
|
|
39
|
-
* await pubsub.psubscribe('orders:*', ({ channel, message }) => {
|
|
40
|
-
* console.log(channel, message);
|
|
41
|
-
* });
|
|
42
|
-
* ```
|
|
43
|
-
*
|
|
44
|
-
* **Event Emissions:**
|
|
45
|
-
* - `message`: Emitted when a message is received on a subscribed channel.
|
|
46
|
-
* Payload: `{ channel: string, message: string }`
|
|
47
|
-
* - `pmessage`: Emitted when a pattern message is received.
|
|
48
|
-
* Payload: `{ pattern: string, channel: string, message: string }`
|
|
49
|
-
* - `error`: Emitted on subscriber errors.
|
|
50
|
-
* Payload: `Error`
|
|
51
|
-
*/
|
|
52
|
-
export class PubSub extends EventEmitter {
|
|
53
|
-
publisher;
|
|
54
|
-
subscriber = null;
|
|
55
|
-
logger;
|
|
56
|
-
subscriptions = new Map();
|
|
57
|
-
patternSubscriptions = new Map();
|
|
58
|
-
/**
|
|
59
|
-
* Creates a pub/sub instance. Publishing works immediately; subscribing
|
|
60
|
-
* requires calling {@link connectSubscriber} first.
|
|
61
|
-
*
|
|
62
|
-
* @param publisher - A {@link RedisClientWrapper} used for publishing.
|
|
63
|
-
* @param logger - Optional pino-compatible logger; defaults to `console`.
|
|
64
|
-
*
|
|
65
|
-
* @example
|
|
66
|
-
* ```ts
|
|
67
|
-
* const pubsub = new PubSub(client);
|
|
68
|
-
* ```
|
|
69
|
-
*/
|
|
70
|
-
/**
|
|
71
|
-
* Creates a pub/sub instance. Publishing works immediately; subscribing
|
|
72
|
-
* requires calling {@link connectSubscriber} first.
|
|
73
|
-
*
|
|
74
|
-
* @param publisher - A {@link RedisClientWrapper} used for publishing.
|
|
75
|
-
* @param logger - Optional pino-compatible logger; defaults to `console`.
|
|
76
|
-
*
|
|
77
|
-
* @example
|
|
78
|
-
* ```ts
|
|
79
|
-
* const pubsub = new PubSub(client);
|
|
80
|
-
* ```
|
|
81
|
-
*/
|
|
82
|
-
constructor(publisher, logger = defaultLogger) {
|
|
83
|
-
super();
|
|
84
|
-
this.publisher = publisher;
|
|
85
|
-
this.logger = logger.child({ component: 'PubSub' });
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Opens a dedicated subscriber connection.
|
|
89
|
-
*
|
|
90
|
-
* Idempotent: a second call is a no-op while a subscriber is connected.
|
|
91
|
-
* Subscriber errors are emitted as `'error'` events on the instance.
|
|
92
|
-
*
|
|
93
|
-
* @param config - Redis config for the subscriber connection (any mode).
|
|
94
|
-
*
|
|
95
|
-
* @example
|
|
96
|
-
* ```ts
|
|
97
|
-
* await pubsub.connectSubscriber({ mode: 'standalone', host: 'localhost', port: 6379 });
|
|
98
|
-
* ```
|
|
99
|
-
*/
|
|
100
|
-
/**
|
|
101
|
-
* Opens a dedicated subscriber connection.
|
|
102
|
-
*
|
|
103
|
-
* **Behavior:**
|
|
104
|
-
* - Idempotent: a second call is a no-op while a subscriber is connected.
|
|
105
|
-
* - Subscriber errors are emitted as `'error'` events on the instance.
|
|
106
|
-
*
|
|
107
|
-
* **Parameters:**
|
|
108
|
-
* - `config` - Redis config for the subscriber connection (any mode: standalone, sentinel, or cluster).
|
|
109
|
-
*
|
|
110
|
-
* **Example:**
|
|
111
|
-
* ```ts
|
|
112
|
-
* // Connect with standalone configuration
|
|
113
|
-
* await pubsub.connectSubscriber({ mode: 'standalone', host: 'localhost', port: 6379 });
|
|
114
|
-
*
|
|
115
|
-
* // Connect with cluster configuration
|
|
116
|
-
* await pubsub.connectSubscriber({
|
|
117
|
-
* mode: 'cluster',
|
|
118
|
-
* clusterNodes: [{ host: 'redis1', port: 7000 }, { host: 'redis2', port: 7001 }],
|
|
119
|
-
* });
|
|
120
|
-
* ```
|
|
121
|
-
*
|
|
122
|
-
* @returns `Promise<void>` that resolves when the subscriber connection is established.
|
|
123
|
-
*/
|
|
124
|
-
async connectSubscriber(config) {
|
|
125
|
-
if (this.subscriber)
|
|
126
|
-
return;
|
|
127
|
-
this.subscriber = new RedisClientWrapper(config, this.logger);
|
|
128
|
-
this.setupSubscriber();
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Sets up event listeners on the subscriber connection.
|
|
132
|
-
*
|
|
133
|
-
* **Behavior:**
|
|
134
|
-
* - Listens for `message` events and dispatches to {@link handleMessage}.
|
|
135
|
-
* - Listens for `pmessage` events (pattern subscriptions) and dispatches to {@link handlePatternMessage}.
|
|
136
|
-
* - Listens for `error` events and emits them on the instance.
|
|
137
|
-
*
|
|
138
|
-
* @internal
|
|
139
|
-
*/
|
|
140
|
-
setupSubscriber() {
|
|
141
|
-
if (!this.subscriber)
|
|
142
|
-
return;
|
|
143
|
-
const raw = this.subscriber.raw;
|
|
144
|
-
raw.on('message', (channel, message) => {
|
|
145
|
-
this.handleMessage(channel, message);
|
|
146
|
-
});
|
|
147
|
-
raw.on('pmessage', (pattern, channel, message) => {
|
|
148
|
-
this.handlePatternMessage(pattern, channel, message);
|
|
149
|
-
});
|
|
150
|
-
raw.on('error', (error) => {
|
|
151
|
-
this.logger.error('Subscriber error:', error);
|
|
152
|
-
this.emit('error', error);
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Handles a standard message event from the subscriber.
|
|
157
|
-
*
|
|
158
|
-
* **Behavior:**
|
|
159
|
-
* - Parses the message payload as JSON when possible.
|
|
160
|
-
* - Invokes all registered handlers for the channel.
|
|
161
|
-
* - Catches and logs handler errors without crashing.
|
|
162
|
-
*
|
|
163
|
-
* **Parameters:**
|
|
164
|
-
* - `channel` - The Redis channel name.
|
|
165
|
-
* - `message` - The raw message string from Redis (JSON-encoded).
|
|
166
|
-
*
|
|
167
|
-
* @internal
|
|
168
|
-
*/
|
|
169
|
-
handleMessage(channel, message) {
|
|
170
|
-
const handlers = this.subscriptions.get(channel);
|
|
171
|
-
if (!handlers)
|
|
172
|
-
return;
|
|
173
|
-
let parsed = message;
|
|
174
|
-
try {
|
|
175
|
-
parsed = JSON.parse(message);
|
|
176
|
-
}
|
|
177
|
-
catch { }
|
|
178
|
-
for (const handler of handlers) {
|
|
179
|
-
try {
|
|
180
|
-
handler(parsed);
|
|
181
|
-
}
|
|
182
|
-
catch (error) {
|
|
183
|
-
this.logger.error('Handler error:', error);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Handles a pattern message event from the subscriber.
|
|
189
|
-
*
|
|
190
|
-
* **Behavior:**
|
|
191
|
-
* - Parses the message payload as JSON when possible.
|
|
192
|
-
* - Invokes all registered handlers for the pattern.
|
|
193
|
-
* - Each handler receives an object with `channel` and `message` properties.
|
|
194
|
-
* - Catches and logs handler errors without crashing.
|
|
195
|
-
*
|
|
196
|
-
* **Parameters:**
|
|
197
|
-
* - `pattern` - The pattern that matched.
|
|
198
|
-
* - `channel` - The specific channel that was matched.
|
|
199
|
-
* - `message` - The raw message string from Redis (JSON-encoded).
|
|
200
|
-
*
|
|
201
|
-
* @internal
|
|
202
|
-
*/
|
|
203
|
-
handlePatternMessage(pattern, channel, message) {
|
|
204
|
-
const handlers = this.patternSubscriptions.get(pattern);
|
|
205
|
-
if (!handlers)
|
|
206
|
-
return;
|
|
207
|
-
let parsed = message;
|
|
208
|
-
try {
|
|
209
|
-
parsed = JSON.parse(message);
|
|
210
|
-
}
|
|
211
|
-
catch { }
|
|
212
|
-
for (const handler of handlers) {
|
|
213
|
-
try {
|
|
214
|
-
handler({ channel, message: parsed });
|
|
215
|
-
}
|
|
216
|
-
catch (error) {
|
|
217
|
-
this.logger.error('Handler error:', error);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Publishes a message to a channel.
|
|
223
|
-
*
|
|
224
|
-
* Non-string values are JSON-serialized.
|
|
225
|
-
*
|
|
226
|
-
* @param channel - The channel name.
|
|
227
|
-
* @param message - The message payload (string or any JSON-serializable value).
|
|
228
|
-
* @returns The number of subscribers that received the message.
|
|
229
|
-
*
|
|
230
|
-
* @example
|
|
231
|
-
* ```ts
|
|
232
|
-
* const receivers = await pubsub.publish('orders:created', { id: 1, total: 99 });
|
|
233
|
-
* ```
|
|
234
|
-
*/
|
|
235
|
-
/**
|
|
236
|
-
* Publishes a message to a channel.
|
|
237
|
-
*
|
|
238
|
-
* **Behavior:**
|
|
239
|
-
* - Non-string values are JSON-serialized automatically.
|
|
240
|
-
* - The raw message is published to the Redis channel.
|
|
241
|
-
* - Returns the number of subscribers that received the message.
|
|
242
|
-
*
|
|
243
|
-
* **Type Parameters:**
|
|
244
|
-
* - `T` - The type of the message payload. Non-string values are JSON-serialized.
|
|
245
|
-
*
|
|
246
|
-
* **Returns:**
|
|
247
|
-
* - The number of subscribers that received the message.
|
|
248
|
-
*
|
|
249
|
-
* **Example:**
|
|
250
|
-
* ```ts
|
|
251
|
-
* const receivers = await pubsub.publish('orders:created', { id: 1, total: 99 });
|
|
252
|
-
* // receivers === number of subscribed clients
|
|
253
|
-
* ```
|
|
254
|
-
*
|
|
255
|
-
* **Parameters:**
|
|
256
|
-
* - `channel` - The channel name.
|
|
257
|
-
* - `message` - The message payload (string or any JSON-serializable value).
|
|
258
|
-
*
|
|
259
|
-
* @returns The number of subscribers that received the message.
|
|
260
|
-
*/
|
|
261
|
-
async publish(channel, message) {
|
|
262
|
-
const raw = typeof message === 'string' ? message : JSON.stringify(message);
|
|
263
|
-
return this.publisher.raw.publish(channel, raw);
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Subscribes a handler to a channel.
|
|
267
|
-
*
|
|
268
|
-
* Multiple handlers per channel are supported; the channel is subscribed on
|
|
269
|
-
* Redis only once. Delivered payloads are JSON-parsed when possible.
|
|
270
|
-
*
|
|
271
|
-
* @param channel - The channel name.
|
|
272
|
-
* @param handler - Callback receiving the (parsed) message.
|
|
273
|
-
* @throws `Error` if the subscriber connection is not open.
|
|
274
|
-
*
|
|
275
|
-
* @example
|
|
276
|
-
* ```ts
|
|
277
|
-
* await pubsub.subscribe('orders:created', (order) => {
|
|
278
|
-
* console.log(order.id);
|
|
279
|
-
* });
|
|
280
|
-
* ```
|
|
281
|
-
*/
|
|
282
|
-
/**
|
|
283
|
-
* Subscribes a handler to a channel.
|
|
284
|
-
*
|
|
285
|
-
* **Behavior:**
|
|
286
|
-
* - Multiple handlers per channel are supported; the channel is subscribed on
|
|
287
|
-
* Redis only once.
|
|
288
|
-
* - Delivered payloads are JSON-parsed when possible.
|
|
289
|
-
* - Throws an error if the subscriber connection is not open.
|
|
290
|
-
*
|
|
291
|
-
* **Type Parameters:**
|
|
292
|
-
* - `T` - The type of the message data received in the handler.
|
|
293
|
-
*
|
|
294
|
-
* **Returns:**
|
|
295
|
-
* - `Promise<void>` that resolves when the subscription is established.
|
|
296
|
-
*
|
|
297
|
-
* **Example:**
|
|
298
|
-
* ```ts
|
|
299
|
-
* await pubsub.subscribe('orders:created', (order) => {
|
|
300
|
-
* console.log(order.id);
|
|
301
|
-
* });
|
|
302
|
-
* ```
|
|
303
|
-
*
|
|
304
|
-
* **Parameters:**
|
|
305
|
-
* - `channel` - The channel name.
|
|
306
|
-
* - `handler` - Callback receiving the (parsed) message.
|
|
307
|
-
*
|
|
308
|
-
* @throws `Error` if the subscriber connection is not open.
|
|
309
|
-
*/
|
|
310
|
-
async subscribe(channel, handler) {
|
|
311
|
-
if (!this.subscriber) {
|
|
312
|
-
throw new Error('Subscriber not connected');
|
|
313
|
-
}
|
|
314
|
-
if (!this.subscriptions.has(channel)) {
|
|
315
|
-
this.subscriptions.set(channel, new Set());
|
|
316
|
-
await this.subscriber.raw.subscribe(channel);
|
|
317
|
-
}
|
|
318
|
-
this.subscriptions.get(channel).add(handler);
|
|
319
|
-
this.logger.debug('Subscribed to channel', { channel });
|
|
320
|
-
}
|
|
321
|
-
/**
|
|
322
|
-
* Removes a handler (or all handlers) from a channel.
|
|
323
|
-
*
|
|
324
|
-
* The Redis subscription is dropped once the last handler for the channel is
|
|
325
|
-
* removed. Without a handler, the whole channel is unsubscribed.
|
|
326
|
-
*
|
|
327
|
-
* @param channel - The channel name.
|
|
328
|
-
* @param handler - Optional specific handler to remove; when omitted all
|
|
329
|
-
* handlers for the channel are removed.
|
|
330
|
-
*
|
|
331
|
-
* @example
|
|
332
|
-
* ```ts
|
|
333
|
-
* await pubsub.unsubscribe('orders:created', myHandler);
|
|
334
|
-
* await pubsub.unsubscribe('orders:created'); // remove everything
|
|
335
|
-
* ```
|
|
336
|
-
*/
|
|
337
|
-
/**
|
|
338
|
-
* Removes a handler (or all handlers) from a channel.
|
|
339
|
-
*
|
|
340
|
-
* **Behavior:**
|
|
341
|
-
* - The Redis subscription is dropped once the last handler for the channel is
|
|
342
|
-
* removed.
|
|
343
|
-
* - Without a handler, the whole channel is unsubscribed.
|
|
344
|
-
*
|
|
345
|
-
* **Returns:**
|
|
346
|
-
* - `Promise<void>` that resolves when the unsubscription is complete.
|
|
347
|
-
*
|
|
348
|
-
* **Example:**
|
|
349
|
-
* ```ts
|
|
350
|
-
* await pubsub.unsubscribe('orders:created', myHandler);
|
|
351
|
-
* await pubsub.unsubscribe('orders:created'); // remove everything
|
|
352
|
-
* ```
|
|
353
|
-
*
|
|
354
|
-
* **Parameters:**
|
|
355
|
-
* - `channel` - The channel name.
|
|
356
|
-
* - `handler` - Optional specific handler to remove; when omitted all
|
|
357
|
-
* handlers for the channel are removed.
|
|
358
|
-
*/
|
|
359
|
-
async unsubscribe(channel, handler) {
|
|
360
|
-
if (!this.subscriber)
|
|
361
|
-
return;
|
|
362
|
-
if (handler && this.subscriptions.has(channel)) {
|
|
363
|
-
const handlers = this.subscriptions.get(channel);
|
|
364
|
-
handlers.delete(handler);
|
|
365
|
-
if (handlers.size === 0) {
|
|
366
|
-
this.subscriptions.delete(channel);
|
|
367
|
-
await this.subscriber.raw.unsubscribe(channel);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
else {
|
|
371
|
-
this.subscriptions.delete(channel);
|
|
372
|
-
await this.subscriber.raw.unsubscribe(channel);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* Subscribes a handler to all channels matching a glob pattern.
|
|
377
|
-
*
|
|
378
|
-
* Pattern handlers receive `{ channel, message }` (message JSON-parsed).
|
|
379
|
-
*
|
|
380
|
-
* @param pattern - Glob pattern, e.g. `'orders:*'`.
|
|
381
|
-
* @param handler - Callback receiving `{ channel, message }`.
|
|
382
|
-
* @throws `Error` if the subscriber connection is not open.
|
|
383
|
-
*
|
|
384
|
-
* @example
|
|
385
|
-
* ```ts
|
|
386
|
-
* await pubsub.psubscribe('orders:*', ({ channel, message }) => {
|
|
387
|
-
* console.log(channel, message);
|
|
388
|
-
* });
|
|
389
|
-
* ```
|
|
390
|
-
*/
|
|
391
|
-
/**
|
|
392
|
-
* Subscribes a handler to all channels matching a glob pattern.
|
|
393
|
-
*
|
|
394
|
-
* **Behavior:**
|
|
395
|
-
* - Pattern handlers receive `{ channel, message }` (message JSON-parsed).
|
|
396
|
-
* - The Redis subscription is set up once per pattern.
|
|
397
|
-
*
|
|
398
|
-
* **Type Parameters:**
|
|
399
|
-
* - `T` - The type of the message data received in the handler.
|
|
400
|
-
*
|
|
401
|
-
* **Returns:**
|
|
402
|
-
* - `Promise<void>` that resolves when the pattern subscription is established.
|
|
403
|
-
*
|
|
404
|
-
* **Example:**
|
|
405
|
-
* ```ts
|
|
406
|
-
* await pubsub.psubscribe('orders:*', ({ channel, message }) => {
|
|
407
|
-
* console.log(channel, message);
|
|
408
|
-
* });
|
|
409
|
-
* ```
|
|
410
|
-
*
|
|
411
|
-
* **Parameters:**
|
|
412
|
-
* - `pattern` - Glob pattern, e.g. `'orders:*'`.
|
|
413
|
-
* - `handler` - Callback receiving `{ channel, message }`.
|
|
414
|
-
*
|
|
415
|
-
* @throws `Error` if the subscriber connection is not open.
|
|
416
|
-
*/
|
|
417
|
-
async psubscribe(pattern, handler) {
|
|
418
|
-
if (!this.subscriber) {
|
|
419
|
-
throw new Error('Subscriber not connected');
|
|
420
|
-
}
|
|
421
|
-
if (!this.patternSubscriptions.has(pattern)) {
|
|
422
|
-
this.patternSubscriptions.set(pattern, new Set());
|
|
423
|
-
await this.subscriber.raw.psubscribe(pattern);
|
|
424
|
-
}
|
|
425
|
-
this.patternSubscriptions.get(pattern).add(handler);
|
|
426
|
-
}
|
|
427
|
-
/**
|
|
428
|
-
* Removes a handler (or all handlers) from a pattern subscription.
|
|
429
|
-
*
|
|
430
|
-
* @param pattern - The glob pattern.
|
|
431
|
-
* @param handler - Optional specific handler to remove; when omitted all
|
|
432
|
-
* handlers for the pattern are removed.
|
|
433
|
-
*
|
|
434
|
-
* @example
|
|
435
|
-
* ```ts
|
|
436
|
-
* await pubsub.punsubscribe('orders:*', myHandler);
|
|
437
|
-
* await pubsub.punsubscribe('orders:*');
|
|
438
|
-
* ```
|
|
439
|
-
*/
|
|
440
|
-
/**
|
|
441
|
-
* Removes a handler (or all handlers) from a pattern subscription.
|
|
442
|
-
*
|
|
443
|
-
* **Returns:**
|
|
444
|
-
* - `Promise<void>` that resolves when the punsubscription is complete.
|
|
445
|
-
*
|
|
446
|
-
* **Example:**
|
|
447
|
-
* ```ts
|
|
448
|
-
* await pubsub.punsubscribe('orders:*', myHandler);
|
|
449
|
-
* await pubsub.punsubscribe('orders:*');
|
|
450
|
-
* ```
|
|
451
|
-
*
|
|
452
|
-
* **Parameters:**
|
|
453
|
-
* - `pattern` - The glob pattern.
|
|
454
|
-
* - `handler` - Optional specific handler to remove; when omitted all
|
|
455
|
-
* handlers for the pattern are removed.
|
|
456
|
-
*/
|
|
457
|
-
async punsubscribe(pattern, handler) {
|
|
458
|
-
if (!this.subscriber)
|
|
459
|
-
return;
|
|
460
|
-
if (handler && this.patternSubscriptions.has(pattern)) {
|
|
461
|
-
const handlers = this.patternSubscriptions.get(pattern);
|
|
462
|
-
handlers.delete(handler);
|
|
463
|
-
if (handlers.size === 0) {
|
|
464
|
-
this.patternSubscriptions.delete(pattern);
|
|
465
|
-
await this.subscriber.raw.punsubscribe(pattern);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
else {
|
|
469
|
-
this.patternSubscriptions.delete(pattern);
|
|
470
|
-
await this.subscriber.raw.punsubscribe(pattern);
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
/**
|
|
474
|
-
* Closes the subscriber connection and clears all subscriptions.
|
|
475
|
-
*
|
|
476
|
-
* The publisher client is not closed (it is owned by the caller).
|
|
477
|
-
*
|
|
478
|
-
* @example
|
|
479
|
-
* ```ts
|
|
480
|
-
* await pubsub.close();
|
|
481
|
-
* ```
|
|
482
|
-
*/
|
|
483
|
-
/**
|
|
484
|
-
* Closes the subscriber connection and clears all subscriptions.
|
|
485
|
-
*
|
|
486
|
-
* **Behavior:**
|
|
487
|
-
* - The publisher client is not closed (it is owned by the caller).
|
|
488
|
-
* - All subscriptions are cleared from memory.
|
|
489
|
-
*
|
|
490
|
-
* **Example:**
|
|
491
|
-
* ```ts
|
|
492
|
-
* await pubsub.close();
|
|
493
|
-
* ```
|
|
494
|
-
*
|
|
495
|
-
* @returns `Promise<void>` that resolves when the subscriber is closed.
|
|
496
|
-
*/
|
|
497
|
-
async close() {
|
|
498
|
-
if (this.subscriber) {
|
|
499
|
-
await this.subscriber.close();
|
|
500
|
-
this.subscriber = null;
|
|
501
|
-
}
|
|
502
|
-
this.subscriptions.clear();
|
|
503
|
-
this.patternSubscriptions.clear();
|
|
504
|
-
}
|
|
505
|
-
/**
|
|
506
|
-
* Returns subscription statistics.
|
|
507
|
-
*
|
|
508
|
-
* @returns `{ subscriptions, patternSubscriptions, connected }`.
|
|
509
|
-
*
|
|
510
|
-
* @example
|
|
511
|
-
* ```ts
|
|
512
|
-
* const stats = pubsub.getStats();
|
|
513
|
-
* // { subscriptions: 2, patternSubscriptions: 1, connected: true }
|
|
514
|
-
* ```
|
|
515
|
-
*/
|
|
516
|
-
/**
|
|
517
|
-
* Returns subscription statistics.
|
|
518
|
-
*
|
|
519
|
-
* **Returns:**
|
|
520
|
-
* - A {@link PubSubStats} object with the current subscription state.
|
|
521
|
-
*
|
|
522
|
-
* **Example:**
|
|
523
|
-
* ```ts
|
|
524
|
-
* const stats = pubsub.getStats();
|
|
525
|
-
* // { subscriptions: 2, patternSubscriptions: 1, connected: true }
|
|
526
|
-
* ```
|
|
527
|
-
*
|
|
528
|
-
* @returns `{ subscriptions, patternSubscriptions, connected }`.
|
|
529
|
-
*/
|
|
530
|
-
getStats() {
|
|
531
|
-
return {
|
|
532
|
-
subscriptions: this.subscriptions.size,
|
|
533
|
-
patternSubscriptions: this.patternSubscriptions.size,
|
|
534
|
-
connected: this.subscriber !== null,
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
|
-
}
|