@wgtechlabs/nuvex 0.1.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/LICENSE +21 -0
- package/README.md +427 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/cjs/core/client.js +981 -0
- package/dist/cjs/core/client.js.map +1 -0
- package/dist/cjs/core/database.js +297 -0
- package/dist/cjs/core/database.js.map +1 -0
- package/dist/cjs/core/engine.js +1202 -0
- package/dist/cjs/core/engine.js.map +1 -0
- package/dist/cjs/core/index.js +35 -0
- package/dist/cjs/core/index.js.map +1 -0
- package/dist/cjs/index.js +109 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/interfaces/index.js +12 -0
- package/dist/cjs/interfaces/index.js.map +1 -0
- package/dist/cjs/layers/index.js +22 -0
- package/dist/cjs/layers/index.js.map +1 -0
- package/dist/cjs/layers/memory.js +388 -0
- package/dist/cjs/layers/memory.js.map +1 -0
- package/dist/cjs/layers/postgres.js +492 -0
- package/dist/cjs/layers/postgres.js.map +1 -0
- package/dist/cjs/layers/redis.js +388 -0
- package/dist/cjs/layers/redis.js.map +1 -0
- package/dist/cjs/types/index.js +52 -0
- package/dist/cjs/types/index.js.map +1 -0
- package/dist/esm/core/client.js +944 -0
- package/dist/esm/core/client.js.map +1 -0
- package/dist/esm/core/database.js +289 -0
- package/dist/esm/core/database.js.map +1 -0
- package/dist/esm/core/engine.js +1198 -0
- package/dist/esm/core/engine.js.map +1 -0
- package/dist/esm/core/index.js +16 -0
- package/dist/esm/core/index.js.map +1 -0
- package/dist/esm/index.js +87 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/interfaces/index.js +11 -0
- package/dist/esm/interfaces/index.js.map +1 -0
- package/dist/esm/layers/index.js +16 -0
- package/dist/esm/layers/index.js.map +1 -0
- package/dist/esm/layers/memory.js +384 -0
- package/dist/esm/layers/memory.js.map +1 -0
- package/dist/esm/layers/postgres.js +485 -0
- package/dist/esm/layers/postgres.js.map +1 -0
- package/dist/esm/layers/redis.js +384 -0
- package/dist/esm/layers/redis.js.map +1 -0
- package/dist/esm/types/index.js +49 -0
- package/dist/esm/types/index.js.map +1 -0
- package/dist/types/core/client.d.ts +561 -0
- package/dist/types/core/client.d.ts.map +1 -0
- package/dist/types/core/database.d.ts +130 -0
- package/dist/types/core/database.d.ts.map +1 -0
- package/dist/types/core/engine.d.ts +450 -0
- package/dist/types/core/engine.d.ts.map +1 -0
- package/dist/types/core/index.d.ts +13 -0
- package/dist/types/core/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +85 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/interfaces/index.d.ts +209 -0
- package/dist/types/interfaces/index.d.ts.map +1 -0
- package/dist/types/layers/index.d.ts +16 -0
- package/dist/types/layers/index.d.ts.map +1 -0
- package/dist/types/layers/memory.d.ts +261 -0
- package/dist/types/layers/memory.d.ts.map +1 -0
- package/dist/types/layers/postgres.d.ts +313 -0
- package/dist/types/layers/postgres.d.ts.map +1 -0
- package/dist/types/layers/redis.d.ts +248 -0
- package/dist/types/layers/redis.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +410 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/package.json +90 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuvex - PostgreSQL Storage Layer (L3)
|
|
3
|
+
* Next-gen Unified Vault Experience
|
|
4
|
+
*
|
|
5
|
+
* PostgreSQL persistent storage layer serving as the source of truth for all data.
|
|
6
|
+
* Provides ACID-compliant, durable storage with full data integrity guarantees.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - ACID-compliant persistent storage
|
|
10
|
+
* - Source of truth for all data
|
|
11
|
+
* - JSON support for flexible data structures
|
|
12
|
+
* - Automatic TTL-based expiration
|
|
13
|
+
* - Connection pooling for optimal performance
|
|
14
|
+
* - Health monitoring with SELECT 1 queries
|
|
15
|
+
*
|
|
16
|
+
* @author Waren Gonzaga, WG Technology Labs
|
|
17
|
+
* @since 2025
|
|
18
|
+
*/
|
|
19
|
+
import type { Pool as PoolType } from 'pg';
|
|
20
|
+
import type { StorageLayerInterface, Logger } from '../interfaces/index.js';
|
|
21
|
+
import type { PostgresConfig } from '../types/index.js';
|
|
22
|
+
/**
|
|
23
|
+
* PostgreSQL Storage Layer - L3 Persistent Storage
|
|
24
|
+
*
|
|
25
|
+
* Implements persistent storage using PostgreSQL. This is the authoritative
|
|
26
|
+
* source of truth for all data in the system. All writes must succeed here
|
|
27
|
+
* for the operation to be considered successful.
|
|
28
|
+
*
|
|
29
|
+
* **Key Features:**
|
|
30
|
+
* - ACID compliance for data integrity
|
|
31
|
+
* - Durable storage that survives restarts
|
|
32
|
+
* - JSON/JSONB support for complex objects
|
|
33
|
+
* - TTL-based automatic expiration
|
|
34
|
+
* - Connection pooling for performance
|
|
35
|
+
* - Transaction support for complex operations
|
|
36
|
+
*
|
|
37
|
+
* **Storage Schema:**
|
|
38
|
+
* - Table: nuvex_storage
|
|
39
|
+
* - Columns: id, key (unique), value (JSONB), expires_at, created_at, updated_at
|
|
40
|
+
* - Indexes: key, expires_at, key pattern (trigram)
|
|
41
|
+
*
|
|
42
|
+
* **Performance Characteristics:**
|
|
43
|
+
* - Get: O(log n) with index lookup
|
|
44
|
+
* - Set: O(log n) with index update
|
|
45
|
+
* - Latency: 5-50ms typical (storage + network)
|
|
46
|
+
*
|
|
47
|
+
* **Error Handling:**
|
|
48
|
+
* - Returns null on read errors (graceful degradation)
|
|
49
|
+
* - Logs errors for monitoring
|
|
50
|
+
* - Throws on critical connection failures
|
|
51
|
+
*
|
|
52
|
+
* @implements {StorageLayerInterface}
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* // Create PostgreSQL layer
|
|
57
|
+
* const postgres = new PostgresStorage({
|
|
58
|
+
* host: 'localhost',
|
|
59
|
+
* port: 5432,
|
|
60
|
+
* database: 'myapp',
|
|
61
|
+
* user: 'postgres',
|
|
62
|
+
* password: 'password'
|
|
63
|
+
* });
|
|
64
|
+
*
|
|
65
|
+
* // Connect (creates pool)
|
|
66
|
+
* await postgres.connect();
|
|
67
|
+
*
|
|
68
|
+
* // Store data (source of truth)
|
|
69
|
+
* await postgres.set('user:123', userData, 86400);
|
|
70
|
+
*
|
|
71
|
+
* // Retrieve data
|
|
72
|
+
* const data = await postgres.get('user:123');
|
|
73
|
+
*
|
|
74
|
+
* // Check health
|
|
75
|
+
* const isHealthy = await postgres.ping();
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @class PostgresStorage
|
|
79
|
+
* @since 1.0.0
|
|
80
|
+
*/
|
|
81
|
+
export declare class PostgresStorage implements StorageLayerInterface {
|
|
82
|
+
/** PostgreSQL connection pool */
|
|
83
|
+
private pool;
|
|
84
|
+
/** Database configuration or existing pool */
|
|
85
|
+
private readonly config;
|
|
86
|
+
/** Whether the pool is connected */
|
|
87
|
+
private connected;
|
|
88
|
+
/** Optional logger for debugging and monitoring */
|
|
89
|
+
private logger;
|
|
90
|
+
/** Whether we created the pool (vs. received existing one) */
|
|
91
|
+
private readonly ownsPool;
|
|
92
|
+
/** Table name for storage */
|
|
93
|
+
private readonly tableName;
|
|
94
|
+
/** Key column name */
|
|
95
|
+
private readonly keyColumn;
|
|
96
|
+
/** Value/data column name */
|
|
97
|
+
private readonly valueColumn;
|
|
98
|
+
/**
|
|
99
|
+
* Creates a new PostgresStorage instance
|
|
100
|
+
*
|
|
101
|
+
* Accepts either a PostgreSQL configuration object or an existing Pool instance.
|
|
102
|
+
* If a Pool is provided, the caller is responsible for managing its lifecycle.
|
|
103
|
+
*
|
|
104
|
+
* Schema configuration is extracted from the config object when creating a new pool.
|
|
105
|
+
* When using an existing pool, schema defaults to standard Nuvex naming.
|
|
106
|
+
*
|
|
107
|
+
* @param config - PostgreSQL configuration or existing Pool instance
|
|
108
|
+
* @param logger - Optional logger for debugging
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* // With configuration (supports schema customization)
|
|
113
|
+
* const postgres = new PostgresStorage({
|
|
114
|
+
* host: 'localhost',
|
|
115
|
+
* database: 'myapp',
|
|
116
|
+
* user: 'postgres',
|
|
117
|
+
* password: 'password',
|
|
118
|
+
* schema: {
|
|
119
|
+
* tableName: 'storage_cache',
|
|
120
|
+
* columns: { key: 'key', value: 'value' }
|
|
121
|
+
* }
|
|
122
|
+
* });
|
|
123
|
+
*
|
|
124
|
+
* // With existing pool (uses default schema)
|
|
125
|
+
* const existingPool = new Pool({ ... });
|
|
126
|
+
* const postgres = new PostgresStorage(existingPool);
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
constructor(config: PostgresConfig | PoolType, logger?: Logger | null);
|
|
130
|
+
/**
|
|
131
|
+
* Establish connection to PostgreSQL
|
|
132
|
+
*
|
|
133
|
+
* Creates a connection pool (if not already provided) and tests the connection.
|
|
134
|
+
* Should be called before any storage operations.
|
|
135
|
+
*
|
|
136
|
+
* @throws {Error} If connection test fails
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* try {
|
|
141
|
+
* await postgres.connect();
|
|
142
|
+
* console.log('PostgreSQL connected');
|
|
143
|
+
* } catch (error) {
|
|
144
|
+
* console.error('PostgreSQL connection failed:', error);
|
|
145
|
+
* }
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
connect(): Promise<void>;
|
|
149
|
+
/**
|
|
150
|
+
* Close PostgreSQL connection pool
|
|
151
|
+
*
|
|
152
|
+
* Only closes the pool if we created it. If an existing pool was provided,
|
|
153
|
+
* the caller is responsible for closing it.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* await postgres.disconnect();
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
disconnect(): Promise<void>;
|
|
161
|
+
/**
|
|
162
|
+
* Retrieve a value from PostgreSQL
|
|
163
|
+
*
|
|
164
|
+
* Queries the nuvex_storage table and automatically filters out expired entries.
|
|
165
|
+
* Deserializes the JSON-stored value.
|
|
166
|
+
*
|
|
167
|
+
* @param key - The key to retrieve
|
|
168
|
+
* @returns Promise resolving to the value or null if not found/expired
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* const userData = await postgres.get('user:123');
|
|
173
|
+
* if (userData !== null) {
|
|
174
|
+
* console.log('Found in PostgreSQL');
|
|
175
|
+
* }
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
get(key: string): Promise<unknown>;
|
|
179
|
+
/**
|
|
180
|
+
* Store a value in PostgreSQL
|
|
181
|
+
*
|
|
182
|
+
* Inserts or updates the value in the nuvex_storage table. Uses UPSERT
|
|
183
|
+
* (INSERT ... ON CONFLICT) to handle existing keys efficiently.
|
|
184
|
+
*
|
|
185
|
+
* **Note:** This is the authoritative write. If this fails, the entire
|
|
186
|
+
* write operation should be considered failed.
|
|
187
|
+
*
|
|
188
|
+
* @param key - The key to store
|
|
189
|
+
* @param value - The value to store (will be JSON serialized)
|
|
190
|
+
* @param ttlSeconds - Optional TTL in seconds
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```typescript
|
|
194
|
+
* // Store with 24 hour TTL
|
|
195
|
+
* await postgres.set('user:123', userData, 86400);
|
|
196
|
+
*
|
|
197
|
+
* // Store without TTL (persists until deleted)
|
|
198
|
+
* await postgres.set('config:app', configData);
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
set(key: string, value: unknown, ttlSeconds?: number): Promise<void>;
|
|
202
|
+
/**
|
|
203
|
+
* Delete a value from PostgreSQL
|
|
204
|
+
*
|
|
205
|
+
* Permanently removes the key from the nuvex_storage table.
|
|
206
|
+
*
|
|
207
|
+
* @param key - The key to delete
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```typescript
|
|
211
|
+
* await postgres.delete('user:123');
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
delete(key: string): Promise<void>;
|
|
215
|
+
/**
|
|
216
|
+
* Check if a key exists in PostgreSQL
|
|
217
|
+
*
|
|
218
|
+
* Queries for the key and verifies it hasn't expired.
|
|
219
|
+
*
|
|
220
|
+
* @param key - The key to check
|
|
221
|
+
* @returns Promise resolving to true if the key exists and is not expired
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```typescript
|
|
225
|
+
* if (await postgres.exists('user:123')) {
|
|
226
|
+
* console.log('Key exists in PostgreSQL');
|
|
227
|
+
* }
|
|
228
|
+
* ```
|
|
229
|
+
*/
|
|
230
|
+
exists(key: string): Promise<boolean>;
|
|
231
|
+
/**
|
|
232
|
+
* Clear all keys from PostgreSQL
|
|
233
|
+
*
|
|
234
|
+
* **WARNING:** This operation deletes all data from nuvex_storage table.
|
|
235
|
+
* Use with extreme caution in production environments.
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```typescript
|
|
239
|
+
* await postgres.clear(); // Deletes all data
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
clear(): Promise<void>;
|
|
243
|
+
/**
|
|
244
|
+
* Health check for PostgreSQL connection
|
|
245
|
+
*
|
|
246
|
+
* Executes a simple SELECT 1 query to verify connectivity and database
|
|
247
|
+
* responsiveness. This is a lightweight operation that tests the full
|
|
248
|
+
* connection path including pool, connection, and database.
|
|
249
|
+
*
|
|
250
|
+
* @returns Promise resolving to true if PostgreSQL is healthy and responsive
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```typescript
|
|
254
|
+
* const isHealthy = await postgres.ping();
|
|
255
|
+
* if (!isHealthy) {
|
|
256
|
+
* console.error('PostgreSQL connection is down');
|
|
257
|
+
* }
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
ping(): Promise<boolean>;
|
|
261
|
+
/**
|
|
262
|
+
* Check if PostgreSQL is connected
|
|
263
|
+
*
|
|
264
|
+
* @returns True if connected
|
|
265
|
+
*/
|
|
266
|
+
isConnected(): boolean;
|
|
267
|
+
/**
|
|
268
|
+
* Get the PostgreSQL connection pool
|
|
269
|
+
*
|
|
270
|
+
* Useful for executing custom queries or transactions.
|
|
271
|
+
*
|
|
272
|
+
* @returns The connection pool or null if not connected
|
|
273
|
+
*
|
|
274
|
+
* @example
|
|
275
|
+
* ```typescript
|
|
276
|
+
* const pool = postgres.getPool();
|
|
277
|
+
* if (pool) {
|
|
278
|
+
* const result = await pool.query('SELECT * FROM custom_table');
|
|
279
|
+
* }
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
282
|
+
getPool(): PoolType | null;
|
|
283
|
+
/**
|
|
284
|
+
* Atomically increment a numeric value
|
|
285
|
+
*
|
|
286
|
+
* Uses PostgreSQL UPDATE with row-level locking for true atomic increments.
|
|
287
|
+
* If the key doesn't exist, it's created with the delta value.
|
|
288
|
+
*
|
|
289
|
+
* This operation is safe for concurrent access across multiple instances.
|
|
290
|
+
*
|
|
291
|
+
* @param key - The key to increment
|
|
292
|
+
* @param delta - The amount to increment by
|
|
293
|
+
* @param ttlSeconds - Optional TTL in seconds
|
|
294
|
+
* @returns Promise resolving to the new value after increment
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* ```typescript
|
|
298
|
+
* // Atomic increment - safe for concurrent access
|
|
299
|
+
* const newValue = await postgres.increment('counter', 1, 86400);
|
|
300
|
+
* ```
|
|
301
|
+
*/
|
|
302
|
+
increment(key: string, delta: number, ttlSeconds?: number): Promise<number>;
|
|
303
|
+
/**
|
|
304
|
+
* Log a message if logger is configured
|
|
305
|
+
*
|
|
306
|
+
* @private
|
|
307
|
+
* @param level - Log level
|
|
308
|
+
* @param message - Log message
|
|
309
|
+
* @param meta - Optional metadata
|
|
310
|
+
*/
|
|
311
|
+
private log;
|
|
312
|
+
}
|
|
313
|
+
//# sourceMappingURL=postgres.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../../src/layers/postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAC3C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,qBAAa,eAAgB,YAAW,qBAAqB;IAC3D,iCAAiC;IACjC,OAAO,CAAC,IAAI,CAAkB;IAE9B,8CAA8C;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IAEnD,oCAAoC;IACpC,OAAO,CAAC,SAAS,CAAU;IAE3B,mDAAmD;IACnD,OAAO,CAAC,MAAM,CAAgB;IAE9B,8DAA8D;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IAEnC,6BAA6B;IAC7B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,sBAAsB;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,6BAA6B;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;gBACS,MAAM,EAAE,cAAc,GAAG,QAAQ,EAAE,MAAM,GAAE,MAAM,GAAG,IAAW;IAsB3E;;;;;;;;;;;;;;;;;OAiBG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB9B;;;;;;;;;;OAUG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC;;;;;;;;;;;;;;;;OAgBG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA0BxC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB1E;;;;;;;;;;;OAWG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcxC;;;;;;;;;;;;;;OAcG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAoB3C;;;;;;;;;;OAUG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAe5B;;;;;;;;;;;;;;;;OAgBG;IACG,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IAuB9B;;;;OAIG;IACH,WAAW,IAAI,OAAO;IAItB;;;;;;;;;;;;;;OAcG;IACH,OAAO,IAAI,QAAQ,GAAG,IAAI;IAI1B;;;;;;;;;;;;;;;;;;OAkBG;IACG,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA0CjF;;;;;;;OAOG;IACH,OAAO,CAAC,GAAG;CAKZ"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuvex - Redis Storage Layer (L2)
|
|
3
|
+
* Next-gen Unified Vault Experience
|
|
4
|
+
*
|
|
5
|
+
* Redis distributed cache layer providing fast, persistent caching across
|
|
6
|
+
* multiple application instances. Acts as the middle tier in the storage hierarchy.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Distributed caching for multi-instance deployments
|
|
10
|
+
* - Fast access times (1-5ms typical)
|
|
11
|
+
* - Automatic TTL-based expiration
|
|
12
|
+
* - Connection health monitoring
|
|
13
|
+
* - Graceful degradation on failures
|
|
14
|
+
*
|
|
15
|
+
* @author Waren Gonzaga, WG Technology Labs
|
|
16
|
+
* @since 2025
|
|
17
|
+
*/
|
|
18
|
+
import type { StorageLayerInterface, Logger } from '../interfaces/index.js';
|
|
19
|
+
/**
|
|
20
|
+
* Redis Storage Layer - L2 Distributed Cache
|
|
21
|
+
*
|
|
22
|
+
* Implements distributed caching using Redis. This layer provides fast access
|
|
23
|
+
* to frequently used data while supporting multiple application instances.
|
|
24
|
+
* Redis data persists across application restarts (depending on Redis configuration).
|
|
25
|
+
*
|
|
26
|
+
* **Key Features:**
|
|
27
|
+
* - Distributed cache shared across instances
|
|
28
|
+
* - Configurable TTL for automatic expiration
|
|
29
|
+
* - JSON serialization for complex objects
|
|
30
|
+
* - Graceful error handling with logging
|
|
31
|
+
* - Connection health monitoring via PING
|
|
32
|
+
*
|
|
33
|
+
* **Performance Characteristics:**
|
|
34
|
+
* - Get: O(1) network + Redis lookup
|
|
35
|
+
* - Set: O(1) network + Redis write
|
|
36
|
+
* - Latency: 1-5ms typical (network dependent)
|
|
37
|
+
*
|
|
38
|
+
* **Error Handling:**
|
|
39
|
+
* - Returns null on connection failures
|
|
40
|
+
* - Logs errors for monitoring
|
|
41
|
+
* - Doesn't throw to allow graceful degradation
|
|
42
|
+
*
|
|
43
|
+
* @implements {StorageLayerInterface}
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* // Create Redis layer
|
|
48
|
+
* const redis = new RedisStorage('redis://localhost:6379');
|
|
49
|
+
*
|
|
50
|
+
* // Connect to Redis
|
|
51
|
+
* await redis.connect();
|
|
52
|
+
*
|
|
53
|
+
* // Store with 5 minute TTL
|
|
54
|
+
* await redis.set('session:abc', sessionData, 300);
|
|
55
|
+
*
|
|
56
|
+
* // Retrieve data
|
|
57
|
+
* const data = await redis.get('session:abc');
|
|
58
|
+
*
|
|
59
|
+
* // Check health
|
|
60
|
+
* const isHealthy = await redis.ping();
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* @class RedisStorage
|
|
64
|
+
* @since 1.0.0
|
|
65
|
+
*/
|
|
66
|
+
export declare class RedisStorage implements StorageLayerInterface {
|
|
67
|
+
/** Redis client instance */
|
|
68
|
+
private client;
|
|
69
|
+
/** Redis connection URL */
|
|
70
|
+
private readonly url;
|
|
71
|
+
/** Whether the client is connected */
|
|
72
|
+
private connected;
|
|
73
|
+
/** Optional logger for debugging and monitoring */
|
|
74
|
+
private logger;
|
|
75
|
+
/**
|
|
76
|
+
* Creates a new RedisStorage instance
|
|
77
|
+
*
|
|
78
|
+
* Note: The instance is created but not connected. Call connect() to establish
|
|
79
|
+
* the Redis connection.
|
|
80
|
+
*
|
|
81
|
+
* @param url - Redis connection URL (e.g., redis://localhost:6379)
|
|
82
|
+
* @param logger - Optional logger for debugging
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* const redis = new RedisStorage('redis://localhost:6379', console);
|
|
87
|
+
* await redis.connect();
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
constructor(url: string, logger?: Logger | null);
|
|
91
|
+
/**
|
|
92
|
+
* Establish connection to Redis
|
|
93
|
+
*
|
|
94
|
+
* Creates and connects the Redis client. Should be called before any
|
|
95
|
+
* storage operations.
|
|
96
|
+
*
|
|
97
|
+
* @throws {Error} If connection fails
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* try {
|
|
102
|
+
* await redis.connect();
|
|
103
|
+
* console.log('Redis connected');
|
|
104
|
+
* } catch (error) {
|
|
105
|
+
* console.error('Redis connection failed:', error);
|
|
106
|
+
* }
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
connect(): Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* Close Redis connection
|
|
112
|
+
*
|
|
113
|
+
* Gracefully closes the Redis connection. Should be called during
|
|
114
|
+
* application shutdown.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* await redis.disconnect();
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
disconnect(): Promise<void>;
|
|
122
|
+
/**
|
|
123
|
+
* Retrieve a value from Redis cache
|
|
124
|
+
*
|
|
125
|
+
* Deserializes the JSON-stored value. Returns null if the key doesn't exist
|
|
126
|
+
* or if there's a connection/parsing error.
|
|
127
|
+
*
|
|
128
|
+
* @param key - The key to retrieve
|
|
129
|
+
* @returns Promise resolving to the value or null if not found
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* const userData = await redis.get('user:123');
|
|
134
|
+
* if (userData !== null) {
|
|
135
|
+
* console.log('Found in Redis');
|
|
136
|
+
* }
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
get(key: string): Promise<unknown>;
|
|
140
|
+
/**
|
|
141
|
+
* Store a value in Redis cache
|
|
142
|
+
*
|
|
143
|
+
* Serializes the value as JSON and stores it with optional TTL.
|
|
144
|
+
* If TTL is not provided, the key will persist indefinitely (until manually deleted).
|
|
145
|
+
*
|
|
146
|
+
* @param key - The key to store
|
|
147
|
+
* @param value - The value to store (will be JSON serialized)
|
|
148
|
+
* @param ttlSeconds - Optional TTL in seconds
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```typescript
|
|
152
|
+
* // Store with 1 hour TTL
|
|
153
|
+
* await redis.set('session:abc', sessionData, 3600);
|
|
154
|
+
*
|
|
155
|
+
* // Store without TTL (persists until deleted)
|
|
156
|
+
* await redis.set('config:app', configData);
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
set(key: string, value: unknown, ttlSeconds?: number): Promise<void>;
|
|
160
|
+
/**
|
|
161
|
+
* Delete a value from Redis cache
|
|
162
|
+
*
|
|
163
|
+
* @param key - The key to delete
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```typescript
|
|
167
|
+
* await redis.delete('session:expired');
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
delete(key: string): Promise<void>;
|
|
171
|
+
/**
|
|
172
|
+
* Check if a key exists in Redis cache
|
|
173
|
+
*
|
|
174
|
+
* @param key - The key to check
|
|
175
|
+
* @returns Promise resolving to true if the key exists
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* if (await redis.exists('user:123')) {
|
|
180
|
+
* console.log('Key exists in Redis');
|
|
181
|
+
* }
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
exists(key: string): Promise<boolean>;
|
|
185
|
+
/**
|
|
186
|
+
* Clear all keys from Redis database
|
|
187
|
+
*
|
|
188
|
+
* **WARNING:** This operation flushes the entire Redis database.
|
|
189
|
+
* Use with caution in production environments.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```typescript
|
|
193
|
+
* await redis.clear(); // Flushes entire Redis DB
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
clear(): Promise<void>;
|
|
197
|
+
/**
|
|
198
|
+
* Health check for Redis connection
|
|
199
|
+
*
|
|
200
|
+
* Uses Redis PING command to verify connectivity and responsiveness.
|
|
201
|
+
* Returns false if not connected or if PING fails.
|
|
202
|
+
*
|
|
203
|
+
* @returns Promise resolving to true if Redis is healthy and responsive
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```typescript
|
|
207
|
+
* const isHealthy = await redis.ping();
|
|
208
|
+
* if (!isHealthy) {
|
|
209
|
+
* console.error('Redis connection is down');
|
|
210
|
+
* }
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
ping(): Promise<boolean>;
|
|
214
|
+
/**
|
|
215
|
+
* Check if Redis is connected
|
|
216
|
+
*
|
|
217
|
+
* @returns True if connected
|
|
218
|
+
*/
|
|
219
|
+
isConnected(): boolean;
|
|
220
|
+
/**
|
|
221
|
+
* Atomically increment a numeric value
|
|
222
|
+
*
|
|
223
|
+
* Uses Redis INCRBY command for true atomic increments that are safe
|
|
224
|
+
* across multiple instances and concurrent requests.
|
|
225
|
+
*
|
|
226
|
+
* @param key - The key to increment
|
|
227
|
+
* @param delta - The amount to increment by
|
|
228
|
+
* @param ttlSeconds - Optional TTL in seconds
|
|
229
|
+
* @returns Promise resolving to the new value after increment
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```typescript
|
|
233
|
+
* // Atomic increment - safe for concurrent access
|
|
234
|
+
* const newValue = await redis.increment('counter', 1, 3600);
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
increment(key: string, delta: number, ttlSeconds?: number): Promise<number>;
|
|
238
|
+
/**
|
|
239
|
+
* Log a message if logger is configured
|
|
240
|
+
*
|
|
241
|
+
* @private
|
|
242
|
+
* @param level - Log level
|
|
243
|
+
* @param message - Log message
|
|
244
|
+
* @param meta - Optional metadata
|
|
245
|
+
*/
|
|
246
|
+
private log;
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=redis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../../src/layers/redis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,qBAAa,YAAa,YAAW,qBAAqB;IACxD,4BAA4B;IAC5B,OAAO,CAAC,MAAM,CAAyB;IAEvC,2BAA2B;IAC3B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAE7B,sCAAsC;IACtC,OAAO,CAAC,SAAS,CAAU;IAE3B,mDAAmD;IACnD,OAAO,CAAC,MAAM,CAAgB;IAE9B;;;;;;;;;;;;;;OAcG;gBACS,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,GAAG,IAAW;IAOrD;;;;;;;;;;;;;;;;;OAiBG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB9B;;;;;;;;;;OAUG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC;;;;;;;;;;;;;;;;OAgBG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAoBxC;;;;;;;;;;;;;;;;;;OAkBG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB1E;;;;;;;;;OASG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcxC;;;;;;;;;;;;OAYG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgB3C;;;;;;;;;;OAUG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAe5B;;;;;;;;;;;;;;;OAeG;IACG,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IAgB9B;;;;OAIG;IACH,WAAW,IAAI,OAAO;IAItB;;;;;;;;;;;;;;;;OAgBG;IACG,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwBjF;;;;;;;OAOG;IACH,OAAO,CAAC,GAAG;CAKZ"}
|