@owlmeans/redis 0.1.1 → 0.1.3

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 OwlMeans Common — Fullstack typescript framework
3
+ Copyright (c) 2026 OwlMeans Common — Fullstack typescript framework
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,517 +1,57 @@
1
1
  # @owlmeans/redis
2
2
 
3
- Redis service integration for OwlMeans Common server applications. This package provides a server-side Redis service implementation with clustering support, connection management, and multi-layer support designed for caching, session storage, and high-performance data operations.
3
+ Redis service for OwlMeans server contexts connection management with cluster support.
4
4
 
5
5
  ## Overview
6
6
 
7
- The `@owlmeans/redis` package extends the OwlMeans resource system to provide Redis-specific functionality including:
8
-
9
- - **Redis Service Integration**: Factory functions for creating Redis services with connection management
10
- - **Cluster Support**: Automatic Redis cluster and sentinel configuration
11
- - **Connection Pooling**: Efficient Redis connection management with proper cleanup
12
- - **Multi-Layer Support**: Integration with OwlMeans context layer system for proper data isolation
13
- - **Prefix Management**: Automatic key prefixing for namespace isolation
14
-
15
- This package follows the OwlMeans "quadra" pattern as a server-side implementation complementing the basic `@owlmeans/redis-resource` package.
7
+ - `makeRedisService(alias?)` creates a Redis connection service
8
+ - `appendRedis(context, alias?)` — registers the service in the context
9
+ - Reads connection config from `context.cfg.dbs[alias]`
10
+ - Used as the connection provider for `@owlmeans/redis-resource`
16
11
 
17
12
  ## Installation
18
13
 
19
14
  ```bash
20
- npm install @owlmeans/redis
21
- ```
22
-
23
- ## Dependencies
24
-
25
- This package requires Redis client library and integrates with:
26
- - `@owlmeans/redis-resource`: Base Redis resource definitions
27
- - `@owlmeans/server-context`: Server context management
28
- - `@owlmeans/resource`: Base resource service patterns
29
- - `ioredis`: High-performance Redis client library
30
-
31
- ## Core Concepts
32
-
33
- ### Redis Service
34
-
35
- The Redis service provides connection management and extends the base database service with Redis-specific functionality like clustering and prefix management.
36
-
37
- ### Connection Management
38
-
39
- Manages Redis connections with support for clustering, sentinels, and proper connection lifecycle management including graceful shutdown.
40
-
41
- ### Layer Integration
42
-
43
- Supports multi-layer data isolation through the OwlMeans context layer system, allowing service-specific and entity-specific Redis configurations.
44
-
45
- ## API Reference
46
-
47
- ### Types
48
-
49
- #### `RedisMeta`
50
- Metadata interface for Redis-specific configuration extending ioredis options.
51
-
52
- ```typescript
53
- interface RedisMeta extends RedisOptions {
54
- masterNumber?: number // Master node count for cluster
55
- slaveNumber?: number // Slave node count for cluster
56
- }
57
- ```
58
-
59
- ### Factory Functions
60
-
61
- #### `makeRedisService(alias?: string): RedisDbService`
62
-
63
- Creates a Redis service instance with connection management and clustering capabilities.
64
-
65
- **Parameters:**
66
- - `alias` (optional): Service alias (default: `DEFAULT_ALIAS`)
67
-
68
- **Returns:** `RedisDbService` instance
69
-
70
- **Methods:**
71
- - **`db(configAlias?: string): Promise<RedisDb>`**: Gets Redis database instance with prefix for the configuration
72
- - **`initialize(configAlias?: string): Promise<void>`**: Initializes Redis connection with cluster setup
73
- - **`reinitializeContext<T>(context: BasicContext<ServerConfig>): T`**: Reinitializes service with new context
74
-
75
- **Example:**
76
- ```typescript
77
- import { makeRedisService } from '@owlmeans/redis'
78
-
79
- const redisService = makeRedisService('cache')
80
-
81
- // Initialize with configuration
82
- await redisService.initialize('prod-config')
83
-
84
- // Get database instance with prefix
85
- const db = await redisService.db('prod-config')
86
-
87
- // Use Redis operations
88
- await db.client.set('user:123', JSON.stringify(userData))
89
- const user = await db.client.get('user:123')
15
+ bun add @owlmeans/redis
90
16
  ```
91
17
 
92
- #### `appendRedis<C, T>(context: T, alias?: string): T`
93
-
94
- Convenience function to create and register a Redis service with a context.
95
-
96
- **Parameters:**
97
- - `context`: Server context instance
98
- - `alias` (optional): Service alias (default: `DEFAULT_ALIAS`)
99
-
100
- **Returns:** The context with Redis service registered
18
+ ## Usage
101
19
 
102
- **Example:**
103
20
  ```typescript
104
- import { appendRedis } from '@owlmeans/redis'
105
- import { makeServerContext } from '@owlmeans/server-context'
21
+ import { appendRedis, DEFAULT_ALIAS } from '@owlmeans/redis'
106
22
 
107
- const context = makeServerContext(serverConfig)
108
- const contextWithRedis = appendRedis(context, 'session-store')
109
-
110
- await contextWithRedis.configure().init()
111
-
112
- // Access Redis service
113
- const redisService = context.service('session-store')
23
+ // In context setup (backend/src/context.ts)
24
+ appendRedis<C, T>(context)
114
25
  ```
115
26
 
116
- ### Redis Database Operations
117
-
118
- The Redis service provides a database interface with automatic prefixing:
119
-
120
- #### `RedisDb`
121
- Database instance with client and prefix management.
27
+ Config (`config.json`):
122
28
 
123
- ```typescript
124
- interface RedisDb {
125
- client: RedisClient // ioredis client instance (duplicated for isolation)
126
- prefix: string // Key prefix for namespace isolation
127
- }
128
- ```
129
-
130
- **Usage:**
131
- ```typescript
132
- const db = await redisService.db('config-alias')
133
-
134
- // Keys are automatically prefixed
135
- await db.client.set('session:user123', sessionData)
136
- await db.client.get('session:user123')
137
-
138
- // Use Redis operations with prefix isolation
139
- await db.client.hmset('user:profile', profileData)
140
- const profile = await db.client.hgetall('user:profile')
141
- ```
142
-
143
- ### Cluster Support
144
-
145
- The service automatically handles Redis cluster and sentinel configuration:
146
-
147
- ```typescript
148
- // Configuration with cluster hosts
149
- const config = {
150
- alias: 'cluster-config',
151
- host: ['redis1.example.com', 'redis2.example.com', 'redis3.example.com'],
152
- port: 6379,
153
- database: 'app-cache',
154
- // Additional cluster options in meta
155
- meta: {
156
- masterNumber: 3,
157
- slaveNumber: 6,
158
- enableReadyCheck: true,
159
- maxRetriesPerRequest: 3
160
- }
161
- }
162
-
163
- // Service automatically detects cluster and sets up connections
164
- await redisService.initialize('cluster-config')
165
- ```
166
-
167
- ### Constants
168
-
169
- #### `DEFAULT_ALIAS`
170
- Default service alias for Redis services.
171
-
172
- ```typescript
173
- const DEFAULT_ALIAS = DEFAULT_DB_ALIAS // From @owlmeans/redis-resource
174
- ```
175
-
176
- ## Usage Examples
177
-
178
- ### Basic Redis Service Setup
179
-
180
- ```typescript
181
- import { makeRedisService } from '@owlmeans/redis'
182
- import { makeServerContext } from '@owlmeans/server-context'
183
-
184
- // Create server context with Redis configuration
185
- const context = makeServerContext({
186
- service: 'my-app',
187
- type: AppType.Backend,
188
- layer: Layer.Service,
189
- dbs: [{
190
- alias: 'main-cache',
191
- service: 'redis',
192
- host: 'localhost',
193
- port: 6379,
194
- database: 'app-cache'
195
- }]
196
- })
197
-
198
- // Create and register Redis service
199
- const redisService = makeRedisService('redis')
200
- context.registerService(redisService)
201
-
202
- // Initialize context
203
- await context.configure().init()
204
-
205
- // Use Redis
206
- const db = await redisService.db('main-cache')
207
- await db.client.set('key', 'value')
208
- ```
209
-
210
- ### Using appendRedis Helper
211
-
212
- ```typescript
213
- import { appendRedis } from '@owlmeans/redis'
214
-
215
- const context = makeServerContext(config)
216
- const contextWithRedis = appendRedis(context)
217
-
218
- await contextWithRedis.configure().init()
219
-
220
- const redisService = context.service('redis')
221
- const db = await redisService.db()
222
- ```
223
-
224
- ### Session Storage
225
-
226
- ```typescript
227
- // Configure Redis for session storage
228
- const sessionConfig = {
229
- alias: 'session-store',
230
- service: 'redis',
231
- host: 'localhost',
232
- port: 6379,
233
- database: 'sessions'
234
- }
235
-
236
- const redisService = makeRedisService('redis')
237
- await redisService.initialize('session-store')
238
-
239
- const db = await redisService.db('session-store')
240
-
241
- // Store session data
242
- const sessionId = 'sess_123456'
243
- const sessionData = {
244
- userId: 'user_789',
245
- loginTime: Date.now(),
246
- permissions: ['read', 'write']
247
- }
248
-
249
- await db.client.setex(`session:${sessionId}`, 3600, JSON.stringify(sessionData))
250
-
251
- // Retrieve session data
252
- const rawSession = await db.client.get(`session:${sessionId}`)
253
- const session = JSON.parse(rawSession)
254
- ```
255
-
256
- ### Caching with TTL
257
-
258
- ```typescript
259
- const cacheService = makeRedisService('cache')
260
- await cacheService.initialize('cache-config')
261
-
262
- const db = await cacheService.db('cache-config')
263
-
264
- // Cache with expiration
265
- await db.client.setex('user:profile:123', 300, JSON.stringify(userProfile)) // 5 minutes
266
-
267
- // Cache with complex data structures
268
- await db.client.hmset('stats:daily', {
269
- visitors: 1234,
270
- pageViews: 5678,
271
- lastUpdated: Date.now()
272
- })
273
- await db.client.expire('stats:daily', 86400) // 24 hours
274
-
275
- // Get cached data
276
- const cachedProfile = await db.client.get('user:profile:123')
277
- const stats = await db.client.hgetall('stats:daily')
278
- ```
279
-
280
- ### Multi-Configuration Setup
281
-
282
- ```typescript
283
- const context = makeServerContext({
284
- service: 'multi-redis-app',
285
- type: AppType.Backend,
286
- layer: Layer.Service,
287
- dbs: [
288
- {
289
- alias: 'session-store',
290
- service: 'redis',
291
- host: 'sessions.redis.example.com',
292
- database: 'sessions',
293
- meta: { db: 0 }
294
- },
295
- {
296
- alias: 'cache-store',
297
- service: 'redis',
298
- host: 'cache.redis.example.com',
299
- database: 'cache',
300
- meta: { db: 1 }
301
- }
302
- ]
303
- })
304
-
305
- const redisService = makeRedisService('redis')
306
- context.registerService(redisService)
307
-
308
- await context.configure().init()
309
-
310
- // Use different Redis instances
311
- const sessionDb = await redisService.db('session-store')
312
- const cacheDb = await redisService.db('cache-store')
313
-
314
- // Operations are isolated by configuration
315
- await sessionDb.client.set('user:session', sessionData)
316
- await cacheDb.client.set('user:profile', profileData)
317
- ```
318
-
319
- ### Cluster Configuration
320
-
321
- ```typescript
322
- const clusterConfig = {
323
- service: 'cluster-app',
324
- type: AppType.Backend,
325
- layer: Layer.Service,
326
- dbs: [{
327
- alias: 'cluster-cache',
328
- service: 'redis',
329
- host: [
330
- 'redis1.cluster.example.com',
331
- 'redis2.cluster.example.com',
332
- 'redis3.cluster.example.com'
333
- ],
334
- port: 6379,
335
- database: 'clustered-cache',
336
- meta: {
337
- enableReadyCheck: true,
338
- maxRetriesPerRequest: 3,
339
- retryDelayOnFailover: 100,
340
- masterNumber: 3,
341
- slaveNumber: 6
29
+ ```json
30
+ {
31
+ "dbs": {
32
+ "redis": {
33
+ "host": "localhost",
34
+ "port": 6379
342
35
  }
343
- }]
344
- }
345
-
346
- const context = makeServerContext(clusterConfig)
347
- const redisService = makeRedisService('redis')
348
- context.registerService(redisService)
349
-
350
- // Service automatically handles cluster setup
351
- await context.configure().init()
352
-
353
- const db = await redisService.db('cluster-cache')
354
- // Operations work transparently across cluster
355
- ```
356
-
357
- ### Service Reinitialization
358
-
359
- ```typescript
360
- // Original context
361
- const originalContext = makeServerContext(config)
362
- const redisService = makeRedisService()
363
- originalContext.registerService(redisService)
364
-
365
- // Later, reinitialize with new context
366
- const newContext = makeServerContext(newConfig)
367
- const reinitializedService = redisService.reinitializeContext(newContext)
368
-
369
- // Service now uses new context configuration
370
- await reinitializedService.initialize()
371
- ```
372
-
373
- ### Pub/Sub Operations
374
-
375
- ```typescript
376
- const redisService = makeRedisService('pubsub')
377
- await redisService.initialize('pubsub-config')
378
-
379
- const db = await redisService.db('pubsub-config')
380
-
381
- // Subscribe to channels
382
- await db.client.subscribe('notifications')
383
- db.client.on('message', (channel, message) => {
384
- console.log(`Received from ${channel}: ${message}`)
385
- })
386
-
387
- // Publish messages
388
- await db.client.publish('notifications', JSON.stringify({
389
- type: 'user-login',
390
- userId: '123',
391
- timestamp: Date.now()
392
- }))
393
- ```
394
-
395
- ## Configuration
396
-
397
- Redis service configuration is handled through the server context's database configuration:
398
-
399
- ```typescript
400
- interface DatabaseConfig {
401
- alias: string // Configuration alias
402
- service: string // Service name ('redis')
403
- host: string | string[] // Redis host(s)
404
- port?: number // Redis port
405
- database: string // Database prefix/namespace
406
- username?: string // Authentication username
407
- password?: string // Authentication password
408
- serviceSensitive?: boolean // Enable service-layer isolation
409
- entitySensitive?: boolean // Enable entity-layer isolation
410
- meta?: RedisMeta // Redis-specific options
411
- }
412
- ```
413
-
414
- ### Redis-Specific Meta Options
415
-
416
- ```typescript
417
- interface RedisMeta extends RedisOptions {
418
- masterNumber?: number // Master node count for cluster
419
- slaveNumber?: number // Slave node count for cluster
420
- // Plus all ioredis options:
421
- db?: number // Redis database number
422
- connectTimeout?: number // Connection timeout
423
- commandTimeout?: number // Command timeout
424
- retryDelayOnFailover?: number // Failover retry delay
425
- enableReadyCheck?: boolean // Enable ready check
426
- maxRetriesPerRequest?: number // Max retries per request
427
- // ... and many more ioredis options
428
- }
429
- ```
430
-
431
- ## Error Handling
432
-
433
- The package provides descriptive error messages for common issues:
434
-
435
- - **Client replacement**: Thrown when attempting to replace existing Redis client
436
- - **Context assertion**: Thrown when service context is invalid
437
- - **Connection errors**: Propagated from ioredis client
438
-
439
- ```typescript
440
- try {
441
- await redisService.initialize('config-alias')
442
- } catch (error) {
443
- if (error.message.includes('Cannot replace existing redis client')) {
444
- // Handle client replacement error
445
36
  }
446
37
  }
447
38
  ```
448
39
 
449
- ## Performance Considerations
40
+ ## API
450
41
 
451
- - **Connection Pooling**: ioredis handles connection pooling automatically
452
- - **Client Duplication**: Each db() call creates a duplicate client for isolation
453
- - **Cluster Latency**: Cluster setup may add initialization time
454
- - **Memory Usage**: Multiple Redis connections increase memory usage
455
- - **Key Prefixing**: Adds minimal overhead for namespace isolation
42
+ ### `makeRedisService(alias?): RedisDbService`
456
43
 
457
- ## Security Considerations
44
+ Creates the Redis service. `alias` defaults to `DEFAULT_ALIAS` (`'redis'`).
458
45
 
459
- ### Connection Security
460
- - Use authentication credentials for production Redis instances
461
- - Configure TLS/SSL for Redis connections when needed
462
- - Restrict Redis access to necessary IP addresses
46
+ ### `appendRedis<C, T>(context, alias?): T`
463
47
 
464
- ### Data Security
465
- - Be cautious with sensitive data in Redis (consider encryption)
466
- - Use appropriate TTL values to limit data exposure time
467
- - Implement proper access controls at the application level
48
+ Registers the Redis service in the context.
468
49
 
469
- ### Namespace Isolation
470
- - Use layer-sensitive configurations for multi-tenant applications
471
- - Leverage prefix management for data isolation between services
50
+ ### `RedisMeta`
472
51
 
473
- ## Integration with OwlMeans Ecosystem
474
-
475
- This package integrates with:
476
-
477
- - **@owlmeans/redis-resource**: Base Redis resource types and interfaces
478
- - **@owlmeans/server-context**: Server context and configuration management
479
- - **@owlmeans/resource**: Base resource service patterns
480
- - **@owlmeans/mongo**: For multi-database architectures
481
-
482
- ## Best Practices
483
-
484
- 1. **Use appropriate TTL values** for cached data to prevent memory bloat
485
- 2. **Configure clustering** for production high-availability
486
- 3. **Separate Redis configurations** by use case (cache vs sessions vs pub/sub)
487
- 4. **Monitor Redis memory usage** and implement eviction policies
488
- 5. **Use connection pooling** efficiently with proper client management
52
+ Extends `RedisOptions` (ioredis) all ioredis connection options are supported in config.
489
53
 
490
54
  ## Related Packages
491
55
 
492
- - **@owlmeans/redis-resource**: Base Redis resource definitions
493
- - **@owlmeans/mongo**: MongoDB service implementation
494
- - **@owlmeans/server-context**: Server context management
495
- - **@owlmeans/resource**: Base resource service patterns
496
-
497
- ## Redis Use Cases
498
-
499
- ### Caching
500
- - API response caching
501
- - Database query result caching
502
- - Computed value caching
503
-
504
- ### Session Storage
505
- - User session management
506
- - Authentication token storage
507
- - Shopping cart persistence
508
-
509
- ### Real-time Features
510
- - Pub/Sub messaging
511
- - Live notifications
512
- - Real-time analytics
513
-
514
- ### Rate Limiting
515
- - API rate limiting
516
- - Request throttling
517
- - Usage tracking
56
+ - [`@owlmeans/redis-resource`](../redis-resource) pub/sub and streaming resources over this service
57
+ - [`@owlmeans/server-auth`](../server-auth) `AUTH_CACHE` redis resource for auth token caching
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@owlmeans/redis",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
+ "license": "MIT",
4
5
  "type": "module",
5
6
  "scripts": {
6
7
  "build": "tsc -b",
@@ -20,16 +21,17 @@
20
21
  }
21
22
  },
22
23
  "devDependencies": {
24
+ "@owlmeans/dep-config": "workspace:*",
23
25
  "@types/node": "^24.10.1",
24
26
  "nodemon": "^3.1.11",
25
- "typescript": "^5.8.3"
27
+ "typescript": "^6.0.2"
26
28
  },
27
29
  "dependencies": {
28
30
  "@noble/hashes": "^1.5.0",
29
- "@owlmeans/context": "^0.1.1",
30
- "@owlmeans/redis-resource": "^0.1.1",
31
- "@owlmeans/resource": "^0.1.1",
32
- "@owlmeans/server-context": "^0.1.1",
31
+ "@owlmeans/context": "^0.1.3",
32
+ "@owlmeans/redis-resource": "^0.1.3",
33
+ "@owlmeans/resource": "^0.1.3",
34
+ "@owlmeans/server-context": "^0.1.3",
33
35
  "@scure/base": "^1.1.9",
34
36
  "ioredis": "^5.4.1"
35
37
  },
package/tsconfig.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "extends": [
3
- "../tsconfig.default.json",
3
+ "@owlmeans/dep-config/tsconfig.base.json",
4
+ "@owlmeans/dep-config/tsconfig.node.json"
4
5
  ],
5
6
  "compilerOptions": {
6
- "rootDir": "./src/", /* Specify the root folder within your source files. */
7
- "outDir": "./build/", /* Specify an output folder for all emitted files. */
7
+ "rootDir": "./src/",
8
+ "outDir": "./build/"
8
9
  },
9
10
  "exclude": [
10
11
  "./dist/**/*",
11
12
  "./build/**/*",
12
13
  "./*.ts"
13
14
  ]
14
- }
15
+ }