@bloomneo/appkit 1.2.9 → 1.5.2
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/AGENTS.md +195 -0
- package/CHANGELOG.md +253 -0
- package/README.md +147 -799
- package/bin/commands/generate.js +7 -7
- package/cookbook/README.md +26 -0
- package/cookbook/api-key-service.ts +106 -0
- package/cookbook/auth-protected-crud.ts +112 -0
- package/cookbook/file-upload-pipeline.ts +113 -0
- package/cookbook/multi-tenant-saas.ts +87 -0
- package/cookbook/real-time-chat.ts +121 -0
- package/dist/auth/auth.d.ts +21 -4
- package/dist/auth/auth.d.ts.map +1 -1
- package/dist/auth/auth.js +56 -44
- package/dist/auth/auth.js.map +1 -1
- package/dist/auth/defaults.d.ts +1 -1
- package/dist/auth/defaults.js +35 -35
- package/dist/cache/cache.d.ts +29 -6
- package/dist/cache/cache.d.ts.map +1 -1
- package/dist/cache/cache.js +72 -44
- package/dist/cache/cache.js.map +1 -1
- package/dist/cache/defaults.js +29 -29
- package/dist/cache/index.d.ts +19 -10
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +21 -18
- package/dist/cache/index.js.map +1 -1
- package/dist/config/defaults.d.ts +1 -1
- package/dist/config/defaults.js +11 -11
- package/dist/config/index.d.ts +3 -3
- package/dist/config/index.js +4 -4
- package/dist/database/adapters/mongoose.d.ts +4 -4
- package/dist/database/adapters/mongoose.js +7 -7
- package/dist/database/adapters/prisma.d.ts +4 -4
- package/dist/database/adapters/prisma.js +7 -7
- package/dist/database/defaults.d.ts +1 -1
- package/dist/database/defaults.js +4 -4
- package/dist/database/index.js +2 -2
- package/dist/database/index.js.map +1 -1
- package/dist/email/defaults.js +26 -26
- package/dist/email/index.js +7 -7
- package/dist/email/strategies/resend.js +1 -1
- package/dist/error/defaults.d.ts +1 -1
- package/dist/error/defaults.js +13 -13
- package/dist/error/error.d.ts +12 -0
- package/dist/error/error.d.ts.map +1 -1
- package/dist/error/error.js +19 -0
- package/dist/error/error.js.map +1 -1
- package/dist/error/index.d.ts +14 -3
- package/dist/error/index.d.ts.map +1 -1
- package/dist/error/index.js +14 -3
- package/dist/error/index.js.map +1 -1
- package/dist/event/defaults.js +35 -35
- package/dist/event/index.js +7 -7
- package/dist/logger/defaults.d.ts +1 -1
- package/dist/logger/defaults.js +40 -40
- package/dist/logger/index.d.ts +1 -0
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js.map +1 -1
- package/dist/logger/logger.d.ts +8 -0
- package/dist/logger/logger.d.ts.map +1 -1
- package/dist/logger/logger.js +13 -3
- package/dist/logger/logger.js.map +1 -1
- package/dist/logger/transports/console.js +2 -2
- package/dist/logger/transports/http.d.ts +1 -1
- package/dist/logger/transports/http.js +2 -2
- package/dist/logger/transports/webhook.d.ts +1 -1
- package/dist/logger/transports/webhook.js +3 -3
- package/dist/queue/defaults.d.ts +2 -2
- package/dist/queue/defaults.js +38 -38
- package/dist/security/defaults.d.ts +1 -1
- package/dist/security/defaults.js +30 -30
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +3 -3
- package/dist/security/security.d.ts +1 -1
- package/dist/security/security.js +4 -4
- package/dist/storage/defaults.js +26 -26
- package/dist/storage/index.js +3 -3
- package/dist/util/defaults.d.ts +1 -1
- package/dist/util/defaults.js +41 -41
- package/dist/util/env.d.ts +35 -0
- package/dist/util/env.d.ts.map +1 -0
- package/dist/util/env.js +50 -0
- package/dist/util/env.js.map +1 -0
- package/dist/util/errors.d.ts +52 -0
- package/dist/util/errors.d.ts.map +1 -0
- package/dist/util/errors.js +82 -0
- package/dist/util/errors.js.map +1 -0
- package/dist/util/util.js +1 -1
- package/examples/.env.example +80 -0
- package/examples/README.md +16 -0
- package/examples/auth.ts +228 -0
- package/examples/cache.ts +36 -0
- package/examples/config.ts +45 -0
- package/examples/database.ts +69 -0
- package/examples/email.ts +53 -0
- package/examples/error.ts +50 -0
- package/examples/event.ts +42 -0
- package/examples/logger.ts +41 -0
- package/examples/queue.ts +58 -0
- package/examples/security.ts +46 -0
- package/examples/storage.ts +44 -0
- package/examples/util.ts +47 -0
- package/llms.txt +591 -0
- package/package.json +19 -10
- package/src/auth/README.md +850 -0
- package/src/cache/README.md +756 -0
- package/src/config/README.md +604 -0
- package/src/database/README.md +818 -0
- package/src/email/README.md +759 -0
- package/src/error/README.md +660 -0
- package/src/event/README.md +729 -0
- package/src/logger/README.md +435 -0
- package/src/queue/README.md +851 -0
- package/src/security/README.md +612 -0
- package/src/storage/README.md +1008 -0
- package/src/util/README.md +955 -0
- package/bin/templates/backend/docs/APPKIT_CLI.md +0 -507
- package/bin/templates/backend/docs/APPKIT_COMMENTS_GUIDELINES.md +0 -61
- package/bin/templates/backend/docs/APPKIT_LLM_GUIDE.md +0 -2539
package/dist/cache/cache.js
CHANGED
|
@@ -9,6 +9,36 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { RedisStrategy } from './strategies/redis.js';
|
|
11
11
|
import { MemoryStrategy } from './strategies/memory.js';
|
|
12
|
+
/**
|
|
13
|
+
* Thrown by all cache operations when the underlying strategy fails.
|
|
14
|
+
* Catch this in your route/service and decide whether to fall back to the
|
|
15
|
+
* database, re-throw, or log — the cache module never makes that call for you.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* import { CacheError } from '@bloomneo/appkit/cache';
|
|
19
|
+
*
|
|
20
|
+
* try {
|
|
21
|
+
* const user = await cache.get<User>('user:123');
|
|
22
|
+
* } catch (err) {
|
|
23
|
+
* if (err instanceof CacheError) {
|
|
24
|
+
* logger.warn('Cache unavailable, falling back to DB', { code: err.code });
|
|
25
|
+
* return await db.user.findUnique({ where: { id: 123 } });
|
|
26
|
+
* }
|
|
27
|
+
* throw err; // re-throw unrelated errors
|
|
28
|
+
* }
|
|
29
|
+
*/
|
|
30
|
+
export class CacheError extends Error {
|
|
31
|
+
/** Machine-readable error code, e.g. 'CACHE_GET_FAILED', 'CACHE_CONNECT_FAILED' */
|
|
32
|
+
code;
|
|
33
|
+
constructor(message, options) {
|
|
34
|
+
super(`[@bloomneo/appkit/cache] ${message}`);
|
|
35
|
+
this.name = 'CacheError';
|
|
36
|
+
this.code = options?.code ?? 'CACHE_ERROR';
|
|
37
|
+
if (options?.cause) {
|
|
38
|
+
this.cause = options.cause;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
12
42
|
/**
|
|
13
43
|
* Cache class with automatic strategy selection and ultra-simple API
|
|
14
44
|
*/
|
|
@@ -49,12 +79,11 @@ export class CacheClass {
|
|
|
49
79
|
await this.strategy.connect();
|
|
50
80
|
this.connected = true;
|
|
51
81
|
if (this.config.environment.isDevelopment) {
|
|
52
|
-
console.log(
|
|
82
|
+
console.log(`[@bloomneo/appkit/cache] Connected using ${this.config.strategy} strategy.`);
|
|
53
83
|
}
|
|
54
84
|
}
|
|
55
|
-
catch (
|
|
56
|
-
|
|
57
|
-
throw error;
|
|
85
|
+
catch (cause) {
|
|
86
|
+
throw new CacheError(`Failed to connect using ${this.config.strategy} strategy: ${cause.message}`, { code: 'CACHE_CONNECT_FAILED', cause });
|
|
58
87
|
}
|
|
59
88
|
}
|
|
60
89
|
/**
|
|
@@ -69,11 +98,13 @@ export class CacheClass {
|
|
|
69
98
|
await this.strategy.disconnect();
|
|
70
99
|
this.connected = false;
|
|
71
100
|
if (this.config.environment.isDevelopment) {
|
|
72
|
-
console.log(
|
|
101
|
+
console.log(`[@bloomneo/appkit/cache] Disconnected.`);
|
|
73
102
|
}
|
|
74
103
|
}
|
|
75
|
-
catch (
|
|
76
|
-
|
|
104
|
+
catch (cause) {
|
|
105
|
+
// Disconnect errors are non-fatal — log a warning but don't throw.
|
|
106
|
+
// Throwing during shutdown can mask the original reason the app is shutting down.
|
|
107
|
+
console.warn(`[@bloomneo/appkit/cache] Disconnect warning:`, cause.message);
|
|
77
108
|
}
|
|
78
109
|
}
|
|
79
110
|
/**
|
|
@@ -85,13 +116,15 @@ export class CacheClass {
|
|
|
85
116
|
async get(key) {
|
|
86
117
|
this.validateKey(key);
|
|
87
118
|
await this.ensureConnected();
|
|
119
|
+
const prefixedKey = this.buildKey(key);
|
|
88
120
|
try {
|
|
89
|
-
const prefixedKey = this.buildKey(key);
|
|
90
121
|
return await this.strategy.get(prefixedKey);
|
|
91
122
|
}
|
|
92
|
-
catch (
|
|
93
|
-
|
|
94
|
-
|
|
123
|
+
catch (cause) {
|
|
124
|
+
throw new CacheError(`get failed for key "${key}": ${cause.message}`, {
|
|
125
|
+
code: 'CACHE_GET_FAILED',
|
|
126
|
+
cause,
|
|
127
|
+
});
|
|
95
128
|
}
|
|
96
129
|
}
|
|
97
130
|
/**
|
|
@@ -104,14 +137,16 @@ export class CacheClass {
|
|
|
104
137
|
this.validateKey(key);
|
|
105
138
|
this.validateValue(value);
|
|
106
139
|
await this.ensureConnected();
|
|
140
|
+
const prefixedKey = this.buildKey(key);
|
|
141
|
+
const cacheTTL = ttl ?? this.config.defaultTTL;
|
|
107
142
|
try {
|
|
108
|
-
const prefixedKey = this.buildKey(key);
|
|
109
|
-
const cacheTTL = ttl ?? this.config.defaultTTL;
|
|
110
143
|
return await this.strategy.set(prefixedKey, value, cacheTTL);
|
|
111
144
|
}
|
|
112
|
-
catch (
|
|
113
|
-
|
|
114
|
-
|
|
145
|
+
catch (cause) {
|
|
146
|
+
throw new CacheError(`set failed for key "${key}": ${cause.message}`, {
|
|
147
|
+
code: 'CACHE_SET_FAILED',
|
|
148
|
+
cause,
|
|
149
|
+
});
|
|
115
150
|
}
|
|
116
151
|
}
|
|
117
152
|
/**
|
|
@@ -122,13 +157,15 @@ export class CacheClass {
|
|
|
122
157
|
async delete(key) {
|
|
123
158
|
this.validateKey(key);
|
|
124
159
|
await this.ensureConnected();
|
|
160
|
+
const prefixedKey = this.buildKey(key);
|
|
125
161
|
try {
|
|
126
|
-
const prefixedKey = this.buildKey(key);
|
|
127
162
|
return await this.strategy.delete(prefixedKey);
|
|
128
163
|
}
|
|
129
|
-
catch (
|
|
130
|
-
|
|
131
|
-
|
|
164
|
+
catch (cause) {
|
|
165
|
+
throw new CacheError(`delete failed for key "${key}": ${cause.message}`, {
|
|
166
|
+
code: 'CACHE_DELETE_FAILED',
|
|
167
|
+
cause,
|
|
168
|
+
});
|
|
132
169
|
}
|
|
133
170
|
}
|
|
134
171
|
/**
|
|
@@ -140,7 +177,6 @@ export class CacheClass {
|
|
|
140
177
|
async clear() {
|
|
141
178
|
await this.ensureConnected();
|
|
142
179
|
try {
|
|
143
|
-
// Get all keys in this namespace and delete them
|
|
144
180
|
const pattern = this.buildKey('*');
|
|
145
181
|
const keys = await this.strategy.keys(pattern);
|
|
146
182
|
if (keys.length === 0)
|
|
@@ -148,9 +184,11 @@ export class CacheClass {
|
|
|
148
184
|
const deleted = await this.strategy.deleteMany(keys);
|
|
149
185
|
return deleted === keys.length;
|
|
150
186
|
}
|
|
151
|
-
catch (
|
|
152
|
-
|
|
153
|
-
|
|
187
|
+
catch (cause) {
|
|
188
|
+
throw new CacheError(`clear failed for namespace "${this.namespace}": ${cause.message}`, {
|
|
189
|
+
code: 'CACHE_CLEAR_FAILED',
|
|
190
|
+
cause,
|
|
191
|
+
});
|
|
154
192
|
}
|
|
155
193
|
}
|
|
156
194
|
/**
|
|
@@ -166,15 +204,9 @@ export class CacheClass {
|
|
|
166
204
|
return existing;
|
|
167
205
|
}
|
|
168
206
|
// Generate new value and cache it
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return value;
|
|
173
|
-
}
|
|
174
|
-
catch (error) {
|
|
175
|
-
console.error(`[AppKit] Cache getOrSet factory error for key "${key}":`, error.message);
|
|
176
|
-
throw error; // Re-throw factory errors
|
|
177
|
-
}
|
|
207
|
+
const value = await factory(); // factory errors propagate as-is — not wrapped in CacheError
|
|
208
|
+
await this.set(key, value, ttl);
|
|
209
|
+
return value;
|
|
178
210
|
}
|
|
179
211
|
/**
|
|
180
212
|
* Gets current cache strategy name for debugging
|
|
@@ -218,31 +250,27 @@ export class CacheClass {
|
|
|
218
250
|
*/
|
|
219
251
|
validateKey(key) {
|
|
220
252
|
if (!key || typeof key !== 'string') {
|
|
221
|
-
throw new
|
|
253
|
+
throw new CacheError('Cache key must be a non-empty string', { code: 'CACHE_INVALID_KEY' });
|
|
222
254
|
}
|
|
223
255
|
if (key.length > 250) {
|
|
224
|
-
throw new
|
|
256
|
+
throw new CacheError('Cache key too long (max 250 characters)', { code: 'CACHE_INVALID_KEY' });
|
|
225
257
|
}
|
|
226
258
|
if (key.includes('\n') || key.includes('\r')) {
|
|
227
|
-
throw new
|
|
259
|
+
throw new CacheError('Cache key cannot contain newline characters', { code: 'CACHE_INVALID_KEY' });
|
|
228
260
|
}
|
|
229
261
|
if (key.includes(':')) {
|
|
230
|
-
throw new
|
|
262
|
+
throw new CacheError('Cache key cannot contain colon characters (reserved for namespacing)', { code: 'CACHE_INVALID_KEY' });
|
|
231
263
|
}
|
|
232
264
|
}
|
|
233
|
-
/**
|
|
234
|
-
* Validates cache value
|
|
235
|
-
*/
|
|
236
265
|
validateValue(value) {
|
|
237
266
|
if (value === undefined) {
|
|
238
|
-
throw new
|
|
267
|
+
throw new CacheError('Cannot cache undefined values', { code: 'CACHE_INVALID_VALUE' });
|
|
239
268
|
}
|
|
240
|
-
// Check if value can be serialized
|
|
241
269
|
try {
|
|
242
270
|
JSON.stringify(value);
|
|
243
271
|
}
|
|
244
|
-
catch
|
|
245
|
-
throw new
|
|
272
|
+
catch {
|
|
273
|
+
throw new CacheError('Value must be JSON serializable', { code: 'CACHE_INVALID_VALUE' });
|
|
246
274
|
}
|
|
247
275
|
}
|
|
248
276
|
}
|
package/dist/cache/cache.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/cache/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/cache/cache.ts"],"names":[],"mappings":"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"}
|
package/dist/cache/defaults.js
CHANGED
|
@@ -25,24 +25,24 @@ export function getSmartDefaults() {
|
|
|
25
25
|
// Strategy selection with smart detection
|
|
26
26
|
strategy,
|
|
27
27
|
// Key management with service identification
|
|
28
|
-
keyPrefix: process.env.
|
|
29
|
-
namespace: process.env.
|
|
28
|
+
keyPrefix: process.env.BLOOM_CACHE_PREFIX || process.env.BLOOM_SERVICE_NAME || 'app',
|
|
29
|
+
namespace: process.env.BLOOM_CACHE_NAMESPACE || 'default',
|
|
30
30
|
// TTL configuration with environment awareness
|
|
31
|
-
defaultTTL: parseInt(process.env.
|
|
31
|
+
defaultTTL: parseInt(process.env.BLOOM_CACHE_TTL || (isProduction ? '3600' : '300')), // 1hr prod, 5min dev
|
|
32
32
|
// Redis configuration (only used when strategy is 'redis')
|
|
33
33
|
redis: {
|
|
34
34
|
url: process.env.REDIS_URL || 'redis://localhost:6379',
|
|
35
35
|
password: process.env.REDIS_PASSWORD,
|
|
36
|
-
maxRetries: parseInt(process.env.
|
|
37
|
-
retryDelay: parseInt(process.env.
|
|
38
|
-
connectTimeout: parseInt(process.env.
|
|
39
|
-
commandTimeout: parseInt(process.env.
|
|
36
|
+
maxRetries: parseInt(process.env.BLOOM_CACHE_REDIS_RETRIES || '3'),
|
|
37
|
+
retryDelay: parseInt(process.env.BLOOM_CACHE_REDIS_RETRY_DELAY || '1000'),
|
|
38
|
+
connectTimeout: parseInt(process.env.BLOOM_CACHE_REDIS_CONNECT_TIMEOUT || '10000'),
|
|
39
|
+
commandTimeout: parseInt(process.env.BLOOM_CACHE_REDIS_COMMAND_TIMEOUT || '5000'),
|
|
40
40
|
},
|
|
41
41
|
// Memory configuration (only used when strategy is 'memory')
|
|
42
42
|
memory: {
|
|
43
|
-
maxItems: parseInt(process.env.
|
|
44
|
-
maxSizeBytes: parseInt(process.env.
|
|
45
|
-
checkInterval: parseInt(process.env.
|
|
43
|
+
maxItems: parseInt(process.env.BLOOM_CACHE_MEMORY_MAX_ITEMS || '10000'),
|
|
44
|
+
maxSizeBytes: parseInt(process.env.BLOOM_CACHE_MEMORY_MAX_SIZE || '100000000'), // 100MB
|
|
45
|
+
checkInterval: parseInt(process.env.BLOOM_CACHE_MEMORY_CHECK_INTERVAL || '60000'), // 1 minute
|
|
46
46
|
},
|
|
47
47
|
// Environment information
|
|
48
48
|
environment: {
|
|
@@ -61,7 +61,7 @@ export function getSmartDefaults() {
|
|
|
61
61
|
*/
|
|
62
62
|
function detectCacheStrategy() {
|
|
63
63
|
// Explicit override wins (for testing/debugging)
|
|
64
|
-
const explicit = process.env.
|
|
64
|
+
const explicit = process.env.BLOOM_CACHE_STRATEGY?.toLowerCase();
|
|
65
65
|
if (explicit === 'redis' || explicit === 'memory') {
|
|
66
66
|
return explicit;
|
|
67
67
|
}
|
|
@@ -70,7 +70,7 @@ function detectCacheStrategy() {
|
|
|
70
70
|
return 'redis'; // Redis URL available
|
|
71
71
|
}
|
|
72
72
|
if (process.env.NODE_ENV === 'production') {
|
|
73
|
-
console.warn('[
|
|
73
|
+
console.warn('[Bloomneo AppKit] No REDIS_URL found in production. ' +
|
|
74
74
|
'Using memory cache which will not persist across server restarts. ' +
|
|
75
75
|
'Set REDIS_URL for production caching.');
|
|
76
76
|
}
|
|
@@ -89,41 +89,41 @@ function validateEnvironment() {
|
|
|
89
89
|
throw new Error(`Invalid REDIS_URL: "${redisUrl}". Must start with redis:// or rediss://`);
|
|
90
90
|
}
|
|
91
91
|
// Validate cache strategy if explicitly set
|
|
92
|
-
const strategy = process.env.
|
|
92
|
+
const strategy = process.env.BLOOM_CACHE_STRATEGY;
|
|
93
93
|
if (strategy && !['redis', 'memory'].includes(strategy.toLowerCase())) {
|
|
94
|
-
throw new Error(`Invalid
|
|
94
|
+
throw new Error(`Invalid BLOOM_CACHE_STRATEGY: "${strategy}". Must be "redis" or "memory"`);
|
|
95
95
|
}
|
|
96
96
|
// Validate numeric values
|
|
97
|
-
validateNumericEnv('
|
|
98
|
-
validateNumericEnv('
|
|
99
|
-
validateNumericEnv('
|
|
100
|
-
validateNumericEnv('
|
|
101
|
-
validateNumericEnv('
|
|
102
|
-
validateNumericEnv('
|
|
103
|
-
validateNumericEnv('
|
|
104
|
-
validateNumericEnv('
|
|
97
|
+
validateNumericEnv('BLOOM_CACHE_TTL', 1, 86400 * 7); // 1 second to 1 week
|
|
98
|
+
validateNumericEnv('BLOOM_CACHE_REDIS_RETRIES', 0, 10);
|
|
99
|
+
validateNumericEnv('BLOOM_CACHE_REDIS_RETRY_DELAY', 100, 10000);
|
|
100
|
+
validateNumericEnv('BLOOM_CACHE_REDIS_CONNECT_TIMEOUT', 1000, 60000);
|
|
101
|
+
validateNumericEnv('BLOOM_CACHE_REDIS_COMMAND_TIMEOUT', 1000, 30000);
|
|
102
|
+
validateNumericEnv('BLOOM_CACHE_MEMORY_MAX_ITEMS', 100, 1000000);
|
|
103
|
+
validateNumericEnv('BLOOM_CACHE_MEMORY_MAX_SIZE', 1000000, 1000000000); // 1MB to 1GB
|
|
104
|
+
validateNumericEnv('BLOOM_CACHE_MEMORY_CHECK_INTERVAL', 10000, 300000); // 10s to 5min
|
|
105
105
|
// Validate key prefix
|
|
106
|
-
const keyPrefix = process.env.
|
|
106
|
+
const keyPrefix = process.env.BLOOM_CACHE_PREFIX;
|
|
107
107
|
if (keyPrefix && !/^[a-zA-Z0-9_-]+$/.test(keyPrefix)) {
|
|
108
|
-
throw new Error(`Invalid
|
|
108
|
+
throw new Error(`Invalid BLOOM_CACHE_PREFIX: "${keyPrefix}". Must contain only letters, numbers, underscores, and hyphens`);
|
|
109
109
|
}
|
|
110
110
|
// Validate namespace
|
|
111
|
-
const namespace = process.env.
|
|
111
|
+
const namespace = process.env.BLOOM_CACHE_NAMESPACE;
|
|
112
112
|
if (namespace && !/^[a-zA-Z0-9_-]+$/.test(namespace)) {
|
|
113
|
-
throw new Error(`Invalid
|
|
113
|
+
throw new Error(`Invalid BLOOM_CACHE_NAMESPACE: "${namespace}". Must contain only letters, numbers, underscores, and hyphens`);
|
|
114
114
|
}
|
|
115
115
|
// Production-specific validations
|
|
116
116
|
const nodeEnv = process.env.NODE_ENV;
|
|
117
117
|
if (nodeEnv === 'production') {
|
|
118
118
|
if (!redisUrl) {
|
|
119
|
-
console.warn('[
|
|
119
|
+
console.warn('[Bloomneo AppKit] Production environment detected without REDIS_URL. ' +
|
|
120
120
|
'Memory cache will not persist across server restarts. ' +
|
|
121
121
|
'Consider setting REDIS_URL for production deployments.');
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
// Validate NODE_ENV
|
|
125
125
|
if (nodeEnv && !['development', 'production', 'test', 'staging'].includes(nodeEnv)) {
|
|
126
|
-
console.warn(`[
|
|
126
|
+
console.warn(`[Bloomneo AppKit] Unusual NODE_ENV: "${nodeEnv}". ` +
|
|
127
127
|
`Expected: development, production, test, or staging`);
|
|
128
128
|
}
|
|
129
129
|
}
|
|
@@ -180,7 +180,7 @@ export function validateProductionRequirements() {
|
|
|
180
180
|
const config = getSmartDefaults();
|
|
181
181
|
if (config.environment.isProduction) {
|
|
182
182
|
if (config.strategy === 'memory') {
|
|
183
|
-
console.warn('[
|
|
183
|
+
console.warn('[Bloomneo AppKit] Using memory cache in production. ' +
|
|
184
184
|
'Data will not persist across server restarts. ' +
|
|
185
185
|
'Set REDIS_URL for persistent caching.');
|
|
186
186
|
}
|
package/dist/cache/index.d.ts
CHANGED
|
@@ -10,13 +10,19 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { type CacheConfig } from './defaults.js';
|
|
12
12
|
export interface Cache {
|
|
13
|
-
get(key: string): Promise<
|
|
14
|
-
set(key: string, value:
|
|
13
|
+
get<T = unknown>(key: string): Promise<T | null>;
|
|
14
|
+
set<T = unknown>(key: string, value: T, ttl?: number): Promise<boolean>;
|
|
15
15
|
delete(key: string): Promise<boolean>;
|
|
16
16
|
clear(): Promise<boolean>;
|
|
17
|
-
getOrSet(key: string, factory: () => Promise<
|
|
17
|
+
getOrSet<T = unknown>(key: string, factory: () => Promise<T>, ttl?: number): Promise<T>;
|
|
18
18
|
getStrategy(): string;
|
|
19
|
-
getConfig():
|
|
19
|
+
getConfig(): {
|
|
20
|
+
strategy: string;
|
|
21
|
+
keyPrefix: string;
|
|
22
|
+
namespace: string;
|
|
23
|
+
defaultTTL: number;
|
|
24
|
+
connected: boolean;
|
|
25
|
+
};
|
|
20
26
|
}
|
|
21
27
|
/**
|
|
22
28
|
* Get cache instance for specific namespace - the only function you need to learn
|
|
@@ -27,11 +33,14 @@ export interface Cache {
|
|
|
27
33
|
*/
|
|
28
34
|
declare function get(namespace?: string): Cache;
|
|
29
35
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
36
|
+
* Disconnect all cache instances and reset internal state.
|
|
37
|
+
* Use this for full teardown (e.g., end-of-suite cleanup).
|
|
38
|
+
* For clearing cached data between individual tests use flushAll().
|
|
39
|
+
*
|
|
40
|
+
* @llm-rule WHEN: End-of-test-suite teardown or app restart
|
|
41
|
+
* @llm-rule AVOID: Calling between individual tests — use flushAll() instead
|
|
33
42
|
*/
|
|
34
|
-
declare function
|
|
43
|
+
declare function disconnectAll(): Promise<void>;
|
|
35
44
|
/**
|
|
36
45
|
* Reset cache configuration (useful for testing)
|
|
37
46
|
* @llm-rule WHEN: Testing cache logic with different environment configurations
|
|
@@ -86,7 +95,7 @@ declare function shutdown(): Promise<void>;
|
|
|
86
95
|
*/
|
|
87
96
|
export declare const cacheClass: {
|
|
88
97
|
readonly get: typeof get;
|
|
89
|
-
readonly
|
|
98
|
+
readonly disconnectAll: typeof disconnectAll;
|
|
90
99
|
readonly reset: typeof reset;
|
|
91
100
|
readonly getStrategy: typeof getStrategy;
|
|
92
101
|
readonly getActiveNamespaces: typeof getActiveNamespaces;
|
|
@@ -96,6 +105,6 @@ export declare const cacheClass: {
|
|
|
96
105
|
readonly shutdown: typeof shutdown;
|
|
97
106
|
};
|
|
98
107
|
export type { CacheConfig } from './defaults.js';
|
|
99
|
-
export { CacheClass } from './cache.js';
|
|
108
|
+
export { CacheClass, CacheError } from './cache.js';
|
|
100
109
|
export default cacheClass;
|
|
101
110
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAMnE,MAAM,WAAW,KAAK;IACpB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAMnE,MAAM,WAAW,KAAK;IACpB,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACjD,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtC,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACxF,WAAW,IAAI,MAAM,CAAC;IACtB,SAAS,IAAI;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;CACjH;AAED;;;;;;GAMG;AACH,iBAAS,GAAG,CAAC,SAAS,GAAE,MAAc,GAAG,KAAK,CA8B7C;AAED;;;;;;;GAOG;AACH,iBAAe,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAc5C;AAED;;;;GAIG;AACH,iBAAe,KAAK,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAWpE;AAED;;;;GAIG;AACH,iBAAS,WAAW,IAAI,MAAM,CAK7B;AAED;;;;GAIG;AACH,iBAAS,mBAAmB,IAAI,MAAM,EAAE,CAEvC;AAED;;;;GAIG;AACH,iBAAS,SAAS,IAAI;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB,CAYA;AAED;;;;GAIG;AACH,iBAAS,QAAQ,IAAI,OAAO,CAE3B;AAED;;;;;GAKG;AACH,iBAAe,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC,CAc1C;AAED;;;;GAIG;AACH,iBAAe,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CASvC;AAED;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;CAab,CAAC;AAGX,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGpD,eAAe,UAAU,CAAC"}
|
package/dist/cache/index.js
CHANGED
|
@@ -40,21 +40,24 @@ function get(namespace = 'app') {
|
|
|
40
40
|
const cacheInstance = new CacheClass(globalConfig, namespace);
|
|
41
41
|
// Auto-connect on first use
|
|
42
42
|
cacheInstance.connect().catch((error) => {
|
|
43
|
-
console.error(`[
|
|
43
|
+
console.error(`[@bloomneo/appkit/cache] Auto-connect failed for namespace "${namespace}":`, error.message);
|
|
44
44
|
});
|
|
45
45
|
namedCaches.set(namespace, cacheInstance);
|
|
46
46
|
return cacheInstance;
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
49
|
+
* Disconnect all cache instances and reset internal state.
|
|
50
|
+
* Use this for full teardown (e.g., end-of-suite cleanup).
|
|
51
|
+
* For clearing cached data between individual tests use flushAll().
|
|
52
|
+
*
|
|
53
|
+
* @llm-rule WHEN: End-of-test-suite teardown or app restart
|
|
54
|
+
* @llm-rule AVOID: Calling between individual tests — use flushAll() instead
|
|
52
55
|
*/
|
|
53
|
-
async function
|
|
56
|
+
async function disconnectAll() {
|
|
54
57
|
const disconnectPromises = [];
|
|
55
58
|
for (const [namespace, cache] of namedCaches) {
|
|
56
59
|
disconnectPromises.push(cache.disconnect().catch((error) => {
|
|
57
|
-
console.error(`[
|
|
60
|
+
console.error(`[@bloomneo/appkit/cache] Disconnect failed for namespace "${namespace}":`, error.message);
|
|
58
61
|
}));
|
|
59
62
|
}
|
|
60
63
|
await Promise.all(disconnectPromises);
|
|
@@ -67,8 +70,8 @@ async function clear() {
|
|
|
67
70
|
* @llm-rule AVOID: Using in production - only for tests and development
|
|
68
71
|
*/
|
|
69
72
|
async function reset(newConfig) {
|
|
70
|
-
//
|
|
71
|
-
await
|
|
73
|
+
// Disconnect existing instances before reconfiguring
|
|
74
|
+
await disconnectAll();
|
|
72
75
|
// Reset configuration
|
|
73
76
|
if (newConfig) {
|
|
74
77
|
const defaults = getSmartDefaults();
|
|
@@ -138,7 +141,7 @@ async function flushAll() {
|
|
|
138
141
|
return results.every(result => result === true);
|
|
139
142
|
}
|
|
140
143
|
catch (error) {
|
|
141
|
-
console.error('[
|
|
144
|
+
console.error('[@bloomneo/appkit/cache] flushAll error:', error.message);
|
|
142
145
|
return false;
|
|
143
146
|
}
|
|
144
147
|
}
|
|
@@ -148,13 +151,13 @@ async function flushAll() {
|
|
|
148
151
|
* @llm-rule AVOID: Abrupt process exit - graceful shutdown prevents data loss
|
|
149
152
|
*/
|
|
150
153
|
async function shutdown() {
|
|
151
|
-
console.log('
|
|
154
|
+
console.log('[@bloomneo/appkit/cache] Graceful shutdown starting...');
|
|
152
155
|
try {
|
|
153
|
-
await
|
|
154
|
-
console.log('
|
|
156
|
+
await disconnectAll();
|
|
157
|
+
console.log('[@bloomneo/appkit/cache] Shutdown complete.');
|
|
155
158
|
}
|
|
156
159
|
catch (error) {
|
|
157
|
-
console.error('
|
|
160
|
+
console.error('[@bloomneo/appkit/cache] Shutdown error:', error.message);
|
|
158
161
|
}
|
|
159
162
|
}
|
|
160
163
|
/**
|
|
@@ -164,16 +167,16 @@ export const cacheClass = {
|
|
|
164
167
|
// Core method (like auth.get())
|
|
165
168
|
get,
|
|
166
169
|
// Utility methods
|
|
167
|
-
clear
|
|
170
|
+
disconnectAll, // Disconnects all instances + resets state. Use flushAll() to clear data between tests.
|
|
168
171
|
reset,
|
|
169
172
|
getStrategy,
|
|
170
173
|
getActiveNamespaces,
|
|
171
174
|
getConfig,
|
|
172
175
|
hasRedis,
|
|
173
|
-
flushAll,
|
|
176
|
+
flushAll, // Clears cached data across all namespaces. Use between individual tests.
|
|
174
177
|
shutdown,
|
|
175
178
|
};
|
|
176
|
-
export { CacheClass } from './cache.js';
|
|
179
|
+
export { CacheClass, CacheError } from './cache.js';
|
|
177
180
|
// Default export
|
|
178
181
|
export default cacheClass;
|
|
179
182
|
// Auto-setup graceful shutdown handlers
|
|
@@ -188,13 +191,13 @@ if (typeof process !== 'undefined') {
|
|
|
188
191
|
process.on('SIGINT', shutdownHandler);
|
|
189
192
|
// Handle uncaught errors
|
|
190
193
|
process.on('uncaughtException', (error) => {
|
|
191
|
-
console.error('[
|
|
194
|
+
console.error('[@bloomneo/appkit/cache] Uncaught exception:', error);
|
|
192
195
|
shutdown().finally(() => {
|
|
193
196
|
process.exit(1);
|
|
194
197
|
});
|
|
195
198
|
});
|
|
196
199
|
process.on('unhandledRejection', (reason) => {
|
|
197
|
-
console.error('[
|
|
200
|
+
console.error('[@bloomneo/appkit/cache] Unhandled rejection:', reason);
|
|
198
201
|
shutdown().finally(() => {
|
|
199
202
|
process.exit(1);
|
|
200
203
|
});
|
package/dist/cache/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAoB,MAAM,eAAe,CAAC;AAEnE,4DAA4D;AAC5D,IAAI,YAAY,GAAuB,IAAI,CAAC;AAC5C,MAAM,WAAW,GAAG,IAAI,GAAG,EAAsB,CAAC;AAYlD;;;;;;GAMG;AACH,SAAS,GAAG,CAAC,YAAoB,KAAK;IACpC,qBAAqB;IACrB,IAAI,CAAC,SAAS,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAC;IAClG,CAAC;IAED,2DAA2D;IAC3D,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,gBAAgB,EAAE,CAAC;IACpC,CAAC;IAED,mCAAmC;IACnC,IAAI,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/B,OAAO,WAAW,CAAC,GAAG,CAAC,SAAS,CAAE,CAAC;IACrC,CAAC;IAED,0CAA0C;IAC1C,MAAM,aAAa,GAAG,IAAI,UAAU,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IAE9D,4BAA4B;IAC5B,aAAa,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACtC,OAAO,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,7 +25,7 @@ export interface AppConfig extends ConfigValue {
|
|
|
25
25
|
* @llm-rule AVOID: Calling repeatedly - validates environment each time, expensive operation
|
|
26
26
|
* @llm-rule NOTE: Called once at startup, cached globally for performance
|
|
27
27
|
* @llm-rule CONVENTION: Only processes non-framework variables for user config
|
|
28
|
-
* @llm-rule CONVENTION: Variables with
|
|
28
|
+
* @llm-rule CONVENTION: Variables with BLOOM_* and FLUX_* are AppKit internal
|
|
29
29
|
*/
|
|
30
30
|
export declare function buildConfigFromEnv(): AppConfig;
|
|
31
31
|
/**
|