@b9g/cache-redis 0.1.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/README.md +195 -0
- package/package.json +74 -0
- package/src/factory.cjs +34 -0
- package/src/factory.d.ts +19 -0
- package/src/factory.js +11 -0
- package/src/index.cjs +32 -0
- package/src/index.d.ts +7 -0
- package/src/index.js +8 -0
- package/src/redis-cache.cjs +18208 -0
- package/src/redis-cache.d.ts +71 -0
- package/src/redis-cache.js +228 -0
package/README.md
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# @b9g/cache-redis
|
|
2
|
+
|
|
3
|
+
Redis cache adapter for Shovel's universal cache system.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **HTTP-aware caching**: Stores complete HTTP responses with headers and status codes
|
|
8
|
+
- **TTL support**: Configurable time-to-live for cache entries
|
|
9
|
+
- **Size limits**: Configurable maximum entry size to prevent memory issues
|
|
10
|
+
- **Connection pooling**: Uses the official Redis client with connection management
|
|
11
|
+
- **Error resilience**: Graceful handling of Redis connection issues
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun install @b9g/cache-redis
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Basic Usage
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import {CustomCacheStorage} from "@b9g/cache";
|
|
25
|
+
import {createRedisFactory} from "@b9g/cache-redis";
|
|
26
|
+
|
|
27
|
+
// Create cache storage with Redis backend
|
|
28
|
+
const cacheStorage = new CustomCacheStorage(createRedisFactory({
|
|
29
|
+
redis: {
|
|
30
|
+
url: "redis://localhost:6379"
|
|
31
|
+
},
|
|
32
|
+
defaultTTL: 3600, // 1 hour
|
|
33
|
+
prefix: "myapp"
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
// Use the cache
|
|
37
|
+
const cache = await cacheStorage.open("pages");
|
|
38
|
+
await cache.put(request, response);
|
|
39
|
+
const cached = await cache.match(request);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### With Platform Integration
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import {CustomCacheStorage} from "@b9g/cache";
|
|
46
|
+
import {createRedisFactory} from "@b9g/cache-redis";
|
|
47
|
+
|
|
48
|
+
// In your platform configuration
|
|
49
|
+
const platform = createBunPlatform({
|
|
50
|
+
cache: {
|
|
51
|
+
factory: createRedisFactory({
|
|
52
|
+
redis: {
|
|
53
|
+
url: process.env.REDIS_URL || "redis://localhost:6379",
|
|
54
|
+
password: process.env.REDIS_PASSWORD
|
|
55
|
+
},
|
|
56
|
+
defaultTTL: 3600,
|
|
57
|
+
maxEntrySize: 5 * 1024 * 1024 // 5MB max per entry
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Configuration Options
|
|
64
|
+
|
|
65
|
+
### RedisCacheOptions
|
|
66
|
+
|
|
67
|
+
- `redis?: RedisClientOptions` - Redis connection configuration
|
|
68
|
+
- `prefix?: string` - Key prefix for Redis keys (default: "cache")
|
|
69
|
+
- `defaultTTL?: number` - Default TTL in seconds (0 = no expiration)
|
|
70
|
+
- `maxEntrySize?: number` - Maximum cache entry size in bytes (default: 10MB)
|
|
71
|
+
|
|
72
|
+
### Redis Connection Options
|
|
73
|
+
|
|
74
|
+
The `redis` option accepts all standard Redis client options:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
{
|
|
78
|
+
redis: {
|
|
79
|
+
url: "redis://localhost:6379",
|
|
80
|
+
password: "your-password",
|
|
81
|
+
database: 0,
|
|
82
|
+
connectTimeout: 10000,
|
|
83
|
+
lazyConnect: true
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Environment Variables
|
|
89
|
+
|
|
90
|
+
Common Redis configuration via environment variables:
|
|
91
|
+
|
|
92
|
+
- `REDIS_URL` - Complete Redis connection URL
|
|
93
|
+
- `REDIS_HOST` - Redis hostname
|
|
94
|
+
- `REDIS_PORT` - Redis port
|
|
95
|
+
- `REDIS_PASSWORD` - Redis password
|
|
96
|
+
- `REDIS_DB` - Redis database number
|
|
97
|
+
|
|
98
|
+
## Performance Considerations
|
|
99
|
+
|
|
100
|
+
### Entry Size Limits
|
|
101
|
+
|
|
102
|
+
Large responses are automatically rejected to prevent memory issues:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const cache = new RedisCache("large-files", {
|
|
106
|
+
maxEntrySize: 1024 * 1024 // 1MB limit
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### TTL Configuration
|
|
111
|
+
|
|
112
|
+
Configure TTL based on your caching strategy:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// Short-lived API responses
|
|
116
|
+
const apiCache = new RedisCache("api", {
|
|
117
|
+
defaultTTL: 300 // 5 minutes
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Long-lived static assets
|
|
121
|
+
const staticCache = new RedisCache("static", {
|
|
122
|
+
defaultTTL: 86400 // 24 hours
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Permanent cache (manual invalidation)
|
|
126
|
+
const permanentCache = new RedisCache("permanent", {
|
|
127
|
+
defaultTTL: 0 // No expiration
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Connection Pooling
|
|
132
|
+
|
|
133
|
+
The Redis client automatically manages connection pooling. For high-traffic applications, consider tuning connection settings:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
{
|
|
137
|
+
redis: {
|
|
138
|
+
socket: {
|
|
139
|
+
connectTimeout: 10000,
|
|
140
|
+
keepAlive: true,
|
|
141
|
+
noDelay: true
|
|
142
|
+
},
|
|
143
|
+
isolationPoolOptions: {
|
|
144
|
+
min: 2,
|
|
145
|
+
max: 10
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Error Handling
|
|
152
|
+
|
|
153
|
+
The Redis cache gracefully handles connection issues:
|
|
154
|
+
|
|
155
|
+
- Failed connections return `undefined` for cache misses
|
|
156
|
+
- Connection errors are logged but don't crash the application
|
|
157
|
+
- Automatic reconnection when Redis becomes available
|
|
158
|
+
|
|
159
|
+
## Cache Statistics
|
|
160
|
+
|
|
161
|
+
Get insights into cache performance:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
const cache = new RedisCache("my-cache");
|
|
165
|
+
const stats = await cache.getStats();
|
|
166
|
+
|
|
167
|
+
console.log({
|
|
168
|
+
connected: stats.connected,
|
|
169
|
+
keyCount: stats.keyCount,
|
|
170
|
+
totalSize: stats.totalSize,
|
|
171
|
+
prefix: stats.prefix
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Cleanup
|
|
176
|
+
|
|
177
|
+
Properly dispose of cache instances:
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// Dispose single cache
|
|
181
|
+
await cache.dispose();
|
|
182
|
+
|
|
183
|
+
// Dispose entire cache storage
|
|
184
|
+
await cacheStorage.dispose();
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Shovel Integration
|
|
188
|
+
|
|
189
|
+
This cache adapter is designed to work seamlessly with Shovel's cache-first architecture:
|
|
190
|
+
|
|
191
|
+
- **Platform agnostic**: Works with any Shovel platform (Bun, Node.js, Cloudflare)
|
|
192
|
+
- **HTTP-aware**: Preserves response headers and status codes
|
|
193
|
+
- **ServiceWorker compatible**: Implements the standard Cache API interface
|
|
194
|
+
|
|
195
|
+
For more information about Shovel's caching system, see the [@b9g/cache](../cache) documentation.
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@b9g/cache-redis",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Redis cache adapter for Shovel cache system",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cache",
|
|
7
|
+
"redis",
|
|
8
|
+
"shovel",
|
|
9
|
+
"metaframework",
|
|
10
|
+
"cache-adapter"
|
|
11
|
+
],
|
|
12
|
+
"author": "Shovel Team",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/b9g/shovel.git",
|
|
17
|
+
"directory": "packages/cache-redis"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"redis": "^4.6.10"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@b9g/libuild": "^0.1.10"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@b9g/cache": "workspace:*"
|
|
27
|
+
},
|
|
28
|
+
"type": "module",
|
|
29
|
+
"types": "src/index.d.ts",
|
|
30
|
+
"files": [
|
|
31
|
+
"README.md",
|
|
32
|
+
"src/"
|
|
33
|
+
],
|
|
34
|
+
"main": "src/index.cjs",
|
|
35
|
+
"module": "src/index.js",
|
|
36
|
+
"exports": {
|
|
37
|
+
".": {
|
|
38
|
+
"types": "./src/index.d.ts",
|
|
39
|
+
"import": "./src/index.js",
|
|
40
|
+
"require": "./src/index.cjs"
|
|
41
|
+
},
|
|
42
|
+
"./factory": {
|
|
43
|
+
"types": "./src/factory.d.ts",
|
|
44
|
+
"import": "./src/factory.js",
|
|
45
|
+
"require": "./src/factory.cjs"
|
|
46
|
+
},
|
|
47
|
+
"./factory.js": {
|
|
48
|
+
"types": "./src/factory.d.ts",
|
|
49
|
+
"import": "./src/factory.js",
|
|
50
|
+
"require": "./src/factory.cjs"
|
|
51
|
+
},
|
|
52
|
+
"./index": {
|
|
53
|
+
"types": "./src/index.d.ts",
|
|
54
|
+
"import": "./src/index.js",
|
|
55
|
+
"require": "./src/index.cjs"
|
|
56
|
+
},
|
|
57
|
+
"./index.js": {
|
|
58
|
+
"types": "./src/index.d.ts",
|
|
59
|
+
"import": "./src/index.js",
|
|
60
|
+
"require": "./src/index.cjs"
|
|
61
|
+
},
|
|
62
|
+
"./redis-cache": {
|
|
63
|
+
"types": "./src/redis-cache.d.ts",
|
|
64
|
+
"import": "./src/redis-cache.js",
|
|
65
|
+
"require": "./src/redis-cache.cjs"
|
|
66
|
+
},
|
|
67
|
+
"./redis-cache.js": {
|
|
68
|
+
"types": "./src/redis-cache.d.ts",
|
|
69
|
+
"import": "./src/redis-cache.js",
|
|
70
|
+
"require": "./src/redis-cache.cjs"
|
|
71
|
+
},
|
|
72
|
+
"./package.json": "./package.json"
|
|
73
|
+
}
|
|
74
|
+
}
|
package/src/factory.cjs
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/factory.ts
|
|
20
|
+
var factory_exports = {};
|
|
21
|
+
__export(factory_exports, {
|
|
22
|
+
createRedisFactory: () => createRedisFactory
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(factory_exports);
|
|
25
|
+
var import_redis_cache = require("./redis-cache.cjs");
|
|
26
|
+
function createRedisFactory(options = {}) {
|
|
27
|
+
return (name) => {
|
|
28
|
+
return new import_redis_cache.RedisCache(name, options);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
32
|
+
0 && (module.exports = {
|
|
33
|
+
createRedisFactory
|
|
34
|
+
});
|
package/src/factory.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type CacheFactory } from "@b9g/cache";
|
|
2
|
+
import { type RedisCacheOptions } from "./redis-cache.js";
|
|
3
|
+
/**
|
|
4
|
+
* Create a Redis cache factory for use with CustomCacheStorage
|
|
5
|
+
*
|
|
6
|
+
* Example usage:
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import {CustomCacheStorage} from "@b9g/cache";
|
|
9
|
+
* import {createRedisFactory} from "@b9g/cache-redis";
|
|
10
|
+
*
|
|
11
|
+
* const cacheStorage = new CustomCacheStorage(createRedisFactory({
|
|
12
|
+
* redis: { url: "redis://localhost:6379" },
|
|
13
|
+
* defaultTTL: 3600 // 1 hour
|
|
14
|
+
* }));
|
|
15
|
+
*
|
|
16
|
+
* const cache = await cacheStorage.open("my-cache");
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function createRedisFactory(options?: RedisCacheOptions): CacheFactory;
|
package/src/factory.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/// <reference types="./factory.d.ts" />
|
|
2
|
+
// src/factory.ts
|
|
3
|
+
import { RedisCache } from "./redis-cache.js";
|
|
4
|
+
function createRedisFactory(options = {}) {
|
|
5
|
+
return (name) => {
|
|
6
|
+
return new RedisCache(name, options);
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
createRedisFactory
|
|
11
|
+
};
|
package/src/index.cjs
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/index.ts
|
|
20
|
+
var src_exports = {};
|
|
21
|
+
__export(src_exports, {
|
|
22
|
+
RedisCache: () => import_redis_cache.RedisCache,
|
|
23
|
+
createRedisFactory: () => import_factory.createRedisFactory
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(src_exports);
|
|
26
|
+
var import_redis_cache = require("./redis-cache.cjs");
|
|
27
|
+
var import_factory = require("./factory.cjs");
|
|
28
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
29
|
+
0 && (module.exports = {
|
|
30
|
+
RedisCache,
|
|
31
|
+
createRedisFactory
|
|
32
|
+
});
|
package/src/index.d.ts
ADDED