@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.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +427 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/cjs/core/client.js +981 -0
  5. package/dist/cjs/core/client.js.map +1 -0
  6. package/dist/cjs/core/database.js +297 -0
  7. package/dist/cjs/core/database.js.map +1 -0
  8. package/dist/cjs/core/engine.js +1202 -0
  9. package/dist/cjs/core/engine.js.map +1 -0
  10. package/dist/cjs/core/index.js +35 -0
  11. package/dist/cjs/core/index.js.map +1 -0
  12. package/dist/cjs/index.js +109 -0
  13. package/dist/cjs/index.js.map +1 -0
  14. package/dist/cjs/interfaces/index.js +12 -0
  15. package/dist/cjs/interfaces/index.js.map +1 -0
  16. package/dist/cjs/layers/index.js +22 -0
  17. package/dist/cjs/layers/index.js.map +1 -0
  18. package/dist/cjs/layers/memory.js +388 -0
  19. package/dist/cjs/layers/memory.js.map +1 -0
  20. package/dist/cjs/layers/postgres.js +492 -0
  21. package/dist/cjs/layers/postgres.js.map +1 -0
  22. package/dist/cjs/layers/redis.js +388 -0
  23. package/dist/cjs/layers/redis.js.map +1 -0
  24. package/dist/cjs/types/index.js +52 -0
  25. package/dist/cjs/types/index.js.map +1 -0
  26. package/dist/esm/core/client.js +944 -0
  27. package/dist/esm/core/client.js.map +1 -0
  28. package/dist/esm/core/database.js +289 -0
  29. package/dist/esm/core/database.js.map +1 -0
  30. package/dist/esm/core/engine.js +1198 -0
  31. package/dist/esm/core/engine.js.map +1 -0
  32. package/dist/esm/core/index.js +16 -0
  33. package/dist/esm/core/index.js.map +1 -0
  34. package/dist/esm/index.js +87 -0
  35. package/dist/esm/index.js.map +1 -0
  36. package/dist/esm/interfaces/index.js +11 -0
  37. package/dist/esm/interfaces/index.js.map +1 -0
  38. package/dist/esm/layers/index.js +16 -0
  39. package/dist/esm/layers/index.js.map +1 -0
  40. package/dist/esm/layers/memory.js +384 -0
  41. package/dist/esm/layers/memory.js.map +1 -0
  42. package/dist/esm/layers/postgres.js +485 -0
  43. package/dist/esm/layers/postgres.js.map +1 -0
  44. package/dist/esm/layers/redis.js +384 -0
  45. package/dist/esm/layers/redis.js.map +1 -0
  46. package/dist/esm/types/index.js +49 -0
  47. package/dist/esm/types/index.js.map +1 -0
  48. package/dist/types/core/client.d.ts +561 -0
  49. package/dist/types/core/client.d.ts.map +1 -0
  50. package/dist/types/core/database.d.ts +130 -0
  51. package/dist/types/core/database.d.ts.map +1 -0
  52. package/dist/types/core/engine.d.ts +450 -0
  53. package/dist/types/core/engine.d.ts.map +1 -0
  54. package/dist/types/core/index.d.ts +13 -0
  55. package/dist/types/core/index.d.ts.map +1 -0
  56. package/dist/types/index.d.ts +85 -0
  57. package/dist/types/index.d.ts.map +1 -0
  58. package/dist/types/interfaces/index.d.ts +209 -0
  59. package/dist/types/interfaces/index.d.ts.map +1 -0
  60. package/dist/types/layers/index.d.ts +16 -0
  61. package/dist/types/layers/index.d.ts.map +1 -0
  62. package/dist/types/layers/memory.d.ts +261 -0
  63. package/dist/types/layers/memory.d.ts.map +1 -0
  64. package/dist/types/layers/postgres.d.ts +313 -0
  65. package/dist/types/layers/postgres.d.ts.map +1 -0
  66. package/dist/types/layers/redis.d.ts +248 -0
  67. package/dist/types/layers/redis.d.ts.map +1 -0
  68. package/dist/types/types/index.d.ts +410 -0
  69. package/dist/types/types/index.d.ts.map +1 -0
  70. package/package.json +90 -0
@@ -0,0 +1,561 @@
1
+ /**
2
+ * Nuvex - Client Implementation
3
+ * Next-gen Unified Vault Experience
4
+ *
5
+ * High-level client operations for any Node.js application using the StorageEngine
6
+ * multi-layer architecture. Provides application-centric methods for storing and
7
+ * retrieving data with built-in health checks, metrics, and maintenance operations.
8
+ *
9
+ * Core Features:
10
+ * - Generic key-value operations with intelligent caching
11
+ * - Health monitoring and diagnostics
12
+ * - Automatic cleanup and maintenance
13
+ * - Configuration management
14
+ * - Backup and restore capabilities
15
+ *
16
+ * @author Waren Gonzaga, WG Technology Labs
17
+ * @since 2025
18
+ */
19
+ import { StorageEngine } from './engine.js';
20
+ import type { NuvexConfig, StorageOptions, BatchOperation, BatchResult, QueryOptions, QueryResult } from '../types/index.js';
21
+ import type { Store as IStore } from '../interfaces/index.js';
22
+ /**
23
+ * Nuvex Client - High-level storage operations
24
+ *
25
+ * Provides a high-level interface for interacting with the multi-layer storage
26
+ * architecture. Implements the Store interface with additional convenience methods,
27
+ * health monitoring, backup/restore capabilities, and singleton pattern support.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * // Initialize as singleton
32
+ * const client = await NuvexClient.initialize({
33
+ * postgres: { host: 'localhost', port: 5432, database: 'myapp' },
34
+ * redis: { url: 'redis://localhost:6379' },
35
+ * memory: { ttl: 3600000, maxSize: 10000 }
36
+ * });
37
+ *
38
+ * // Store and retrieve data
39
+ * await client.set('user:123', { name: 'John', email: 'john@example.com' });
40
+ * const user = await client.get('user:123');
41
+ *
42
+ * // Use namespacing
43
+ * await client.setNamespaced('users', '123', userData);
44
+ * const userData = await client.getNamespaced('users', '123');
45
+ *
46
+ * // Perform health checks
47
+ * const health = await client.healthCheck();
48
+ * console.log('Storage layers healthy:', health.overall);
49
+ * ```
50
+ *
51
+ * @class NuvexClient
52
+ * @implements {IStore}
53
+ * @author Waren Gonzaga, WG Technology Labs
54
+ * @since 2025
55
+ */
56
+ export declare class NuvexClient implements IStore {
57
+ private static instance;
58
+ private storage;
59
+ private config;
60
+ private logger;
61
+ constructor(config: NuvexConfig);
62
+ private log;
63
+ /**
64
+ * Initialize the Store singleton instance
65
+ *
66
+ * Creates a new NuvexClient instance if one doesn't exist and connects to all
67
+ * configured storage layers. This method ensures only one instance exists
68
+ * throughout the application lifecycle.
69
+ *
70
+ * @param config - Configuration object for all storage layers
71
+ * @returns Promise that resolves to the initialized NuvexClient instance
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * const client = await NuvexClient.initialize({
76
+ * postgres: { host: 'localhost', port: 5432, database: 'myapp' },
77
+ * redis: { url: 'redis://localhost:6379' },
78
+ * memory: { ttl: 3600000, maxSize: 10000 }
79
+ * });
80
+ * ```
81
+ *
82
+ * @since 1.0.0
83
+ */
84
+ static initialize(config: NuvexConfig): Promise<NuvexClient>;
85
+ /**
86
+ * Get the singleton instance
87
+ *
88
+ * Returns the existing NuvexClient instance. Must be called after initialize().
89
+ *
90
+ * @returns The singleton NuvexClient instance
91
+ * @throws {Error} If the store has not been initialized
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * // After initialization
96
+ * const client = NuvexClient.getInstance();
97
+ * await client.set('key', 'value');
98
+ * ```
99
+ *
100
+ * @since 1.0.0
101
+ */
102
+ static getInstance(): NuvexClient;
103
+ /**
104
+ * Create a new Store instance (non-singleton)
105
+ *
106
+ * Creates a new NuvexClient instance without affecting the singleton.
107
+ * Useful for testing or when multiple isolated instances are needed.
108
+ *
109
+ * @param config - Configuration object for all storage layers
110
+ * @returns Promise that resolves to a new NuvexClient instance
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * const testClient = await NuvexClient.create({
115
+ * postgres: testDbConfig,
116
+ * memory: { ttl: 1000 }
117
+ * });
118
+ * ```
119
+ *
120
+ * @since 1.0.0
121
+ */
122
+ static create(config: NuvexConfig): Promise<NuvexClient>;
123
+ /**
124
+ * Connect to all configured storage layers
125
+ *
126
+ * Establishes connections to PostgreSQL, Redis (if configured), and initializes
127
+ * the memory cache. This method is automatically called by initialize() and create().
128
+ *
129
+ * @returns Promise that resolves when all connections are established
130
+ * @throws {Error} If any required storage layer fails to connect
131
+ *
132
+ * @since 1.0.0
133
+ */
134
+ connect(): Promise<void>;
135
+ /**
136
+ * Disconnect from all storage layers
137
+ *
138
+ * Cleanly closes all connections and clears the memory cache.
139
+ * Should be called during application shutdown.
140
+ *
141
+ * @returns Promise that resolves when all connections are closed
142
+ *
143
+ * @since 1.0.0
144
+ */
145
+ disconnect(): Promise<void>;
146
+ /**
147
+ * Check if the client is connected to storage layers
148
+ *
149
+ * @returns True if connected to at least the primary storage layer
150
+ *
151
+ * @since 1.0.0
152
+ */
153
+ isConnected(): boolean;
154
+ /**
155
+ * Store a value in the multi-layer storage system
156
+ *
157
+ * Stores the value across all available storage layers (Memory → Redis → PostgreSQL)
158
+ * with intelligent TTL management and layer-specific optimizations.
159
+ *
160
+ * @template T - The type of the value being stored
161
+ * @param key - Unique identifier for the stored value
162
+ * @param value - The value to store (will be JSON serialized)
163
+ * @param options - Optional storage configuration
164
+ * @returns Promise that resolves to true if stored successfully
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * // Store with default TTL
169
+ * await client.set('user:123', { name: 'John', email: 'john@example.com' });
170
+ *
171
+ * // Store with custom TTL (60 seconds)
172
+ * await client.set('session:abc', sessionData, { ttl: 60 });
173
+ *
174
+ * // Store only in memory layer
175
+ * await client.set('cache:temp', data, { layer: StorageLayer.MEMORY });
176
+ * ```
177
+ *
178
+ * @since 1.0.0
179
+ */
180
+ set<T = unknown>(key: string, value: T, options?: StorageOptions): Promise<boolean>;
181
+ /**
182
+ * Retrieve a value from the multi-layer storage system
183
+ *
184
+ * Searches for the value across storage layers in order (Memory → Redis → PostgreSQL)
185
+ * and automatically promotes the value to higher layers for faster future access.
186
+ *
187
+ * @template T - The expected type of the retrieved value
188
+ * @param key - Unique identifier of the value to retrieve
189
+ * @param options - Optional retrieval configuration
190
+ * @returns Promise that resolves to the value or null if not found
191
+ *
192
+ * @example
193
+ * ```typescript
194
+ * // Get from any layer
195
+ * const user = await client.get<UserType>('user:123');
196
+ *
197
+ * // Get only from PostgreSQL, skip cache
198
+ * const freshData = await client.get('data:key', { skipCache: true });
199
+ *
200
+ * // Get only from memory layer
201
+ * const cachedData = await client.get('cache:key', { layer: StorageLayer.MEMORY });
202
+ * ```
203
+ *
204
+ * @since 1.0.0
205
+ */
206
+ get<T = unknown>(key: string, options?: StorageOptions): Promise<T | null>;
207
+ /**
208
+ * Delete a value from all storage layers
209
+ *
210
+ * Removes the value from all storage layers to ensure consistency.
211
+ *
212
+ * @param key - Unique identifier of the value to delete
213
+ * @param options - Optional deletion configuration
214
+ * @returns Promise that resolves to true if deleted successfully
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * // Delete from all layers
219
+ * await client.delete('user:123');
220
+ *
221
+ * // Delete only from memory layer
222
+ * await client.delete('cache:temp', { layer: StorageLayer.MEMORY });
223
+ * ```
224
+ *
225
+ * @since 1.0.0
226
+ */
227
+ delete(key: string, options?: StorageOptions): Promise<boolean>;
228
+ /**
229
+ * Check if a key exists in any storage layer
230
+ *
231
+ * @param key - Unique identifier to check for existence
232
+ * @param options - Optional configuration to check specific layer
233
+ * @returns Promise that resolves to true if the key exists
234
+ *
235
+ * @example
236
+ * ```typescript
237
+ * if (await client.exists('user:123')) {
238
+ * console.log('User exists');
239
+ * }
240
+ * ```
241
+ *
242
+ * @since 1.0.0
243
+ */
244
+ exists(key: string, options?: StorageOptions): Promise<boolean>;
245
+ /**
246
+ * Set or update the expiration time for a key
247
+ *
248
+ * @param key - Unique identifier of the value
249
+ * @param ttl - Time to live in seconds
250
+ * @returns Promise that resolves to true if expiration was set successfully
251
+ *
252
+ * @example
253
+ * ```typescript
254
+ * // Expire in 1 hour
255
+ * await client.expire('session:abc', 3600);
256
+ * ```
257
+ *
258
+ * @since 1.0.0
259
+ */
260
+ expire(key: string, ttl: number): Promise<boolean>;
261
+ /**
262
+ * Execute multiple set operations in a batch
263
+ *
264
+ * Efficiently executes multiple storage operations with automatic error handling
265
+ * and transaction-like behavior where possible.
266
+ *
267
+ * @param operations - Array of batch operations to execute
268
+ * @returns Promise that resolves to an array of results for each operation
269
+ *
270
+ * @example
271
+ * ```typescript
272
+ * const results = await client.setBatch([
273
+ * { operation: 'set', key: 'user:1', value: userData1 },
274
+ * { operation: 'set', key: 'user:2', value: userData2, options: { ttl: 3600 } }
275
+ * ]);
276
+ *
277
+ * results.forEach((result, index) => {
278
+ * console.log(`Operation ${index}: ${result.success ? 'Success' : 'Failed'}`);
279
+ * });
280
+ * ```
281
+ *
282
+ * @since 1.0.0
283
+ */
284
+ setBatch(operations: BatchOperation[]): Promise<BatchResult[]>;
285
+ /**
286
+ * Retrieve multiple values in a batch
287
+ *
288
+ * Efficiently retrieves multiple values with layer optimization and
289
+ * automatic cache promotion.
290
+ *
291
+ * @param keys - Array of keys to retrieve
292
+ * @param options - Optional configuration applied to all operations
293
+ * @returns Promise that resolves to an array of results for each key
294
+ *
295
+ * @example
296
+ * ```typescript
297
+ * const results = await client.getBatch(['user:1', 'user:2', 'user:3']);
298
+ * const users = results
299
+ * .filter(result => result.success && result.value)
300
+ * .map(result => result.value);
301
+ * ```
302
+ *
303
+ * @since 1.0.0
304
+ */
305
+ getBatch(keys: string[], options?: StorageOptions): Promise<BatchResult[]>;
306
+ /**
307
+ * Delete multiple values in a batch
308
+ *
309
+ * Efficiently deletes multiple values from all storage layers.
310
+ *
311
+ * @param keys - Array of keys to delete
312
+ * @returns Promise that resolves to an array of results for each key
313
+ *
314
+ * @example
315
+ * ```typescript
316
+ * const results = await client.deleteBatch(['temp:1', 'temp:2', 'temp:3']);
317
+ * const deletedCount = results.filter(r => r.success).length;
318
+ * ```
319
+ *
320
+ * @since 1.0.0
321
+ */
322
+ deleteBatch(keys: string[]): Promise<BatchResult[]>;
323
+ query<T = unknown>(options: QueryOptions): Promise<QueryResult<T>>;
324
+ keys(pattern?: string): Promise<string[]>;
325
+ clear(pattern?: string): Promise<number>;
326
+ /**
327
+ * Get performance metrics for all layers or specific layer(s)
328
+ *
329
+ * Returns metrics about storage operations and performance. Can be filtered
330
+ * to return metrics for specific layers only.
331
+ *
332
+ * @param layers - Optional layer(s) to get metrics for. If not provided, returns all metrics.
333
+ * Can be a single layer string, 'all', or array of layer strings.
334
+ * @returns Object containing requested metrics
335
+ *
336
+ * @example
337
+ * ```typescript
338
+ * // Get all metrics
339
+ * const metrics = client.getMetrics();
340
+ *
341
+ * // Get specific layer metrics
342
+ * const memoryMetrics = client.getMetrics('memory');
343
+ * // { memoryHits, memoryMisses, memorySize, memoryMaxSize }
344
+ *
345
+ * // Get multiple layer metrics
346
+ * const cacheMetrics = client.getMetrics(['memory', 'redis']);
347
+ * // { memoryHits, memoryMisses, memorySize, memoryMaxSize, redisHits, redisMisses, totalOperations, averageResponseTime, cacheHitRatio }
348
+ * ```
349
+ *
350
+ * @since 1.0.0
351
+ */
352
+ getMetrics(layers?: 'memory' | 'redis' | 'postgres' | 'all' | Array<'memory' | 'redis' | 'postgres'>): Record<string, number>;
353
+ resetMetrics(): void;
354
+ promote(key: string, targetLayer: string): Promise<boolean>;
355
+ demote(key: string, targetLayer: string): Promise<boolean>;
356
+ getLayerInfo(key: string): Promise<{
357
+ layer: string;
358
+ ttl?: number;
359
+ } | null>;
360
+ /**
361
+ * Configure the store with new settings
362
+ */
363
+ configure(config: Partial<NuvexConfig>): Promise<void>;
364
+ /**
365
+ * Get the underlying storage engine
366
+ *
367
+ * @internal This method is intended for internal and testing use only.
368
+ * It provides direct access to the StorageEngine instance.
369
+ *
370
+ * @returns The StorageEngine instance used by this client
371
+ */
372
+ getEngine(): StorageEngine;
373
+ /**
374
+ * Get current configuration
375
+ */
376
+ getConfig(): NuvexConfig;
377
+ /**
378
+ * Health check for all storage layers or specific layer(s)
379
+ *
380
+ * Performs comprehensive health checks on configured storage layers
381
+ * using the underlying engine's ping() methods for each layer.
382
+ *
383
+ * @param layers - Optional layer(s) to check. If not provided, checks all layers.
384
+ * Can be a single layer string or array of layer strings.
385
+ * @returns Promise that resolves to health status for requested layer(s)
386
+ *
387
+ * @example
388
+ * ```typescript
389
+ * // Check all layers
390
+ * const health = await client.healthCheck();
391
+ * // { memory: true, redis: true, postgres: true }
392
+ *
393
+ * // Check specific layer
394
+ * const redisHealth = await client.healthCheck('redis');
395
+ * // { redis: true }
396
+ *
397
+ * // Check multiple layers
398
+ * const cacheHealth = await client.healthCheck(['memory', 'redis']);
399
+ * // { memory: true, redis: true }
400
+ *
401
+ * if (!health.redis) {
402
+ * console.error('Redis layer is down');
403
+ * }
404
+ * ```
405
+ *
406
+ * @since 1.0.0
407
+ */
408
+ healthCheck(layers?: 'memory' | 'redis' | 'postgres' | Array<'memory' | 'redis' | 'postgres'>): Promise<Record<string, boolean>>;
409
+ /**
410
+ * Cleanup expired entries and optimize storage
411
+ */
412
+ cleanup(): Promise<{
413
+ cleaned: number;
414
+ errors: number;
415
+ }>;
416
+ /**
417
+ * Compact storage and optimize performance
418
+ */
419
+ compact(): Promise<void>;
420
+ /**
421
+ * Backup storage data to external location with incremental support
422
+ */
423
+ backup(destination?: string, options?: {
424
+ incremental?: boolean;
425
+ compression?: boolean;
426
+ }): Promise<string>;
427
+ /**
428
+ * Restore storage data from external backup location
429
+ */
430
+ restore(source: string, options?: {
431
+ clearExisting?: boolean;
432
+ dryRun?: boolean;
433
+ }): Promise<boolean>;
434
+ /**
435
+ * Namespace-aware set operation
436
+ */
437
+ setNamespaced(namespace: string, key: string, value: unknown, options?: StorageOptions): Promise<boolean>;
438
+ /**
439
+ * Namespace-aware get operation
440
+ */
441
+ getNamespaced<T = unknown>(namespace: string, key: string, options?: StorageOptions): Promise<T | null>;
442
+ /**
443
+ * Get all keys in a namespace
444
+ */
445
+ getNamespaceKeys(namespace: string): Promise<string[]>;
446
+ /**
447
+ * Clear entire namespace
448
+ */
449
+ clearNamespace(namespace: string): Promise<number>;
450
+ /**
451
+ * Atomically increment a numeric value
452
+ *
453
+ * This method provides true atomic increments that are safe for concurrent access
454
+ * across all storage layers. Uses native atomic operations from Redis (INCRBY) and
455
+ * PostgreSQL (UPDATE with row locks) when available.
456
+ *
457
+ * **Thread-Safety:**
458
+ * - ✅ Safe for concurrent increments to the same key
459
+ * - ✅ No lost updates in high-concurrency scenarios
460
+ * - ✅ Works correctly across multiple instances
461
+ *
462
+ * **Important:** The key must contain a numeric value (or not exist).
463
+ * Incrementing a non-numeric value will throw an error.
464
+ *
465
+ * **How It Works:**
466
+ * 1. Uses atomic increment at the authoritative layer (PostgreSQL or Redis)
467
+ * 2. Propagates the new value to cache layers for consistency
468
+ * 3. Returns the exact new value after increment
469
+ *
470
+ * **Example Usage:**
471
+ * ```typescript
472
+ * // ✅ SAFE: Concurrent increments work correctly
473
+ * await Promise.all([
474
+ * client.increment('counter'), // atomic: 5 → 6
475
+ * client.increment('counter') // atomic: 6 → 7
476
+ * ]);
477
+ * // Result: 7 (all increments counted correctly)
478
+ *
479
+ * // Custom delta
480
+ * await client.increment('page_views', 5);
481
+ *
482
+ * // With TTL (in milliseconds)
483
+ * await client.increment('rate_limit', 1, 3600000);
484
+ * ```
485
+ *
486
+ * **Use Cases:**
487
+ * - ✅ High-concurrency counters (page views, API calls)
488
+ * - ✅ Critical operations (user credits, inventory)
489
+ * - ✅ Financial operations requiring exactness
490
+ * - ✅ Distributed systems with multiple instances
491
+ *
492
+ * @param key - The key to increment (must contain numeric value or not exist)
493
+ * @param delta - The amount to increment by (default: 1)
494
+ * @param ttl - Optional TTL in milliseconds
495
+ * @returns Promise resolving to the new value after increment
496
+ * @throws {Error} If the key contains a non-numeric value
497
+ */
498
+ increment(key: string, delta?: number, ttl?: number): Promise<number>;
499
+ /**
500
+ * Atomically decrement a numeric value
501
+ *
502
+ * This is a convenience method that uses atomic increment with a negative delta.
503
+ * Provides the same thread-safety guarantees as increment().
504
+ *
505
+ * @param key - The key to decrement
506
+ * @param delta - The amount to decrement by (default: 1)
507
+ * @param ttl - Optional TTL in milliseconds
508
+ * @returns Promise resolving to the new value after decrement
509
+ *
510
+ * @example
511
+ * ```typescript
512
+ * // Decrement by 1
513
+ * await client.decrement('inventory');
514
+ *
515
+ * // Decrement by custom amount
516
+ * await client.decrement('stock', 5);
517
+ * ```
518
+ */
519
+ decrement(key: string, delta?: number, ttl?: number): Promise<number>;
520
+ /**
521
+ * Set if not exists
522
+ *
523
+ * Stores a value only if the key does not already exist. Useful for
524
+ * initializing values that should not be overwritten.
525
+ *
526
+ * @note This implementation uses a check-then-set pattern which has a
527
+ * TOCTOU (Time-of-Check to Time-of-Use) race condition. Between the
528
+ * `exists()` and `set()` calls, another client could write to the same key.
529
+ * For critical use cases requiring true atomic set-if-not-exists semantics,
530
+ * use Redis `SET key value NX` or PostgreSQL `INSERT ... ON CONFLICT DO NOTHING`
531
+ * directly via the storage layer.
532
+ *
533
+ * @template T - The type of the value being stored
534
+ * @param key - Unique identifier for the stored value
535
+ * @param value - The value to store if key doesn't exist
536
+ * @param options - Optional storage configuration
537
+ * @returns Promise resolving to true if value was set, false if key already existed
538
+ *
539
+ * @example
540
+ * ```typescript
541
+ * // Initialize a counter only if it doesn't exist
542
+ * await client.setIfNotExists('counter', 0);
543
+ * ```
544
+ */
545
+ setIfNotExists<T = unknown>(key: string, value: T, options?: StorageOptions): Promise<boolean>;
546
+ /**
547
+ * Get multiple keys with a common prefix
548
+ */
549
+ getByPrefix<T = unknown>(prefix: string, options?: StorageOptions): Promise<Record<string, T>>;
550
+ static set<T = unknown>(key: string, value: T, options?: StorageOptions): Promise<boolean>;
551
+ static get<T = unknown>(key: string, options?: StorageOptions): Promise<T | null>;
552
+ static delete(key: string, options?: StorageOptions): Promise<boolean>;
553
+ static exists(key: string, options?: StorageOptions): Promise<boolean>;
554
+ static healthCheck(layers?: 'memory' | 'redis' | 'postgres' | Array<'memory' | 'redis' | 'postgres'>): Promise<Record<string, boolean>>;
555
+ static getMetrics(layers?: 'memory' | 'redis' | 'postgres' | 'all' | Array<'memory' | 'redis' | 'postgres'>): Record<string, number>;
556
+ /**
557
+ * Shutdown the store and cleanup resources
558
+ */
559
+ static shutdown(): Promise<void>;
560
+ }
561
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/core/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Nuvex - Database Utilities
3
+ * Next-gen Unified Vault Experience
4
+ *
5
+ * Database schema setup and migration utilities for PostgreSQL storage layer.
6
+ *
7
+ * @author Waren Gonzaga, WG Technology Labs
8
+ * @since 2025
9
+ */
10
+ import type { Pool as PoolType } from 'pg';
11
+ import type { PostgresSchemaConfig } from '../types/index.js';
12
+ import type { Logger } from '../interfaces/index.js';
13
+ /**
14
+ * Validate SQL identifier to prevent SQL injection
15
+ * Ensures the identifier contains only alphanumeric characters and underscores
16
+ *
17
+ * @param identifier - SQL identifier to validate
18
+ * @param name - Name of the identifier for error messages
19
+ * @throws {Error} If identifier contains invalid characters
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * validateSQLIdentifier('my_table_123', 'table name'); // OK
24
+ * validateSQLIdentifier('users; DROP TABLE', 'table name'); // throws Error
25
+ * ```
26
+ *
27
+ * @since 1.0.0
28
+ */
29
+ export declare function validateSQLIdentifier(identifier: string, name: string): void;
30
+ /**
31
+ * Generate SQL schema for Nuvex storage with configurable table and column names
32
+ *
33
+ * @param schema - Optional schema configuration for custom table/column names
34
+ * @returns SQL string for creating the schema
35
+ * @throws {Error} If table or column names contain invalid characters
36
+ */
37
+ export declare function generateNuvexSchemaSQL(schema?: PostgresSchemaConfig): string;
38
+ export declare const NUVEX_SCHEMA_SQL: string;
39
+ export interface SchemaSetupOptions {
40
+ /** Enable trigram extension for advanced pattern matching (requires pg_trgm) */
41
+ enableTrigram?: boolean;
42
+ /** Set up periodic cleanup job using pg_cron extension */
43
+ enableCleanupJob?: boolean;
44
+ /** Schema configuration for custom table/column names */
45
+ schema?: PostgresSchemaConfig;
46
+ }
47
+ /**
48
+ * Setup Nuvex database schema
49
+ *
50
+ * Creates the necessary PostgreSQL tables, indexes, functions, and triggers
51
+ * required for the Nuvex storage system. This function is idempotent and
52
+ * can be safely called multiple times.
53
+ *
54
+ * Features created:
55
+ * - `nuvex_storage` table with JSON support and TTL
56
+ * - Indexes for performance optimization
57
+ * - Automatic `updated_at` trigger
58
+ * - Cleanup function for expired entries
59
+ * - Optional trigram support for pattern matching
60
+ * - Optional automated cleanup job scheduling
61
+ *
62
+ * @param db - PostgreSQL connection pool
63
+ * @param options - Optional configuration for schema setup
64
+ * @returns Promise that resolves when schema is created
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * import { Pool } from 'pg';
69
+ * import { setupNuvexSchema } from './database';
70
+ *
71
+ * const db = new Pool({ connectionString: 'postgresql://...' });
72
+ *
73
+ * // Basic setup
74
+ * await setupNuvexSchema(db);
75
+ *
76
+ * // Advanced setup with all features
77
+ * await setupNuvexSchema(db, {
78
+ * enableTrigram: true, // Enable pattern matching
79
+ * enableCleanupJob: true // Auto-cleanup expired entries
80
+ * });
81
+ * ```
82
+ *
83
+ * @throws {Error} If database connection fails or schema creation fails
84
+ *
85
+ * @since 1.0.0
86
+ */
87
+ export declare function setupNuvexSchema(db: PoolType, options?: SchemaSetupOptions, logger?: Logger): Promise<void>;
88
+ /**
89
+ * Manually clean up expired entries
90
+ *
91
+ * Executes the cleanup function to remove all expired entries from the
92
+ * nuvex_storage table. This can be called manually or as part of a maintenance routine.
93
+ *
94
+ * @param db - PostgreSQL connection pool
95
+ * @returns Promise that resolves to the number of deleted entries
96
+ *
97
+ * @example
98
+ * ```typescript
99
+ * const deletedCount = await cleanupExpiredEntries(db);
100
+ * console.log(`Cleaned up ${deletedCount} expired entries`);
101
+ * ```
102
+ *
103
+ * @throws {Error} If the cleanup operation fails
104
+ *
105
+ * @since 1.0.0
106
+ */
107
+ export declare function cleanupExpiredEntries(db: PoolType, schema?: PostgresSchemaConfig, logger?: Logger): Promise<number>;
108
+ /**
109
+ * Drop Nuvex schema (for cleanup/testing)
110
+ *
111
+ * Completely removes all Nuvex-related database objects including tables,
112
+ * functions, triggers, and indexes. This operation is irreversible and will
113
+ * result in permanent data loss.
114
+ *
115
+ * @param db - PostgreSQL connection pool
116
+ * @returns Promise that resolves when schema is dropped
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * // Use with extreme caution - this will delete all data!
121
+ * await dropNuvexSchema(testDb); // Only use in tests
122
+ * ```
123
+ *
124
+ * @throws {Error} If the drop operation fails
125
+ *
126
+ * @warning This operation is irreversible and will cause permanent data loss
127
+ * @since 1.0.0
128
+ */
129
+ export declare function dropNuvexSchema(db: PoolType, schema?: PostgresSchemaConfig, logger?: Logger): Promise<void>;
130
+ //# sourceMappingURL=database.d.ts.map