@bloomneo/appkit 1.2.9 → 1.5.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/dist/cache/defaults.js +4 -4
- package/dist/config/defaults.js +5 -5
- package/dist/database/adapters/mongoose.d.ts +4 -4
- package/dist/database/adapters/mongoose.js +5 -5
- package/dist/database/adapters/prisma.d.ts +4 -4
- package/dist/database/adapters/prisma.js +5 -5
- package/dist/email/defaults.js +6 -6
- package/dist/email/index.js +7 -7
- package/dist/email/strategies/resend.js +1 -1
- package/dist/error/defaults.js +2 -2
- package/dist/event/defaults.js +5 -5
- package/dist/event/index.js +7 -7
- package/dist/logger/transports/console.js +1 -1
- package/dist/logger/transports/http.js +1 -1
- package/dist/logger/transports/webhook.js +2 -2
- package/dist/security/defaults.js +3 -3
- package/dist/storage/defaults.js +7 -7
- package/dist/storage/index.js +3 -3
- package/dist/util/defaults.js +7 -7
- package/dist/util/util.js +1 -1
- package/package.json +1 -1
package/dist/cache/defaults.js
CHANGED
|
@@ -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
|
}
|
|
@@ -116,14 +116,14 @@ function validateEnvironment() {
|
|
|
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/config/defaults.js
CHANGED
|
@@ -65,7 +65,7 @@ function setNestedValue(obj, path, value) {
|
|
|
65
65
|
function validateEnvironment() {
|
|
66
66
|
const nodeEnv = process.env.NODE_ENV;
|
|
67
67
|
if (nodeEnv && !['development', 'production', 'test', 'staging'].includes(nodeEnv)) {
|
|
68
|
-
console.warn(`[
|
|
68
|
+
console.warn(`[Bloomneo AppKit] Unusual NODE_ENV: "${nodeEnv}". ` +
|
|
69
69
|
`Expected: development, production, test, or staging.`);
|
|
70
70
|
}
|
|
71
71
|
// Validate common required variables in production
|
|
@@ -73,7 +73,7 @@ function validateEnvironment() {
|
|
|
73
73
|
const requiredProdVars = ['VOILA_SERVICE_NAME'];
|
|
74
74
|
const missing = requiredProdVars.filter(varName => !process.env[varName]);
|
|
75
75
|
if (missing.length > 0) {
|
|
76
|
-
console.warn(`[
|
|
76
|
+
console.warn(`[Bloomneo AppKit] Missing recommended production environment variables: ${missing.join(', ')}`);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
}
|
|
@@ -81,11 +81,11 @@ function validateEnvironment() {
|
|
|
81
81
|
* Check if environment variable is a framework variable that should be ignored
|
|
82
82
|
* @llm-rule WHEN: Filtering out framework variables from app config parsing
|
|
83
83
|
* @llm-rule AVOID: Parsing framework variables as app config - they serve different purposes
|
|
84
|
-
* @llm-rule NOTE:
|
|
84
|
+
* @llm-rule NOTE: Bloomneo AppKit uses VOILA_* and FLUX_* for internal configuration
|
|
85
85
|
*/
|
|
86
86
|
function isFrameworkVariable(envKey) {
|
|
87
87
|
const frameworkPrefixes = [
|
|
88
|
-
'VOILA_', //
|
|
88
|
+
'VOILA_', // Bloomneo AppKit framework configuration
|
|
89
89
|
'FLUX_', // Flux Framework internal variables
|
|
90
90
|
'NODE_', // Node.js environment variables
|
|
91
91
|
'npm_', // npm variables
|
|
@@ -146,7 +146,7 @@ function validateEnvVarFormat(envKey) {
|
|
|
146
146
|
}
|
|
147
147
|
// Check for proper UPPER_SNAKE_CASE format
|
|
148
148
|
if (envKey !== envKey.toUpperCase()) {
|
|
149
|
-
console.warn(`[
|
|
149
|
+
console.warn(`[Bloomneo AppKit] Environment variable "${envKey}" should be uppercase for consistency`);
|
|
150
150
|
}
|
|
151
151
|
return true;
|
|
152
152
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module @bloomneo/appkit/database
|
|
4
4
|
* @file src/database/adapters/mongoose.ts
|
|
5
5
|
*
|
|
6
|
-
* @llm-rule WHEN: Using Mongoose ODM with MongoDB databases in
|
|
6
|
+
* @llm-rule WHEN: Using Mongoose ODM with MongoDB databases in Bloomneo framework
|
|
7
7
|
* @llm-rule AVOID: Using with SQL databases - use prisma adapter instead
|
|
8
8
|
* @llm-rule NOTE: Auto-discovers apps from /apps directory structure, applies tenant filtering
|
|
9
9
|
*/
|
|
@@ -36,7 +36,7 @@ interface MongooseConnection {
|
|
|
36
36
|
[key: string]: any;
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
* Simplified Mongoose adapter with
|
|
39
|
+
* Simplified Mongoose adapter with Bloomneo app discovery
|
|
40
40
|
*/
|
|
41
41
|
export declare class MongooseAdapter {
|
|
42
42
|
private options;
|
|
@@ -54,7 +54,7 @@ export declare class MongooseAdapter {
|
|
|
54
54
|
*/
|
|
55
55
|
applyTenantMiddleware(connection: MongooseConnection, tenantId: string, options?: TenantMiddlewareOptions): Promise<MongooseConnection>;
|
|
56
56
|
/**
|
|
57
|
-
* Auto-discover
|
|
57
|
+
* Auto-discover Bloomneo apps with Mongoose models
|
|
58
58
|
*/
|
|
59
59
|
discoverApps(): Promise<DiscoveredApp[]>;
|
|
60
60
|
/**
|
|
@@ -82,7 +82,7 @@ export declare class MongooseAdapter {
|
|
|
82
82
|
*/
|
|
83
83
|
disconnect(): Promise<void>;
|
|
84
84
|
/**
|
|
85
|
-
* Detect current app from file path (
|
|
85
|
+
* Detect current app from file path (Bloomneo structure)
|
|
86
86
|
*/
|
|
87
87
|
private _detectCurrentApp;
|
|
88
88
|
/**
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module @bloomneo/appkit/database
|
|
4
4
|
* @file src/database/adapters/mongoose.ts
|
|
5
5
|
*
|
|
6
|
-
* @llm-rule WHEN: Using Mongoose ODM with MongoDB databases in
|
|
6
|
+
* @llm-rule WHEN: Using Mongoose ODM with MongoDB databases in Bloomneo framework
|
|
7
7
|
* @llm-rule AVOID: Using with SQL databases - use prisma adapter instead
|
|
8
8
|
* @llm-rule NOTE: Auto-discovers apps from /apps directory structure, applies tenant filtering
|
|
9
9
|
*/
|
|
@@ -11,7 +11,7 @@ import fs from 'fs';
|
|
|
11
11
|
import path from 'path';
|
|
12
12
|
import { createDatabaseError } from '../defaults.js';
|
|
13
13
|
/**
|
|
14
|
-
* Simplified Mongoose adapter with
|
|
14
|
+
* Simplified Mongoose adapter with Bloomneo app discovery
|
|
15
15
|
*/
|
|
16
16
|
export class MongooseAdapter {
|
|
17
17
|
options;
|
|
@@ -182,7 +182,7 @@ export class MongooseAdapter {
|
|
|
182
182
|
return connection;
|
|
183
183
|
}
|
|
184
184
|
/**
|
|
185
|
-
* Auto-discover
|
|
185
|
+
* Auto-discover Bloomneo apps with Mongoose models
|
|
186
186
|
*/
|
|
187
187
|
async discoverApps() {
|
|
188
188
|
if (this.discoveredApps)
|
|
@@ -203,7 +203,7 @@ export class MongooseAdapter {
|
|
|
203
203
|
.filter((dirent) => dirent.isDirectory())
|
|
204
204
|
.map((dirent) => dirent.name);
|
|
205
205
|
for (const appName of appFolders) {
|
|
206
|
-
//
|
|
206
|
+
// Bloomneo standard: apps/{appName}/models or apps/{appName}/src/models
|
|
207
207
|
const possibleModelPaths = [
|
|
208
208
|
path.join(appsDir, appName, 'models'),
|
|
209
209
|
path.join(appsDir, appName, 'src/models'),
|
|
@@ -341,7 +341,7 @@ export class MongooseAdapter {
|
|
|
341
341
|
}
|
|
342
342
|
// Private helper methods
|
|
343
343
|
/**
|
|
344
|
-
* Detect current app from file path (
|
|
344
|
+
* Detect current app from file path (Bloomneo structure)
|
|
345
345
|
*/
|
|
346
346
|
async _detectCurrentApp() {
|
|
347
347
|
try {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module @bloomneo/appkit/database
|
|
4
4
|
* @file src/database/adapters/prisma.ts
|
|
5
5
|
*
|
|
6
|
-
* @llm-rule WHEN: Using Prisma ORM with PostgreSQL, MySQL, or SQLite databases in
|
|
6
|
+
* @llm-rule WHEN: Using Prisma ORM with PostgreSQL, MySQL, or SQLite databases in Bloomneo framework
|
|
7
7
|
* @llm-rule AVOID: Using with MongoDB - use mongoose adapter instead
|
|
8
8
|
* @llm-rule NOTE: Auto-discovers apps from /apps directory structure, applies tenant filtering
|
|
9
9
|
*/
|
|
@@ -33,7 +33,7 @@ interface PrismaClient {
|
|
|
33
33
|
[key: string]: any;
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
|
-
* Simplified Prisma adapter with
|
|
36
|
+
* Simplified Prisma adapter with Bloomneo app discovery
|
|
37
37
|
*/
|
|
38
38
|
export declare class PrismaAdapter {
|
|
39
39
|
private options;
|
|
@@ -50,7 +50,7 @@ export declare class PrismaAdapter {
|
|
|
50
50
|
*/
|
|
51
51
|
applyTenantMiddleware(client: PrismaClient, tenantId: string, options?: TenantMiddlewareOptions): Promise<PrismaClient>;
|
|
52
52
|
/**
|
|
53
|
-
* Auto-discover
|
|
53
|
+
* Auto-discover Bloomneo apps with Prisma clients
|
|
54
54
|
*/
|
|
55
55
|
discoverApps(): Promise<DiscoveredApp[]>;
|
|
56
56
|
/**
|
|
@@ -78,7 +78,7 @@ export declare class PrismaAdapter {
|
|
|
78
78
|
*/
|
|
79
79
|
disconnect(): Promise<void>;
|
|
80
80
|
/**
|
|
81
|
-
* Detect current app from file path (
|
|
81
|
+
* Detect current app from file path (Bloomneo structure)
|
|
82
82
|
*/
|
|
83
83
|
private _detectCurrentApp;
|
|
84
84
|
/**
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module @bloomneo/appkit/database
|
|
4
4
|
* @file src/database/adapters/prisma.ts
|
|
5
5
|
*
|
|
6
|
-
* @llm-rule WHEN: Using Prisma ORM with PostgreSQL, MySQL, or SQLite databases in
|
|
6
|
+
* @llm-rule WHEN: Using Prisma ORM with PostgreSQL, MySQL, or SQLite databases in Bloomneo framework
|
|
7
7
|
* @llm-rule AVOID: Using with MongoDB - use mongoose adapter instead
|
|
8
8
|
* @llm-rule NOTE: Auto-discovers apps from /apps directory structure, applies tenant filtering
|
|
9
9
|
*/
|
|
@@ -11,7 +11,7 @@ import fs from 'fs';
|
|
|
11
11
|
import path from 'path';
|
|
12
12
|
import { createDatabaseError } from '../defaults.js';
|
|
13
13
|
/**
|
|
14
|
-
* Simplified Prisma adapter with
|
|
14
|
+
* Simplified Prisma adapter with Bloomneo app discovery
|
|
15
15
|
*/
|
|
16
16
|
export class PrismaAdapter {
|
|
17
17
|
options;
|
|
@@ -149,7 +149,7 @@ export class PrismaAdapter {
|
|
|
149
149
|
return client;
|
|
150
150
|
}
|
|
151
151
|
/**
|
|
152
|
-
* Auto-discover
|
|
152
|
+
* Auto-discover Bloomneo apps with Prisma clients
|
|
153
153
|
*/
|
|
154
154
|
async discoverApps() {
|
|
155
155
|
if (this.discoveredApps)
|
|
@@ -170,7 +170,7 @@ export class PrismaAdapter {
|
|
|
170
170
|
.filter((dirent) => dirent.isDirectory())
|
|
171
171
|
.map((dirent) => dirent.name);
|
|
172
172
|
for (const appName of appFolders) {
|
|
173
|
-
//
|
|
173
|
+
// Bloomneo standard: apps/{appName}/prisma/generated/client
|
|
174
174
|
const clientPath = path.join(appsDir, appName, 'prisma/generated/client/index.js');
|
|
175
175
|
if (fs.existsSync(clientPath)) {
|
|
176
176
|
apps.push({
|
|
@@ -315,7 +315,7 @@ export class PrismaAdapter {
|
|
|
315
315
|
}
|
|
316
316
|
// Private helper methods
|
|
317
317
|
/**
|
|
318
|
-
* Detect current app from file path (
|
|
318
|
+
* Detect current app from file path (Bloomneo structure)
|
|
319
319
|
*/
|
|
320
320
|
async _detectCurrentApp() {
|
|
321
321
|
try {
|
package/dist/email/defaults.js
CHANGED
|
@@ -84,7 +84,7 @@ function detectEmailStrategy() {
|
|
|
84
84
|
}
|
|
85
85
|
// Default to console for development/testing
|
|
86
86
|
if (process.env.NODE_ENV === 'production') {
|
|
87
|
-
console.warn('[
|
|
87
|
+
console.warn('[Bloomneo AppKit] No email provider configured in production. ' +
|
|
88
88
|
'Using console strategy which will only log emails. ' +
|
|
89
89
|
'Set RESEND_API_KEY or SMTP_HOST for production email sending.');
|
|
90
90
|
}
|
|
@@ -174,7 +174,7 @@ function validateEnvironment() {
|
|
|
174
174
|
}
|
|
175
175
|
// Validate NODE_ENV
|
|
176
176
|
if (nodeEnv && !['development', 'production', 'test', 'staging'].includes(nodeEnv)) {
|
|
177
|
-
console.warn(`[
|
|
177
|
+
console.warn(`[Bloomneo AppKit] Unusual NODE_ENV: "${nodeEnv}". ` +
|
|
178
178
|
`Expected: development, production, test, or staging`);
|
|
179
179
|
}
|
|
180
180
|
}
|
|
@@ -192,7 +192,7 @@ function validateSmtpConfig() {
|
|
|
192
192
|
}
|
|
193
193
|
// Many SMTP servers require authentication
|
|
194
194
|
if (!user && !pass) {
|
|
195
|
-
console.warn('[
|
|
195
|
+
console.warn('[Bloomneo AppKit] SMTP configured without authentication. ' +
|
|
196
196
|
'Set SMTP_USER and SMTP_PASS if your server requires authentication.');
|
|
197
197
|
}
|
|
198
198
|
if (user && !pass) {
|
|
@@ -210,14 +210,14 @@ function validateSmtpConfig() {
|
|
|
210
210
|
function validateProductionConfig() {
|
|
211
211
|
const strategy = detectEmailStrategy();
|
|
212
212
|
if (strategy === 'console') {
|
|
213
|
-
console.warn('[
|
|
213
|
+
console.warn('[Bloomneo AppKit] Using console email strategy in production. ' +
|
|
214
214
|
'Emails will only be logged, not sent. ' +
|
|
215
215
|
'Set RESEND_API_KEY or SMTP_HOST for production email sending.');
|
|
216
216
|
}
|
|
217
217
|
// Validate FROM email is set in production
|
|
218
218
|
const fromEmail = process.env.VOILA_EMAIL_FROM_EMAIL;
|
|
219
219
|
if (!fromEmail) {
|
|
220
|
-
console.warn('[
|
|
220
|
+
console.warn('[Bloomneo AppKit] No FROM email configured in production. ' +
|
|
221
221
|
'Set VOILA_EMAIL_FROM_EMAIL for professional email sending.');
|
|
222
222
|
}
|
|
223
223
|
}
|
|
@@ -269,7 +269,7 @@ export function validateProductionRequirements() {
|
|
|
269
269
|
const config = getSmartDefaults();
|
|
270
270
|
if (config.environment.isProduction) {
|
|
271
271
|
if (config.strategy === 'console') {
|
|
272
|
-
console.warn('[
|
|
272
|
+
console.warn('[Bloomneo AppKit] Using console email strategy in production. ' +
|
|
273
273
|
'Emails will only be logged, not sent. ' +
|
|
274
274
|
'Set RESEND_API_KEY or SMTP_HOST for production email sending.');
|
|
275
275
|
}
|
package/dist/email/index.js
CHANGED
|
@@ -126,13 +126,13 @@ function validateConfig() {
|
|
|
126
126
|
try {
|
|
127
127
|
const validation = validateStartupConfiguration();
|
|
128
128
|
if (validation.errors.length > 0) {
|
|
129
|
-
console.error('[
|
|
129
|
+
console.error('[Bloomneo AppKit] Email configuration errors:', validation.errors);
|
|
130
130
|
}
|
|
131
131
|
if (validation.warnings.length > 0) {
|
|
132
|
-
console.warn('[
|
|
132
|
+
console.warn('[Bloomneo AppKit] Email configuration warnings:', validation.warnings);
|
|
133
133
|
}
|
|
134
134
|
if (validation.ready) {
|
|
135
|
-
console.log(`✅ [
|
|
135
|
+
console.log(`✅ [Bloomneo AppKit] Email configured with ${validation.strategy} strategy`);
|
|
136
136
|
}
|
|
137
137
|
return {
|
|
138
138
|
valid: validation.errors.length === 0,
|
|
@@ -144,7 +144,7 @@ function validateConfig() {
|
|
|
144
144
|
}
|
|
145
145
|
catch (error) {
|
|
146
146
|
const errorMessage = error.message;
|
|
147
|
-
console.error('[
|
|
147
|
+
console.error('[Bloomneo AppKit] Email configuration validation failed:', errorMessage);
|
|
148
148
|
return {
|
|
149
149
|
valid: false,
|
|
150
150
|
strategy: 'unknown',
|
|
@@ -164,13 +164,13 @@ function validateProduction() {
|
|
|
164
164
|
try {
|
|
165
165
|
validateProductionRequirements();
|
|
166
166
|
if (process.env.NODE_ENV === 'production' && !hasProvider()) {
|
|
167
|
-
console.warn('[
|
|
167
|
+
console.warn('[Bloomneo AppKit] No email provider configured in production. ' +
|
|
168
168
|
'Set RESEND_API_KEY or SMTP_HOST to send real emails.');
|
|
169
169
|
}
|
|
170
|
-
console.log('✅ [
|
|
170
|
+
console.log('✅ [Bloomneo AppKit] Production email requirements validated');
|
|
171
171
|
}
|
|
172
172
|
catch (error) {
|
|
173
|
-
console.error('[
|
|
173
|
+
console.error('[Bloomneo AppKit] Production email validation failed:', error.message);
|
|
174
174
|
throw error;
|
|
175
175
|
}
|
|
176
176
|
}
|
|
@@ -195,7 +195,7 @@ export class ResendStrategy {
|
|
|
195
195
|
headers: {
|
|
196
196
|
'Authorization': `Bearer ${this.apiKey}`,
|
|
197
197
|
'Content-Type': 'application/json',
|
|
198
|
-
'User-Agent': '
|
|
198
|
+
'User-Agent': 'Bloomneo-AppKit-Email/1.0.0',
|
|
199
199
|
},
|
|
200
200
|
body: JSON.stringify(payload),
|
|
201
201
|
});
|
package/dist/error/defaults.js
CHANGED
|
@@ -63,12 +63,12 @@ function validateEnvironment() {
|
|
|
63
63
|
// Validate NODE_ENV (essential for environment detection)
|
|
64
64
|
const nodeEnv = process.env.NODE_ENV;
|
|
65
65
|
if (nodeEnv && !['development', 'production', 'test', 'staging'].includes(nodeEnv)) {
|
|
66
|
-
console.warn(`[
|
|
66
|
+
console.warn(`[Bloomneo AppKit] Unusual NODE_ENV: "${nodeEnv}". ` +
|
|
67
67
|
`Expected: development, production, test, or staging`);
|
|
68
68
|
}
|
|
69
69
|
// Essential production safety check
|
|
70
70
|
if (nodeEnv === 'production' && process.env.VOILA_ERROR_STACK === 'true') {
|
|
71
|
-
console.warn(`[
|
|
71
|
+
console.warn(`[Bloomneo AppKit] Security warning: VOILA_ERROR_STACK=true in production. ` +
|
|
72
72
|
`Stack traces may expose internal application structure. Consider setting to false.`);
|
|
73
73
|
}
|
|
74
74
|
}
|
package/dist/event/defaults.js
CHANGED
|
@@ -76,7 +76,7 @@ function detectEventStrategy() {
|
|
|
76
76
|
}
|
|
77
77
|
// Default to memory for development/testing
|
|
78
78
|
if (process.env.NODE_ENV === 'production') {
|
|
79
|
-
console.warn('[
|
|
79
|
+
console.warn('[Bloomneo AppKit] No REDIS_URL found in production. ' +
|
|
80
80
|
'Using memory event strategy which will not work across multiple servers. ' +
|
|
81
81
|
'Set REDIS_URL for distributed events.');
|
|
82
82
|
}
|
|
@@ -125,7 +125,7 @@ function validateEnvironment() {
|
|
|
125
125
|
}
|
|
126
126
|
// Validate NODE_ENV
|
|
127
127
|
if (nodeEnv && !['development', 'production', 'test', 'staging'].includes(nodeEnv)) {
|
|
128
|
-
console.warn(`[
|
|
128
|
+
console.warn(`[Bloomneo AppKit] Unusual NODE_ENV: "${nodeEnv}". ` +
|
|
129
129
|
`Expected: development, production, test, or staging`);
|
|
130
130
|
}
|
|
131
131
|
}
|
|
@@ -165,14 +165,14 @@ function validateNumericEnv(name, min, max) {
|
|
|
165
165
|
function validateProductionConfig() {
|
|
166
166
|
const strategy = detectEventStrategy();
|
|
167
167
|
if (strategy === 'memory') {
|
|
168
|
-
console.warn('[
|
|
168
|
+
console.warn('[Bloomneo AppKit] Using memory event strategy in production. ' +
|
|
169
169
|
'Events will only work within single server instance. ' +
|
|
170
170
|
'Set REDIS_URL for distributed events across multiple servers.');
|
|
171
171
|
}
|
|
172
172
|
// Validate namespace is set in production
|
|
173
173
|
const namespace = process.env.VOILA_EVENT_NAMESPACE;
|
|
174
174
|
if (!namespace) {
|
|
175
|
-
console.warn('[
|
|
175
|
+
console.warn('[Bloomneo AppKit] No event namespace configured in production. ' +
|
|
176
176
|
'Set VOILA_EVENT_NAMESPACE for proper event isolation.');
|
|
177
177
|
}
|
|
178
178
|
}
|
|
@@ -200,7 +200,7 @@ export function validateProductionRequirements() {
|
|
|
200
200
|
const config = getSmartDefaults();
|
|
201
201
|
if (config.environment.isProduction) {
|
|
202
202
|
if (config.strategy === 'memory') {
|
|
203
|
-
console.warn('[
|
|
203
|
+
console.warn('[Bloomneo AppKit] Using memory event strategy in production. ' +
|
|
204
204
|
'Events will not work across multiple server instances. ' +
|
|
205
205
|
'Set REDIS_URL for distributed events.');
|
|
206
206
|
}
|
package/dist/event/index.js
CHANGED
|
@@ -170,13 +170,13 @@ function validateConfig() {
|
|
|
170
170
|
try {
|
|
171
171
|
const validation = validateStartupConfiguration();
|
|
172
172
|
if (validation.errors.length > 0) {
|
|
173
|
-
console.error('[
|
|
173
|
+
console.error('[Bloomneo AppKit] Event configuration errors:', validation.errors);
|
|
174
174
|
}
|
|
175
175
|
if (validation.warnings.length > 0) {
|
|
176
|
-
console.warn('[
|
|
176
|
+
console.warn('[Bloomneo AppKit] Event configuration warnings:', validation.warnings);
|
|
177
177
|
}
|
|
178
178
|
if (validation.ready) {
|
|
179
|
-
console.log(`✅ [
|
|
179
|
+
console.log(`✅ [Bloomneo AppKit] Events configured with ${validation.strategy} strategy`);
|
|
180
180
|
}
|
|
181
181
|
return {
|
|
182
182
|
valid: validation.errors.length === 0,
|
|
@@ -188,7 +188,7 @@ function validateConfig() {
|
|
|
188
188
|
}
|
|
189
189
|
catch (error) {
|
|
190
190
|
const errorMessage = error.message;
|
|
191
|
-
console.error('[
|
|
191
|
+
console.error('[Bloomneo AppKit] Event configuration validation failed:', errorMessage);
|
|
192
192
|
return {
|
|
193
193
|
valid: false,
|
|
194
194
|
strategy: 'unknown',
|
|
@@ -208,13 +208,13 @@ function validateProduction() {
|
|
|
208
208
|
try {
|
|
209
209
|
validateProductionRequirements();
|
|
210
210
|
if (process.env.NODE_ENV === 'production' && !hasRedis()) {
|
|
211
|
-
console.warn('[
|
|
211
|
+
console.warn('[Bloomneo AppKit] No Redis configured in production. ' +
|
|
212
212
|
'Set REDIS_URL for distributed events across servers.');
|
|
213
213
|
}
|
|
214
|
-
console.log('✅ [
|
|
214
|
+
console.log('✅ [Bloomneo AppKit] Production event requirements validated');
|
|
215
215
|
}
|
|
216
216
|
catch (error) {
|
|
217
|
-
console.error('[
|
|
217
|
+
console.error('[Bloomneo AppKit] Production event validation failed:', error.message);
|
|
218
218
|
throw error;
|
|
219
219
|
}
|
|
220
220
|
}
|
|
@@ -100,7 +100,7 @@ export class ConsoleTransport {
|
|
|
100
100
|
minute: '2-digit',
|
|
101
101
|
second: '2-digit'
|
|
102
102
|
});
|
|
103
|
-
// Special handling for
|
|
103
|
+
// Special handling for Bloomneo startup messages (keep them prominent)
|
|
104
104
|
if (message && (message.includes('✨') || message.includes('🚀') || message.includes('👋'))) {
|
|
105
105
|
return `${cleanTime} ${message}`;
|
|
106
106
|
}
|
|
@@ -326,7 +326,7 @@ export class HttpTransport {
|
|
|
326
326
|
headers: {
|
|
327
327
|
'Content-Type': 'application/json',
|
|
328
328
|
'Content-Length': Buffer.byteLength(payload),
|
|
329
|
-
'User-Agent': '
|
|
329
|
+
'User-Agent': 'Bloomneo-AppKit-Logging/1.0.0',
|
|
330
330
|
},
|
|
331
331
|
timeout: this.timeout,
|
|
332
332
|
};
|
|
@@ -316,7 +316,7 @@ export class WebhookTransport {
|
|
|
316
316
|
{
|
|
317
317
|
color: color,
|
|
318
318
|
fields: fields,
|
|
319
|
-
footer: '
|
|
319
|
+
footer: 'Bloomneo AppKit Logging',
|
|
320
320
|
ts: Math.floor(new Date(entry.timestamp).getTime() / 1000),
|
|
321
321
|
},
|
|
322
322
|
],
|
|
@@ -405,7 +405,7 @@ export class WebhookTransport {
|
|
|
405
405
|
headers: {
|
|
406
406
|
'Content-Type': 'application/json',
|
|
407
407
|
'Content-Length': Buffer.byteLength(payload),
|
|
408
|
-
'User-Agent': '
|
|
408
|
+
'User-Agent': 'Bloomneo-AppKit-Logging/1.0.0',
|
|
409
409
|
},
|
|
410
410
|
timeout: 10000, // 10 second timeout for webhooks
|
|
411
411
|
};
|
|
@@ -69,7 +69,7 @@ function validateEnvironment() {
|
|
|
69
69
|
// Validate CSRF secret in production
|
|
70
70
|
const csrfSecret = process.env.VOILA_SECURITY_CSRF_SECRET || process.env.VOILA_AUTH_SECRET;
|
|
71
71
|
if (!csrfSecret && nodeEnv === 'production') {
|
|
72
|
-
console.warn('[
|
|
72
|
+
console.warn('[Bloomneo AppKit] VOILA_SECURITY_CSRF_SECRET not set. ' +
|
|
73
73
|
'CSRF protection will not work in production. ' +
|
|
74
74
|
'Set VOILA_SECURITY_CSRF_SECRET or VOILA_AUTH_SECRET environment variable.');
|
|
75
75
|
}
|
|
@@ -112,13 +112,13 @@ function validateEnvironment() {
|
|
|
112
112
|
// Production-specific warnings
|
|
113
113
|
if (nodeEnv === 'production') {
|
|
114
114
|
if (!encryptionKey) {
|
|
115
|
-
console.warn('[
|
|
115
|
+
console.warn('[Bloomneo AppKit] VOILA_SECURITY_ENCRYPTION_KEY not set. ' +
|
|
116
116
|
'Data encryption will not be available in production.');
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
// Validate NODE_ENV
|
|
120
120
|
if (nodeEnv && !['development', 'production', 'test', 'staging'].includes(nodeEnv)) {
|
|
121
|
-
console.warn(`[
|
|
121
|
+
console.warn(`[Bloomneo AppKit] Unusual NODE_ENV: "${nodeEnv}". ` +
|
|
122
122
|
`Expected: development, production, test, or staging`);
|
|
123
123
|
}
|
|
124
124
|
}
|
package/dist/storage/defaults.js
CHANGED
|
@@ -83,7 +83,7 @@ function detectStorageStrategy() {
|
|
|
83
83
|
}
|
|
84
84
|
// Default to local for development/single server
|
|
85
85
|
if (process.env.NODE_ENV === 'production') {
|
|
86
|
-
console.warn('[
|
|
86
|
+
console.warn('[Bloomneo AppKit] No cloud storage configured in production. ' +
|
|
87
87
|
'Using local filesystem which may not scale. ' +
|
|
88
88
|
'Set AWS_S3_BUCKET or CLOUDFLARE_R2_BUCKET for cloud storage.');
|
|
89
89
|
}
|
|
@@ -107,7 +107,7 @@ function parseAllowedTypes() {
|
|
|
107
107
|
}
|
|
108
108
|
if (envTypes === '*') {
|
|
109
109
|
if (process.env.NODE_ENV === 'production') {
|
|
110
|
-
console.warn('[
|
|
110
|
+
console.warn('[Bloomneo AppKit] SECURITY WARNING: All file types allowed in production. ' +
|
|
111
111
|
'Set VOILA_STORAGE_ALLOWED_TYPES to specific types for security.');
|
|
112
112
|
}
|
|
113
113
|
return ['*']; // Allow all types (use with caution)
|
|
@@ -148,7 +148,7 @@ function validateEnvironment() {
|
|
|
148
148
|
}
|
|
149
149
|
// Validate NODE_ENV
|
|
150
150
|
if (nodeEnv && !['development', 'production', 'test', 'staging'].includes(nodeEnv)) {
|
|
151
|
-
console.warn(`[
|
|
151
|
+
console.warn(`[Bloomneo AppKit] Unusual NODE_ENV: "${nodeEnv}". ` +
|
|
152
152
|
`Expected: development, production, test, or staging`);
|
|
153
153
|
}
|
|
154
154
|
}
|
|
@@ -216,7 +216,7 @@ function validateR2Config() {
|
|
|
216
216
|
function validateLocalConfig() {
|
|
217
217
|
const dir = process.env.VOILA_STORAGE_DIR;
|
|
218
218
|
if (dir && (dir.includes('..') || dir.startsWith('/') && process.env.NODE_ENV === 'production')) {
|
|
219
|
-
console.warn(`[
|
|
219
|
+
console.warn(`[Bloomneo AppKit] Potentially unsafe storage directory: "${dir}". ` +
|
|
220
220
|
`Consider using a relative path for security.`);
|
|
221
221
|
}
|
|
222
222
|
const baseUrl = process.env.VOILA_STORAGE_BASE_URL;
|
|
@@ -232,14 +232,14 @@ function validateLocalConfig() {
|
|
|
232
232
|
function validateProductionConfig() {
|
|
233
233
|
const strategy = detectStorageStrategy();
|
|
234
234
|
if (strategy === 'local') {
|
|
235
|
-
console.warn('[
|
|
235
|
+
console.warn('[Bloomneo AppKit] Using local storage in production. ' +
|
|
236
236
|
'Files will only exist on single server instance. ' +
|
|
237
237
|
'Set AWS_S3_BUCKET or CLOUDFLARE_R2_BUCKET for distributed storage.');
|
|
238
238
|
}
|
|
239
239
|
// Warn about missing CDN in production
|
|
240
240
|
const cdnUrl = process.env.VOILA_STORAGE_CDN_URL || process.env.CLOUDFLARE_R2_CDN_URL;
|
|
241
241
|
if (!cdnUrl && strategy !== 'local') {
|
|
242
|
-
console.warn('[
|
|
242
|
+
console.warn('[Bloomneo AppKit] No CDN URL configured in production. ' +
|
|
243
243
|
'Set VOILA_STORAGE_CDN_URL for better performance.');
|
|
244
244
|
}
|
|
245
245
|
}
|
|
@@ -339,7 +339,7 @@ export function getDeploymentConfig(type) {
|
|
|
339
339
|
case 'production':
|
|
340
340
|
const strategy = detectStorageStrategy();
|
|
341
341
|
if (strategy === 'local') {
|
|
342
|
-
console.warn('[
|
|
342
|
+
console.warn('[Bloomneo AppKit] Local storage not recommended for production');
|
|
343
343
|
}
|
|
344
344
|
return {
|
|
345
345
|
strategy,
|
package/dist/storage/index.js
CHANGED
|
@@ -100,17 +100,17 @@ function validateConfig() {
|
|
|
100
100
|
try {
|
|
101
101
|
const strategy = getStrategy();
|
|
102
102
|
if (strategy === 'local' && process.env.NODE_ENV === 'production') {
|
|
103
|
-
console.warn('[
|
|
103
|
+
console.warn('[Bloomneo AppKit] Using local storage in production. ' +
|
|
104
104
|
'Files will only exist on single server instance. ' +
|
|
105
105
|
'Set AWS_S3_BUCKET or CLOUDFLARE_R2_BUCKET for distributed storage.');
|
|
106
106
|
}
|
|
107
107
|
if (process.env.NODE_ENV === 'production' && !hasCloudStorage()) {
|
|
108
|
-
console.warn('[
|
|
108
|
+
console.warn('[Bloomneo AppKit] No cloud storage configured in production. ' +
|
|
109
109
|
'Set AWS_S3_BUCKET or CLOUDFLARE_R2_BUCKET for scalable file storage.');
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
catch (error) {
|
|
113
|
-
console.error('[
|
|
113
|
+
console.error('[Bloomneo AppKit] Storage configuration validation failed:', error.message);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
/**
|
package/dist/util/defaults.js
CHANGED
|
@@ -79,7 +79,7 @@ function validateEnvironment() {
|
|
|
79
79
|
throw new Error(`Invalid VOILA_UTIL_CACHE_SIZE: "${cacheSize}". Must be a positive number.`);
|
|
80
80
|
}
|
|
81
81
|
if (cacheSizeNum > 100000) {
|
|
82
|
-
console.warn(`[
|
|
82
|
+
console.warn(`[Bloomneo AppKit] Large cache size: ${cacheSizeNum}. This may impact memory usage.`);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
// Validate cache TTL
|
|
@@ -117,30 +117,30 @@ function validateEnvironment() {
|
|
|
117
117
|
// Validate locale if provided
|
|
118
118
|
const locale = process.env.VOILA_UTIL_LOCALE;
|
|
119
119
|
if (locale && !isValidLocale(locale)) {
|
|
120
|
-
console.warn(`[
|
|
120
|
+
console.warn(`[Bloomneo AppKit] Invalid locale: "${locale}". Using default 'en-US'.`);
|
|
121
121
|
}
|
|
122
122
|
// Validate currency if provided
|
|
123
123
|
const currency = process.env.VOILA_UTIL_CURRENCY;
|
|
124
124
|
if (currency && !isValidCurrency(currency)) {
|
|
125
|
-
console.warn(`[
|
|
125
|
+
console.warn(`[Bloomneo AppKit] Invalid currency: "${currency}". Using default 'USD'.`);
|
|
126
126
|
}
|
|
127
127
|
// Validate slugify replacement
|
|
128
128
|
const replacement = process.env.VOILA_UTIL_SLUGIFY_REPLACEMENT;
|
|
129
129
|
if (replacement && replacement.length > 5) {
|
|
130
|
-
console.warn(`[
|
|
130
|
+
console.warn(`[Bloomneo AppKit] Long slugify replacement: "${replacement}". Consider using shorter replacement.`);
|
|
131
131
|
}
|
|
132
132
|
// Production-specific warnings
|
|
133
133
|
if (nodeEnv === 'production') {
|
|
134
134
|
if (process.env.VOILA_UTIL_DEBUG === 'true') {
|
|
135
|
-
console.warn('[
|
|
135
|
+
console.warn('[Bloomneo AppKit] Debug mode enabled in production. This may impact performance.');
|
|
136
136
|
}
|
|
137
137
|
if (process.env.VOILA_UTIL_LOG_OPS === 'true') {
|
|
138
|
-
console.warn('[
|
|
138
|
+
console.warn('[Bloomneo AppKit] Operation logging enabled in production. This may impact performance.');
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
// Validate NODE_ENV
|
|
142
142
|
if (nodeEnv && !['development', 'production', 'test', 'staging'].includes(nodeEnv)) {
|
|
143
|
-
console.warn(`[
|
|
143
|
+
console.warn(`[Bloomneo AppKit] Unusual NODE_ENV: "${nodeEnv}". ` +
|
|
144
144
|
`Expected: development, production, test, or staging`);
|
|
145
145
|
}
|
|
146
146
|
}
|
package/dist/util/util.js
CHANGED
|
@@ -152,7 +152,7 @@ export class UtilClass {
|
|
|
152
152
|
}
|
|
153
153
|
// Performance warning for large arrays
|
|
154
154
|
if (this.config.performance.enabled && array.length > this.config.performance.chunkSizeLimit) {
|
|
155
|
-
console.warn(`[
|
|
155
|
+
console.warn(`[Bloomneo Utils] Chunking large array (${array.length} items). Consider streaming or pagination.`);
|
|
156
156
|
}
|
|
157
157
|
const result = [];
|
|
158
158
|
for (let i = 0; i < array.length; i += size) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bloomneo/appkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Minimal and framework agnostic Node.js toolkit designed for AI agentic backend development. Previously published as @voilajsx/appkit.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|