create-fluxstack 1.0.0 → 1.0.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/create-fluxstack.ts +32 -17
- package/package-template.json +51 -0
- package/package.json +2 -1
- package/.env +0 -30
- package/LICENSE +0 -21
- package/app/client/README.md +0 -69
- package/app/client/frontend-only.ts +0 -12
- package/app/client/index.html +0 -13
- package/app/client/public/vite.svg +0 -1
- package/app/client/src/App.css +0 -883
- package/app/client/src/App.tsx +0 -669
- package/app/client/src/assets/react.svg +0 -1
- package/app/client/src/components/TestPage.tsx +0 -453
- package/app/client/src/index.css +0 -51
- package/app/client/src/lib/eden-api.ts +0 -110
- package/app/client/src/main.tsx +0 -10
- package/app/client/src/vite-env.d.ts +0 -1
- package/app/client/tsconfig.app.json +0 -43
- package/app/client/tsconfig.json +0 -7
- package/app/client/tsconfig.node.json +0 -25
- package/app/server/app.ts +0 -10
- package/app/server/backend-only.ts +0 -15
- package/app/server/controllers/users.controller.ts +0 -69
- package/app/server/index.ts +0 -104
- package/app/server/routes/index.ts +0 -25
- package/app/server/routes/users.routes.ts +0 -121
- package/app/server/types/index.ts +0 -1
- package/app/shared/types/index.ts +0 -18
- package/bun.lock +0 -1053
- package/core/__tests__/integration.test.ts +0 -227
- package/core/build/index.ts +0 -186
- package/core/cli/command-registry.ts +0 -334
- package/core/cli/index.ts +0 -394
- package/core/cli/plugin-discovery.ts +0 -200
- package/core/client/standalone.ts +0 -57
- package/core/config/__tests__/config-loader.test.ts +0 -591
- package/core/config/__tests__/config-merger.test.ts +0 -657
- package/core/config/__tests__/env-converter.test.ts +0 -372
- package/core/config/__tests__/env-processor.test.ts +0 -431
- package/core/config/__tests__/env.test.ts +0 -452
- package/core/config/__tests__/integration.test.ts +0 -418
- package/core/config/__tests__/loader.test.ts +0 -331
- package/core/config/__tests__/schema.test.ts +0 -129
- package/core/config/__tests__/validator.test.ts +0 -318
- package/core/config/env-dynamic.ts +0 -326
- package/core/config/env.ts +0 -597
- package/core/config/index.ts +0 -317
- package/core/config/loader.ts +0 -546
- package/core/config/runtime-config.ts +0 -322
- package/core/config/schema.ts +0 -694
- package/core/config/validator.ts +0 -540
- package/core/framework/__tests__/server.test.ts +0 -233
- package/core/framework/client.ts +0 -132
- package/core/framework/index.ts +0 -8
- package/core/framework/server.ts +0 -501
- package/core/framework/types.ts +0 -63
- package/core/plugins/__tests__/built-in.test.ts.disabled +0 -366
- package/core/plugins/__tests__/manager.test.ts +0 -398
- package/core/plugins/__tests__/monitoring.test.ts +0 -401
- package/core/plugins/__tests__/registry.test.ts +0 -335
- package/core/plugins/built-in/index.ts +0 -142
- package/core/plugins/built-in/logger/index.ts +0 -180
- package/core/plugins/built-in/monitoring/README.md +0 -193
- package/core/plugins/built-in/monitoring/index.ts +0 -912
- package/core/plugins/built-in/static/index.ts +0 -289
- package/core/plugins/built-in/swagger/index.ts +0 -229
- package/core/plugins/built-in/vite/index.ts +0 -316
- package/core/plugins/config.ts +0 -348
- package/core/plugins/discovery.ts +0 -350
- package/core/plugins/executor.ts +0 -351
- package/core/plugins/index.ts +0 -195
- package/core/plugins/manager.ts +0 -583
- package/core/plugins/registry.ts +0 -424
- package/core/plugins/types.ts +0 -254
- package/core/server/framework.ts +0 -123
- package/core/server/index.ts +0 -8
- package/core/server/plugins/database.ts +0 -182
- package/core/server/plugins/logger.ts +0 -47
- package/core/server/plugins/swagger.ts +0 -34
- package/core/server/standalone.ts +0 -91
- package/core/templates/create-project.ts +0 -455
- package/core/types/api.ts +0 -169
- package/core/types/build.ts +0 -174
- package/core/types/config.ts +0 -68
- package/core/types/index.ts +0 -127
- package/core/types/plugin.ts +0 -94
- package/core/utils/__tests__/errors.test.ts +0 -139
- package/core/utils/__tests__/helpers.test.ts +0 -297
- package/core/utils/__tests__/logger.test.ts +0 -141
- package/core/utils/env-runtime-v2.ts +0 -232
- package/core/utils/env-runtime.ts +0 -252
- package/core/utils/errors/codes.ts +0 -115
- package/core/utils/errors/handlers.ts +0 -63
- package/core/utils/errors/index.ts +0 -81
- package/core/utils/helpers.ts +0 -180
- package/core/utils/index.ts +0 -18
- package/core/utils/logger/index.ts +0 -161
- package/core/utils/logger.ts +0 -106
- package/core/utils/monitoring/index.ts +0 -212
- package/tsconfig.json +0 -51
- package/vite.config.ts +0 -42
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime Environment Loader V2 - Simplified API
|
|
3
|
-
* Mais elegante com casting automático e acesso direto
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Enhanced environment variable loader with smart casting
|
|
8
|
-
*/
|
|
9
|
-
class SmartEnvLoader {
|
|
10
|
-
private envAccessor: () => Record<string, string | undefined>
|
|
11
|
-
|
|
12
|
-
constructor() {
|
|
13
|
-
this.envAccessor = this.createDynamicAccessor()
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
private createDynamicAccessor(): () => Record<string, string | undefined> {
|
|
17
|
-
const globalScope = globalThis as any
|
|
18
|
-
|
|
19
|
-
return () => {
|
|
20
|
-
// Try Bun.env first (most reliable in Bun runtime)
|
|
21
|
-
if (globalScope['Bun'] && globalScope['Bun']['env']) {
|
|
22
|
-
return globalScope['Bun']['env']
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Fallback to process.env with dynamic access
|
|
26
|
-
if (globalScope['process'] && globalScope['process']['env']) {
|
|
27
|
-
return globalScope['process']['env']
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Final fallback
|
|
31
|
-
const proc = eval('typeof process !== "undefined" ? process : null')
|
|
32
|
-
return proc?.env || {}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Smart get with automatic type conversion based on default value
|
|
38
|
-
*/
|
|
39
|
-
get<T>(key: string, defaultValue?: T): T {
|
|
40
|
-
const env = this.envAccessor()
|
|
41
|
-
const value = env[key]
|
|
42
|
-
|
|
43
|
-
if (!value || value === '') {
|
|
44
|
-
return defaultValue as T
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Auto-detect type from default value
|
|
48
|
-
if (typeof defaultValue === 'number') {
|
|
49
|
-
const parsed = parseInt(value, 10)
|
|
50
|
-
return (isNaN(parsed) ? defaultValue : parsed) as T
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (typeof defaultValue === 'boolean') {
|
|
54
|
-
return ['true', '1', 'yes', 'on'].includes(value.toLowerCase()) as T
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (Array.isArray(defaultValue)) {
|
|
58
|
-
return value.split(',').map(v => v.trim()).filter(Boolean) as T
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (typeof defaultValue === 'object' && defaultValue !== null) {
|
|
62
|
-
try {
|
|
63
|
-
return JSON.parse(value) as T
|
|
64
|
-
} catch {
|
|
65
|
-
return defaultValue
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return value as T
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Check if environment variable exists
|
|
74
|
-
*/
|
|
75
|
-
has(key: string): boolean {
|
|
76
|
-
const env = this.envAccessor()
|
|
77
|
-
return key in env && env[key] !== undefined && env[key] !== ''
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Get all environment variables
|
|
82
|
-
*/
|
|
83
|
-
all(): Record<string, string> {
|
|
84
|
-
const env = this.envAccessor()
|
|
85
|
-
const result: Record<string, string> = {}
|
|
86
|
-
|
|
87
|
-
for (const [key, value] of Object.entries(env)) {
|
|
88
|
-
if (value !== undefined && value !== '') {
|
|
89
|
-
result[key] = value
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return result
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Create singleton instance
|
|
98
|
-
const smartEnv = new SmartEnvLoader()
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Simplified env API with smart casting
|
|
102
|
-
*/
|
|
103
|
-
export const env = {
|
|
104
|
-
/**
|
|
105
|
-
* Smart get - automatically casts based on default value type
|
|
106
|
-
* Usage:
|
|
107
|
-
* env.get('PORT', 3000) -> number
|
|
108
|
-
* env.get('DEBUG', false) -> boolean
|
|
109
|
-
* env.get('ORIGINS', ['*']) -> string[]
|
|
110
|
-
* env.get('HOST', 'localhost') -> string
|
|
111
|
-
*/
|
|
112
|
-
get: <T>(key: string, defaultValue?: T): T => smartEnv.get(key, defaultValue),
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Check if env var exists
|
|
116
|
-
*/
|
|
117
|
-
has: (key: string) => smartEnv.has(key),
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Get number value
|
|
121
|
-
*/
|
|
122
|
-
num: (key: string, defaultValue?: number) => Number(smartEnv.get(key, defaultValue?.toString() || '0')),
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Get boolean value
|
|
126
|
-
*/
|
|
127
|
-
bool: (key: string, defaultValue?: boolean) => smartEnv.get(key, defaultValue?.toString() || 'false') === 'true',
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Get array value
|
|
131
|
-
*/
|
|
132
|
-
array: (key: string, defaultValue?: string[]) => smartEnv.get(key, defaultValue?.join(',') || '').split(',').filter(Boolean),
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Get all env vars
|
|
136
|
-
*/
|
|
137
|
-
all: () => smartEnv.all(),
|
|
138
|
-
|
|
139
|
-
// Common environment variables as properties with smart defaults
|
|
140
|
-
get NODE_ENV() { return this.get('NODE_ENV', 'development') },
|
|
141
|
-
get PORT() { return this.get('PORT', 3000) },
|
|
142
|
-
get HOST() { return this.get('HOST', 'localhost') },
|
|
143
|
-
get DEBUG() { return this.get('DEBUG', false) },
|
|
144
|
-
get LOG_LEVEL() { return this.get('LOG_LEVEL', 'info') },
|
|
145
|
-
get DATABASE_URL() { return this.get('DATABASE_URL', '') },
|
|
146
|
-
get JWT_SECRET() { return this.get('JWT_SECRET', '') },
|
|
147
|
-
get CORS_ORIGINS() { return this.get('CORS_ORIGINS', ['*']) },
|
|
148
|
-
get VITE_PORT() { return this.get('VITE_PORT', 5173) },
|
|
149
|
-
get API_PREFIX() { return this.get('API_PREFIX', '/api') },
|
|
150
|
-
|
|
151
|
-
// App specific
|
|
152
|
-
get FLUXSTACK_APP_NAME() { return this.get('FLUXSTACK_APP_NAME', 'FluxStack') },
|
|
153
|
-
get FLUXSTACK_APP_VERSION() { return this.get('FLUXSTACK_APP_VERSION', '1.0.0') },
|
|
154
|
-
|
|
155
|
-
// Monitoring
|
|
156
|
-
get ENABLE_MONITORING() { return this.get('ENABLE_MONITORING', false) },
|
|
157
|
-
get ENABLE_SWAGGER() { return this.get('ENABLE_SWAGGER', true) },
|
|
158
|
-
get ENABLE_METRICS() { return this.get('ENABLE_METRICS', false) },
|
|
159
|
-
|
|
160
|
-
// Database
|
|
161
|
-
get DB_HOST() { return this.get('DB_HOST', 'localhost') },
|
|
162
|
-
get DB_PORT() { return this.get('DB_PORT', 5432) },
|
|
163
|
-
get DB_NAME() { return this.get('DB_NAME', '') },
|
|
164
|
-
get DB_USER() { return this.get('DB_USER', '') },
|
|
165
|
-
get DB_PASSWORD() { return this.get('DB_PASSWORD', '') },
|
|
166
|
-
get DB_SSL() { return this.get('DB_SSL', false) },
|
|
167
|
-
|
|
168
|
-
// SMTP
|
|
169
|
-
get SMTP_HOST() { return this.get('SMTP_HOST', '') },
|
|
170
|
-
get SMTP_PORT() { return this.get('SMTP_PORT', 587) },
|
|
171
|
-
get SMTP_USER() { return this.get('SMTP_USER', '') },
|
|
172
|
-
get SMTP_PASSWORD() { return this.get('SMTP_PASSWORD', '') },
|
|
173
|
-
get SMTP_SECURE() { return this.get('SMTP_SECURE', false) }
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Create namespaced environment access
|
|
178
|
-
* Usage: const db = createNamespace('DATABASE_')
|
|
179
|
-
* db.get('URL') -> reads DATABASE_URL
|
|
180
|
-
*/
|
|
181
|
-
export function createNamespace(prefix: string) {
|
|
182
|
-
return {
|
|
183
|
-
get: <T>(key: string, defaultValue?: T): T =>
|
|
184
|
-
smartEnv.get(`${prefix}${key}`, defaultValue),
|
|
185
|
-
|
|
186
|
-
has: (key: string) => smartEnv.has(`${prefix}${key}`),
|
|
187
|
-
|
|
188
|
-
all: () => {
|
|
189
|
-
const allEnv = smartEnv.all()
|
|
190
|
-
const namespaced: Record<string, string> = {}
|
|
191
|
-
|
|
192
|
-
for (const [key, value] of Object.entries(allEnv)) {
|
|
193
|
-
if (key.startsWith(prefix)) {
|
|
194
|
-
namespaced[key.slice(prefix.length)] = value
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return namespaced
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Environment validation
|
|
205
|
-
*/
|
|
206
|
-
export const validate = {
|
|
207
|
-
require(keys: string[]): void {
|
|
208
|
-
const missing = keys.filter(key => !smartEnv.has(key))
|
|
209
|
-
if (missing.length > 0) {
|
|
210
|
-
throw new Error(`Missing required environment variables: ${missing.join(', ')}`)
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
|
|
214
|
-
oneOf(key: string, validValues: string[]): void {
|
|
215
|
-
const value = smartEnv.get(key, '')
|
|
216
|
-
if (value && !validValues.includes(value)) {
|
|
217
|
-
throw new Error(`${key} must be one of: ${validValues.join(', ')}, got: ${value}`)
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Convenience functions
|
|
224
|
-
*/
|
|
225
|
-
export const helpers = {
|
|
226
|
-
isDevelopment: () => env.NODE_ENV === 'development',
|
|
227
|
-
isProduction: () => env.NODE_ENV === 'production',
|
|
228
|
-
isTest: () => env.NODE_ENV === 'test',
|
|
229
|
-
|
|
230
|
-
getDatabaseUrl: () => {
|
|
231
|
-
const url = env.DATABASE_URL
|
|
232
|
-
if (url) return url
|
|
233
|
-
|
|
234
|
-
const { DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD } = env
|
|
235
|
-
if (DB_HOST && DB_NAME) {
|
|
236
|
-
const auth = DB_USER ? `${DB_USER}:${DB_PASSWORD}@` : ''
|
|
237
|
-
return `postgres://${auth}${DB_HOST}:${DB_PORT}/${DB_NAME}`
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return null
|
|
241
|
-
},
|
|
242
|
-
|
|
243
|
-
getServerUrl: () => `http://${env.HOST}:${env.PORT}`,
|
|
244
|
-
getClientUrl: () => `http://${env.HOST}:${env.VITE_PORT}`
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
export default env
|
|
248
|
-
|
|
249
|
-
// Legacy exports for compatibility
|
|
250
|
-
export const runtimeEnv = env
|
|
251
|
-
export const envValidation = validate
|
|
252
|
-
export const createEnvNamespace = createNamespace
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
export const ERROR_CODES = {
|
|
2
|
-
// Validation errors (400)
|
|
3
|
-
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
|
4
|
-
INVALID_INPUT: 'INVALID_INPUT',
|
|
5
|
-
MISSING_REQUIRED_FIELD: 'MISSING_REQUIRED_FIELD',
|
|
6
|
-
INVALID_FORMAT: 'INVALID_FORMAT',
|
|
7
|
-
|
|
8
|
-
// Authentication errors (401)
|
|
9
|
-
UNAUTHORIZED: 'UNAUTHORIZED',
|
|
10
|
-
INVALID_TOKEN: 'INVALID_TOKEN',
|
|
11
|
-
TOKEN_EXPIRED: 'TOKEN_EXPIRED',
|
|
12
|
-
INVALID_CREDENTIALS: 'INVALID_CREDENTIALS',
|
|
13
|
-
|
|
14
|
-
// Authorization errors (403)
|
|
15
|
-
FORBIDDEN: 'FORBIDDEN',
|
|
16
|
-
INSUFFICIENT_PERMISSIONS: 'INSUFFICIENT_PERMISSIONS',
|
|
17
|
-
ACCESS_DENIED: 'ACCESS_DENIED',
|
|
18
|
-
|
|
19
|
-
// Not found errors (404)
|
|
20
|
-
NOT_FOUND: 'NOT_FOUND',
|
|
21
|
-
RESOURCE_NOT_FOUND: 'RESOURCE_NOT_FOUND',
|
|
22
|
-
ENDPOINT_NOT_FOUND: 'ENDPOINT_NOT_FOUND',
|
|
23
|
-
|
|
24
|
-
// Conflict errors (409)
|
|
25
|
-
CONFLICT: 'CONFLICT',
|
|
26
|
-
RESOURCE_ALREADY_EXISTS: 'RESOURCE_ALREADY_EXISTS',
|
|
27
|
-
DUPLICATE_ENTRY: 'DUPLICATE_ENTRY',
|
|
28
|
-
|
|
29
|
-
// Server errors (500)
|
|
30
|
-
INTERNAL_ERROR: 'INTERNAL_ERROR',
|
|
31
|
-
INTERNAL_SERVER_ERROR: 'INTERNAL_SERVER_ERROR',
|
|
32
|
-
DATABASE_ERROR: 'DATABASE_ERROR',
|
|
33
|
-
EXTERNAL_SERVICE_ERROR: 'EXTERNAL_SERVICE_ERROR',
|
|
34
|
-
|
|
35
|
-
// Service unavailable (503)
|
|
36
|
-
SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE',
|
|
37
|
-
MAINTENANCE_MODE: 'MAINTENANCE_MODE',
|
|
38
|
-
RATE_LIMIT_EXCEEDED: 'RATE_LIMIT_EXCEEDED',
|
|
39
|
-
|
|
40
|
-
// Plugin errors
|
|
41
|
-
PLUGIN_ERROR: 'PLUGIN_ERROR',
|
|
42
|
-
PLUGIN_NOT_FOUND: 'PLUGIN_NOT_FOUND',
|
|
43
|
-
PLUGIN_INITIALIZATION_ERROR: 'PLUGIN_INITIALIZATION_ERROR',
|
|
44
|
-
|
|
45
|
-
// Configuration errors
|
|
46
|
-
CONFIG_ERROR: 'CONFIG_ERROR',
|
|
47
|
-
INVALID_CONFIG: 'INVALID_CONFIG',
|
|
48
|
-
MISSING_CONFIG: 'MISSING_CONFIG',
|
|
49
|
-
|
|
50
|
-
// Build errors
|
|
51
|
-
BUILD_ERROR: 'BUILD_ERROR',
|
|
52
|
-
COMPILATION_ERROR: 'COMPILATION_ERROR',
|
|
53
|
-
BUNDLING_ERROR: 'BUNDLING_ERROR'
|
|
54
|
-
} as const
|
|
55
|
-
|
|
56
|
-
export type ErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES]
|
|
57
|
-
|
|
58
|
-
export const getErrorMessage = (code: ErrorCode): string => {
|
|
59
|
-
const messages: Record<ErrorCode, string> = {
|
|
60
|
-
// Validation errors
|
|
61
|
-
VALIDATION_ERROR: 'Validation failed',
|
|
62
|
-
INVALID_INPUT: 'Invalid input provided',
|
|
63
|
-
MISSING_REQUIRED_FIELD: 'Required field is missing',
|
|
64
|
-
INVALID_FORMAT: 'Invalid format',
|
|
65
|
-
|
|
66
|
-
// Authentication errors
|
|
67
|
-
UNAUTHORIZED: 'Authentication required',
|
|
68
|
-
INVALID_TOKEN: 'Invalid authentication token',
|
|
69
|
-
TOKEN_EXPIRED: 'Authentication token has expired',
|
|
70
|
-
INVALID_CREDENTIALS: 'Invalid credentials provided',
|
|
71
|
-
|
|
72
|
-
// Authorization errors
|
|
73
|
-
FORBIDDEN: 'Access forbidden',
|
|
74
|
-
INSUFFICIENT_PERMISSIONS: 'Insufficient permissions',
|
|
75
|
-
ACCESS_DENIED: 'Access denied',
|
|
76
|
-
|
|
77
|
-
// Not found errors
|
|
78
|
-
NOT_FOUND: 'Resource not found',
|
|
79
|
-
RESOURCE_NOT_FOUND: 'Requested resource not found',
|
|
80
|
-
ENDPOINT_NOT_FOUND: 'API endpoint not found',
|
|
81
|
-
|
|
82
|
-
// Conflict errors
|
|
83
|
-
CONFLICT: 'Resource conflict',
|
|
84
|
-
RESOURCE_ALREADY_EXISTS: 'Resource already exists',
|
|
85
|
-
DUPLICATE_ENTRY: 'Duplicate entry',
|
|
86
|
-
|
|
87
|
-
// Server errors
|
|
88
|
-
INTERNAL_ERROR: 'Internal server error',
|
|
89
|
-
INTERNAL_SERVER_ERROR: 'Internal server error',
|
|
90
|
-
DATABASE_ERROR: 'Database operation failed',
|
|
91
|
-
EXTERNAL_SERVICE_ERROR: 'External service error',
|
|
92
|
-
|
|
93
|
-
// Service unavailable
|
|
94
|
-
SERVICE_UNAVAILABLE: 'Service temporarily unavailable',
|
|
95
|
-
MAINTENANCE_MODE: 'Service is under maintenance',
|
|
96
|
-
RATE_LIMIT_EXCEEDED: 'Rate limit exceeded',
|
|
97
|
-
|
|
98
|
-
// Plugin errors
|
|
99
|
-
PLUGIN_ERROR: 'Plugin error',
|
|
100
|
-
PLUGIN_NOT_FOUND: 'Plugin not found',
|
|
101
|
-
PLUGIN_INITIALIZATION_ERROR: 'Plugin initialization failed',
|
|
102
|
-
|
|
103
|
-
// Configuration errors
|
|
104
|
-
CONFIG_ERROR: 'Configuration error',
|
|
105
|
-
INVALID_CONFIG: 'Invalid configuration',
|
|
106
|
-
MISSING_CONFIG: 'Missing configuration',
|
|
107
|
-
|
|
108
|
-
// Build errors
|
|
109
|
-
BUILD_ERROR: 'Build error',
|
|
110
|
-
COMPILATION_ERROR: 'Compilation failed',
|
|
111
|
-
BUNDLING_ERROR: 'Bundling failed'
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return messages[code] || 'Unknown error'
|
|
115
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { FluxStackError } from "./index"
|
|
2
|
-
import type { Logger } from "../logger/index"
|
|
3
|
-
|
|
4
|
-
export interface ErrorHandlerContext {
|
|
5
|
-
logger: Logger
|
|
6
|
-
isDevelopment: boolean
|
|
7
|
-
request?: Request
|
|
8
|
-
path?: string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const errorHandler = (error: Error, context: ErrorHandlerContext) => {
|
|
12
|
-
const { logger, isDevelopment, request, path } = context
|
|
13
|
-
|
|
14
|
-
if (error instanceof FluxStackError) {
|
|
15
|
-
// Log FluxStack errors with appropriate level
|
|
16
|
-
const logLevel = error.statusCode >= 500 ? 'error' : 'warn'
|
|
17
|
-
logger[logLevel](error.message, {
|
|
18
|
-
code: error.code,
|
|
19
|
-
statusCode: error.statusCode,
|
|
20
|
-
context: error.context,
|
|
21
|
-
path,
|
|
22
|
-
method: request?.method,
|
|
23
|
-
stack: isDevelopment ? error.stack : undefined
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
error: {
|
|
28
|
-
message: error.message,
|
|
29
|
-
code: error.code,
|
|
30
|
-
statusCode: error.statusCode,
|
|
31
|
-
...(error.context && { details: error.context }),
|
|
32
|
-
...(isDevelopment && { stack: error.stack })
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Handle unknown errors - skip logging for NOT_FOUND unless explicitly enabled
|
|
38
|
-
if (error.message === 'NOT_FOUND' && !process.env.ENABLE_NOT_FOUND_LOGS) {
|
|
39
|
-
// Skip logging NOT_FOUND errors to reduce noise
|
|
40
|
-
} else {
|
|
41
|
-
logger.error('Unhandled error', {
|
|
42
|
-
error: error.message,
|
|
43
|
-
stack: error.stack,
|
|
44
|
-
path,
|
|
45
|
-
method: request?.method
|
|
46
|
-
})
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
error: {
|
|
51
|
-
message: isDevelopment ? error.message : 'Internal server error',
|
|
52
|
-
code: 'INTERNAL_ERROR',
|
|
53
|
-
statusCode: 500,
|
|
54
|
-
...(isDevelopment && { stack: error.stack })
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export const createErrorHandler = (context: Omit<ErrorHandlerContext, 'request' | 'path'>) => {
|
|
60
|
-
return (error: Error, request?: Request, path?: string) => {
|
|
61
|
-
return errorHandler(error, { ...context, request, path })
|
|
62
|
-
}
|
|
63
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
export class FluxStackError extends Error {
|
|
2
|
-
public readonly code: string
|
|
3
|
-
public readonly statusCode: number
|
|
4
|
-
public readonly context?: any
|
|
5
|
-
public readonly timestamp: Date
|
|
6
|
-
|
|
7
|
-
constructor(
|
|
8
|
-
message: string,
|
|
9
|
-
code: string,
|
|
10
|
-
statusCode: number = 500,
|
|
11
|
-
context?: any
|
|
12
|
-
) {
|
|
13
|
-
super(message)
|
|
14
|
-
this.name = 'FluxStackError'
|
|
15
|
-
this.code = code
|
|
16
|
-
this.statusCode = statusCode
|
|
17
|
-
this.context = context
|
|
18
|
-
this.timestamp = new Date()
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
toJSON() {
|
|
22
|
-
return {
|
|
23
|
-
name: this.name,
|
|
24
|
-
message: this.message,
|
|
25
|
-
code: this.code,
|
|
26
|
-
statusCode: this.statusCode,
|
|
27
|
-
context: this.context,
|
|
28
|
-
timestamp: this.timestamp,
|
|
29
|
-
stack: this.stack
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export class ValidationError extends FluxStackError {
|
|
35
|
-
constructor(message: string, context?: any) {
|
|
36
|
-
super(message, 'VALIDATION_ERROR', 400, context)
|
|
37
|
-
this.name = 'ValidationError'
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export class NotFoundError extends FluxStackError {
|
|
42
|
-
constructor(resource: string, context?: any) {
|
|
43
|
-
super(`${resource} not found`, 'NOT_FOUND', 404, context)
|
|
44
|
-
this.name = 'NotFoundError'
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export class UnauthorizedError extends FluxStackError {
|
|
49
|
-
constructor(message: string = 'Unauthorized', context?: any) {
|
|
50
|
-
super(message, 'UNAUTHORIZED', 401, context)
|
|
51
|
-
this.name = 'UnauthorizedError'
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export class ForbiddenError extends FluxStackError {
|
|
56
|
-
constructor(message: string = 'Forbidden', context?: any) {
|
|
57
|
-
super(message, 'FORBIDDEN', 403, context)
|
|
58
|
-
this.name = 'ForbiddenError'
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export class ConflictError extends FluxStackError {
|
|
63
|
-
constructor(message: string, context?: any) {
|
|
64
|
-
super(message, 'CONFLICT', 409, context)
|
|
65
|
-
this.name = 'ConflictError'
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export class InternalServerError extends FluxStackError {
|
|
70
|
-
constructor(message: string = 'Internal server error', context?: any) {
|
|
71
|
-
super(message, 'INTERNAL_SERVER_ERROR', 500, context)
|
|
72
|
-
this.name = 'InternalServerError'
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export class ServiceUnavailableError extends FluxStackError {
|
|
77
|
-
constructor(message: string = 'Service unavailable', context?: any) {
|
|
78
|
-
super(message, 'SERVICE_UNAVAILABLE', 503, context)
|
|
79
|
-
this.name = 'ServiceUnavailableError'
|
|
80
|
-
}
|
|
81
|
-
}
|
package/core/utils/helpers.ts
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* General utility functions for FluxStack
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export const formatBytes = (bytes: number, decimals: number = 2): string => {
|
|
6
|
-
if (bytes === 0) return '0 Bytes'
|
|
7
|
-
|
|
8
|
-
const k = 1024
|
|
9
|
-
const dm = decimals < 0 ? 0 : decimals
|
|
10
|
-
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
|
11
|
-
|
|
12
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
13
|
-
|
|
14
|
-
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const createTimer = (label: string) => {
|
|
18
|
-
const start = Date.now()
|
|
19
|
-
|
|
20
|
-
return {
|
|
21
|
-
end: (): number => {
|
|
22
|
-
const duration = Date.now() - start
|
|
23
|
-
return duration
|
|
24
|
-
},
|
|
25
|
-
label
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export const delay = (ms: number): Promise<void> => {
|
|
30
|
-
return new Promise(resolve => setTimeout(resolve, ms))
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export const retry = async <T>(
|
|
34
|
-
fn: () => Promise<T>,
|
|
35
|
-
maxAttempts: number = 3,
|
|
36
|
-
delayMs: number = 1000
|
|
37
|
-
): Promise<T> => {
|
|
38
|
-
let lastError: Error
|
|
39
|
-
|
|
40
|
-
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
41
|
-
try {
|
|
42
|
-
return await fn()
|
|
43
|
-
} catch (error) {
|
|
44
|
-
lastError = error as Error
|
|
45
|
-
|
|
46
|
-
if (attempt === maxAttempts) {
|
|
47
|
-
throw lastError
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
await delay(delayMs * attempt) // Exponential backoff
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
throw lastError!
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export const debounce = <T extends (...args: any[]) => any>(
|
|
58
|
-
func: T,
|
|
59
|
-
wait: number
|
|
60
|
-
): ((...args: Parameters<T>) => void) => {
|
|
61
|
-
let timeout: NodeJS.Timeout | null = null
|
|
62
|
-
|
|
63
|
-
return (...args: Parameters<T>) => {
|
|
64
|
-
if (timeout) {
|
|
65
|
-
clearTimeout(timeout)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
timeout = setTimeout(() => {
|
|
69
|
-
func(...args)
|
|
70
|
-
}, wait)
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export const throttle = <T extends (...args: any[]) => any>(
|
|
75
|
-
func: T,
|
|
76
|
-
limit: number
|
|
77
|
-
): ((...args: Parameters<T>) => void) => {
|
|
78
|
-
let inThrottle: boolean = false
|
|
79
|
-
|
|
80
|
-
return (...args: Parameters<T>) => {
|
|
81
|
-
if (!inThrottle) {
|
|
82
|
-
func(...args)
|
|
83
|
-
inThrottle = true
|
|
84
|
-
setTimeout(() => inThrottle = false, limit)
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export const isProduction = (): boolean => {
|
|
90
|
-
return process.env.NODE_ENV === 'production'
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export const isDevelopment = (): boolean => {
|
|
94
|
-
return process.env.NODE_ENV === 'development' || !process.env.NODE_ENV
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export const isTest = (): boolean => {
|
|
98
|
-
return process.env.NODE_ENV === 'test'
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export const deepMerge = <T extends Record<string, any>>(target: T, source: Partial<T>): T => {
|
|
102
|
-
const result = { ...target }
|
|
103
|
-
|
|
104
|
-
for (const key in source) {
|
|
105
|
-
if (source.hasOwnProperty(key)) {
|
|
106
|
-
const sourceValue = source[key]
|
|
107
|
-
const targetValue = result[key]
|
|
108
|
-
|
|
109
|
-
if (
|
|
110
|
-
sourceValue &&
|
|
111
|
-
typeof sourceValue === 'object' &&
|
|
112
|
-
!Array.isArray(sourceValue) &&
|
|
113
|
-
targetValue &&
|
|
114
|
-
typeof targetValue === 'object' &&
|
|
115
|
-
!Array.isArray(targetValue)
|
|
116
|
-
) {
|
|
117
|
-
result[key] = deepMerge(targetValue, sourceValue)
|
|
118
|
-
} else {
|
|
119
|
-
result[key] = sourceValue as T[Extract<keyof T, string>]
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return result
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export const pick = <T extends Record<string, any>, K extends keyof T>(
|
|
128
|
-
obj: T,
|
|
129
|
-
keys: K[]
|
|
130
|
-
): Pick<T, K> => {
|
|
131
|
-
const result = {} as Pick<T, K>
|
|
132
|
-
|
|
133
|
-
for (const key of keys) {
|
|
134
|
-
if (key in obj) {
|
|
135
|
-
result[key] = obj[key]
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return result
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export const omit = <T extends Record<string, any>, K extends keyof T>(
|
|
143
|
-
obj: T,
|
|
144
|
-
keys: K[]
|
|
145
|
-
): Omit<T, K> => {
|
|
146
|
-
const result = { ...obj }
|
|
147
|
-
|
|
148
|
-
for (const key of keys) {
|
|
149
|
-
delete result[key]
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return result
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export const generateId = (length: number = 8): string => {
|
|
156
|
-
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
157
|
-
let result = ''
|
|
158
|
-
|
|
159
|
-
for (let i = 0; i < length; i++) {
|
|
160
|
-
result += chars.charAt(Math.floor(Math.random() * chars.length))
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return result
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export const safeJsonParse = <T = any>(json: string, fallback: T): T => {
|
|
167
|
-
try {
|
|
168
|
-
return JSON.parse(json)
|
|
169
|
-
} catch {
|
|
170
|
-
return fallback
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export const safeJsonStringify = (obj: any, fallback: string = '{}'): string => {
|
|
175
|
-
try {
|
|
176
|
-
return JSON.stringify(obj)
|
|
177
|
-
} catch {
|
|
178
|
-
return fallback
|
|
179
|
-
}
|
|
180
|
-
}
|
package/core/utils/index.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FluxStack Utilities
|
|
3
|
-
* Main exports for utility functions and classes
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Logger utilities
|
|
7
|
-
export { logger, log } from "./logger"
|
|
8
|
-
export type { Logger } from "./logger/index"
|
|
9
|
-
|
|
10
|
-
// Error handling
|
|
11
|
-
export * from "./errors"
|
|
12
|
-
|
|
13
|
-
// Monitoring
|
|
14
|
-
export { MetricsCollector } from "./monitoring"
|
|
15
|
-
export type * from "./monitoring"
|
|
16
|
-
|
|
17
|
-
// General helpers
|
|
18
|
-
export * from "./helpers"
|