@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,485 @@
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 pkg from 'pg';
20
+ const { Pool } = pkg;
21
+ import { validateSQLIdentifier } from '../core/database.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 class PostgresStorage {
82
+ /**
83
+ * Creates a new PostgresStorage instance
84
+ *
85
+ * Accepts either a PostgreSQL configuration object or an existing Pool instance.
86
+ * If a Pool is provided, the caller is responsible for managing its lifecycle.
87
+ *
88
+ * Schema configuration is extracted from the config object when creating a new pool.
89
+ * When using an existing pool, schema defaults to standard Nuvex naming.
90
+ *
91
+ * @param config - PostgreSQL configuration or existing Pool instance
92
+ * @param logger - Optional logger for debugging
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * // With configuration (supports schema customization)
97
+ * const postgres = new PostgresStorage({
98
+ * host: 'localhost',
99
+ * database: 'myapp',
100
+ * user: 'postgres',
101
+ * password: 'password',
102
+ * schema: {
103
+ * tableName: 'storage_cache',
104
+ * columns: { key: 'key', value: 'value' }
105
+ * }
106
+ * });
107
+ *
108
+ * // With existing pool (uses default schema)
109
+ * const existingPool = new Pool({ ... });
110
+ * const postgres = new PostgresStorage(existingPool);
111
+ * ```
112
+ */
113
+ constructor(config, logger = null) {
114
+ this.config = config;
115
+ this.pool = null;
116
+ this.connected = false;
117
+ this.logger = logger;
118
+ // Check if config is already a Pool instance
119
+ this.ownsPool = !('query' in config && typeof config.query === 'function');
120
+ // Extract schema configuration with defaults
121
+ // Note: Schema is only extracted from config objects, not from existing Pool instances
122
+ const schema = this.ownsPool ? config.schema : undefined;
123
+ this.tableName = schema?.tableName ?? 'nuvex_storage';
124
+ this.keyColumn = schema?.columns?.key ?? 'nuvex_key';
125
+ this.valueColumn = schema?.columns?.value ?? 'nuvex_data';
126
+ // Validate all identifiers to prevent SQL injection
127
+ validateSQLIdentifier(this.tableName, 'table name');
128
+ validateSQLIdentifier(this.keyColumn, 'key column name');
129
+ validateSQLIdentifier(this.valueColumn, 'value column name');
130
+ }
131
+ /**
132
+ * Establish connection to PostgreSQL
133
+ *
134
+ * Creates a connection pool (if not already provided) and tests the connection.
135
+ * Should be called before any storage operations.
136
+ *
137
+ * @throws {Error} If connection test fails
138
+ *
139
+ * @example
140
+ * ```typescript
141
+ * try {
142
+ * await postgres.connect();
143
+ * console.log('PostgreSQL connected');
144
+ * } catch (error) {
145
+ * console.error('PostgreSQL connection failed:', error);
146
+ * }
147
+ * ```
148
+ */
149
+ async connect() {
150
+ try {
151
+ if (this.ownsPool) {
152
+ // Create new pool from config
153
+ this.pool = new Pool(this.config);
154
+ }
155
+ else {
156
+ // Use existing pool
157
+ this.pool = this.config;
158
+ }
159
+ // Test connection
160
+ if (this.pool) {
161
+ await this.pool.query('SELECT 1');
162
+ this.connected = true;
163
+ this.log('info', 'PostgreSQL L3: Connected successfully');
164
+ }
165
+ }
166
+ catch (error) {
167
+ this.connected = false;
168
+ this.log('error', 'PostgreSQL L3: Connection failed', {
169
+ error: error instanceof Error ? error.message : String(error)
170
+ });
171
+ throw error;
172
+ }
173
+ }
174
+ /**
175
+ * Close PostgreSQL connection pool
176
+ *
177
+ * Only closes the pool if we created it. If an existing pool was provided,
178
+ * the caller is responsible for closing it.
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * await postgres.disconnect();
183
+ * ```
184
+ */
185
+ async disconnect() {
186
+ if (this.pool && this.ownsPool) {
187
+ await this.pool.end();
188
+ this.log('info', 'PostgreSQL L3: Disconnected');
189
+ }
190
+ this.connected = false;
191
+ }
192
+ /**
193
+ * Retrieve a value from PostgreSQL
194
+ *
195
+ * Queries the nuvex_storage table and automatically filters out expired entries.
196
+ * Deserializes the JSON-stored value.
197
+ *
198
+ * @param key - The key to retrieve
199
+ * @returns Promise resolving to the value or null if not found/expired
200
+ *
201
+ * @example
202
+ * ```typescript
203
+ * const userData = await postgres.get('user:123');
204
+ * if (userData !== null) {
205
+ * console.log('Found in PostgreSQL');
206
+ * }
207
+ * ```
208
+ */
209
+ async get(key) {
210
+ if (!this.connected || !this.pool) {
211
+ return null;
212
+ }
213
+ try {
214
+ const result = await this.pool.query(`SELECT ${this.valueColumn} FROM ${this.tableName} WHERE ${this.keyColumn} = $1 AND (expires_at IS NULL OR expires_at > NOW())`, [key]);
215
+ if (result.rows.length === 0) {
216
+ return null;
217
+ }
218
+ // Value is already parsed by PostgreSQL JSONB type
219
+ return result.rows[0][this.valueColumn];
220
+ }
221
+ catch (error) {
222
+ // Table might not exist yet, that's okay
223
+ this.log('debug', `PostgreSQL L3: Error getting key: ${key}`, {
224
+ error: error instanceof Error ? error.message : String(error)
225
+ });
226
+ return null;
227
+ }
228
+ }
229
+ /**
230
+ * Store a value in PostgreSQL
231
+ *
232
+ * Inserts or updates the value in the nuvex_storage table. Uses UPSERT
233
+ * (INSERT ... ON CONFLICT) to handle existing keys efficiently.
234
+ *
235
+ * **Note:** This is the authoritative write. If this fails, the entire
236
+ * write operation should be considered failed.
237
+ *
238
+ * @param key - The key to store
239
+ * @param value - The value to store (will be JSON serialized)
240
+ * @param ttlSeconds - Optional TTL in seconds
241
+ *
242
+ * @example
243
+ * ```typescript
244
+ * // Store with 24 hour TTL
245
+ * await postgres.set('user:123', userData, 86400);
246
+ *
247
+ * // Store without TTL (persists until deleted)
248
+ * await postgres.set('config:app', configData);
249
+ * ```
250
+ */
251
+ async set(key, value, ttlSeconds) {
252
+ if (!this.connected || !this.pool) {
253
+ this.log('warn', 'PostgreSQL L3: Cannot set - not connected', { key });
254
+ throw new Error('PostgreSQL not connected');
255
+ }
256
+ try {
257
+ const expiresAt = ttlSeconds ? new Date(Date.now() + (ttlSeconds * 1000)) : null;
258
+ await this.pool.query(`INSERT INTO ${this.tableName} (${this.keyColumn}, ${this.valueColumn}, expires_at)
259
+ VALUES ($1, $2, $3)
260
+ ON CONFLICT (${this.keyColumn})
261
+ DO UPDATE SET ${this.valueColumn} = $2, expires_at = $3, updated_at = NOW()`, [key, JSON.stringify(value), expiresAt]);
262
+ }
263
+ catch (error) {
264
+ // If table doesn't exist, this is a critical error for L3
265
+ this.log('error', `PostgreSQL L3: Error setting key: ${key}`, {
266
+ error: error instanceof Error ? error.message : String(error)
267
+ });
268
+ throw error;
269
+ }
270
+ }
271
+ /**
272
+ * Delete a value from PostgreSQL
273
+ *
274
+ * Permanently removes the key from the nuvex_storage table.
275
+ *
276
+ * @param key - The key to delete
277
+ *
278
+ * @example
279
+ * ```typescript
280
+ * await postgres.delete('user:123');
281
+ * ```
282
+ */
283
+ async delete(key) {
284
+ if (!this.connected || !this.pool) {
285
+ return;
286
+ }
287
+ try {
288
+ await this.pool.query(`DELETE FROM ${this.tableName} WHERE ${this.keyColumn} = $1`, [key]);
289
+ }
290
+ catch (error) {
291
+ this.log('error', `PostgreSQL L3: Error deleting key: ${key}`, {
292
+ error: error instanceof Error ? error.message : String(error)
293
+ });
294
+ }
295
+ }
296
+ /**
297
+ * Check if a key exists in PostgreSQL
298
+ *
299
+ * Queries for the key and verifies it hasn't expired.
300
+ *
301
+ * @param key - The key to check
302
+ * @returns Promise resolving to true if the key exists and is not expired
303
+ *
304
+ * @example
305
+ * ```typescript
306
+ * if (await postgres.exists('user:123')) {
307
+ * console.log('Key exists in PostgreSQL');
308
+ * }
309
+ * ```
310
+ */
311
+ async exists(key) {
312
+ if (!this.connected || !this.pool) {
313
+ return false;
314
+ }
315
+ try {
316
+ const result = await this.pool.query(`SELECT 1 FROM ${this.tableName} WHERE ${this.keyColumn} = $1 AND (expires_at IS NULL OR expires_at > NOW())`, [key]);
317
+ return result.rows.length > 0;
318
+ }
319
+ catch (error) {
320
+ this.log('error', `PostgreSQL L3: Error checking existence: ${key}`, {
321
+ error: error instanceof Error ? error.message : String(error)
322
+ });
323
+ return false;
324
+ }
325
+ }
326
+ /**
327
+ * Clear all keys from PostgreSQL
328
+ *
329
+ * **WARNING:** This operation deletes all data from nuvex_storage table.
330
+ * Use with extreme caution in production environments.
331
+ *
332
+ * @example
333
+ * ```typescript
334
+ * await postgres.clear(); // Deletes all data
335
+ * ```
336
+ */
337
+ async clear() {
338
+ if (!this.connected || !this.pool) {
339
+ return;
340
+ }
341
+ try {
342
+ await this.pool.query(`DELETE FROM ${this.tableName}`);
343
+ this.log('info', 'PostgreSQL L3: All data cleared');
344
+ }
345
+ catch (error) {
346
+ this.log('error', 'PostgreSQL L3: Error clearing data', {
347
+ error: error instanceof Error ? error.message : String(error)
348
+ });
349
+ }
350
+ }
351
+ /**
352
+ * Health check for PostgreSQL connection
353
+ *
354
+ * Executes a simple SELECT 1 query to verify connectivity and database
355
+ * responsiveness. This is a lightweight operation that tests the full
356
+ * connection path including pool, connection, and database.
357
+ *
358
+ * @returns Promise resolving to true if PostgreSQL is healthy and responsive
359
+ *
360
+ * @example
361
+ * ```typescript
362
+ * const isHealthy = await postgres.ping();
363
+ * if (!isHealthy) {
364
+ * console.error('PostgreSQL connection is down');
365
+ * }
366
+ * ```
367
+ */
368
+ async ping() {
369
+ if (!this.connected || !this.pool) {
370
+ return false;
371
+ }
372
+ let client;
373
+ try {
374
+ // Get a client from the pool and run a simple query
375
+ client = await this.pool.connect();
376
+ try {
377
+ await client.query('SELECT 1');
378
+ return true;
379
+ }
380
+ finally {
381
+ client.release();
382
+ }
383
+ }
384
+ catch (error) {
385
+ this.log('error', 'PostgreSQL L3: Ping failed', {
386
+ error: error instanceof Error ? error.message : String(error)
387
+ });
388
+ return false;
389
+ }
390
+ }
391
+ /**
392
+ * Check if PostgreSQL is connected
393
+ *
394
+ * @returns True if connected
395
+ */
396
+ isConnected() {
397
+ return this.connected;
398
+ }
399
+ /**
400
+ * Get the PostgreSQL connection pool
401
+ *
402
+ * Useful for executing custom queries or transactions.
403
+ *
404
+ * @returns The connection pool or null if not connected
405
+ *
406
+ * @example
407
+ * ```typescript
408
+ * const pool = postgres.getPool();
409
+ * if (pool) {
410
+ * const result = await pool.query('SELECT * FROM custom_table');
411
+ * }
412
+ * ```
413
+ */
414
+ getPool() {
415
+ return this.pool;
416
+ }
417
+ /**
418
+ * Atomically increment a numeric value
419
+ *
420
+ * Uses PostgreSQL UPDATE with row-level locking for true atomic increments.
421
+ * If the key doesn't exist, it's created with the delta value.
422
+ *
423
+ * This operation is safe for concurrent access across multiple instances.
424
+ *
425
+ * @param key - The key to increment
426
+ * @param delta - The amount to increment by
427
+ * @param ttlSeconds - Optional TTL in seconds
428
+ * @returns Promise resolving to the new value after increment
429
+ *
430
+ * @example
431
+ * ```typescript
432
+ * // Atomic increment - safe for concurrent access
433
+ * const newValue = await postgres.increment('counter', 1, 86400);
434
+ * ```
435
+ */
436
+ async increment(key, delta, ttlSeconds) {
437
+ if (!this.connected || !this.pool) {
438
+ this.log('warn', 'PostgreSQL L3: Cannot increment - not connected', { key });
439
+ throw new Error('PostgreSQL not connected');
440
+ }
441
+ try {
442
+ const expiresAt = ttlSeconds ? new Date(Date.now() + (ttlSeconds * 1000)) : null;
443
+ // Atomic upsert to handle both insert and update cases
444
+ // This avoids race conditions when multiple concurrent increments happen on non-existent keys
445
+ const result = await this.pool.query(`INSERT INTO ${this.tableName} (${this.keyColumn}, ${this.valueColumn}, expires_at)
446
+ VALUES ($1, to_jsonb($2), $3)
447
+ ON CONFLICT (${this.keyColumn}) DO UPDATE
448
+ SET ${this.valueColumn} = to_jsonb(
449
+ CASE
450
+ WHEN ${this.tableName}.expires_at IS NULL OR ${this.tableName}.expires_at > NOW()
451
+ THEN (${this.tableName}.${this.valueColumn}::text)::numeric + (EXCLUDED.${this.valueColumn}::text)::numeric
452
+ ELSE (EXCLUDED.${this.valueColumn}::text)::numeric
453
+ END
454
+ ),
455
+ expires_at = EXCLUDED.expires_at,
456
+ updated_at = NOW()
457
+ RETURNING (${this.valueColumn}::text)::numeric as value`, [key, delta, expiresAt]);
458
+ if (result.rows.length > 0) {
459
+ return Number(result.rows[0].value);
460
+ }
461
+ // Fallback: should not reach here, but return delta if no rows returned
462
+ return delta;
463
+ }
464
+ catch (error) {
465
+ this.log('error', `PostgreSQL L3: Error incrementing key: ${key}`, {
466
+ error: error instanceof Error ? error.message : String(error)
467
+ });
468
+ throw error;
469
+ }
470
+ }
471
+ /**
472
+ * Log a message if logger is configured
473
+ *
474
+ * @private
475
+ * @param level - Log level
476
+ * @param message - Log message
477
+ * @param meta - Optional metadata
478
+ */
479
+ log(level, message, meta) {
480
+ if (this.logger) {
481
+ this.logger[level](message, meta);
482
+ }
483
+ }
484
+ }
485
+ //# sourceMappingURL=postgres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../../src/layers/postgres.ts"],"names":[],"mappings":"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"}