vasuzex 2.1.2 → 2.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/.ai-memory/LOGGER_STRICT_POLICY.md +201 -0
  2. package/.ai-memory/neastore-feature-mapping.md +1114 -0
  3. package/bin/create-vasuzex.js +5 -2
  4. package/examples/runtime-config-examples.js +309 -0
  5. package/framework/Config/DatabaseConfigService.js +348 -0
  6. package/framework/Config/DatabaseConfigServiceProvider.js +69 -0
  7. package/framework/Console/Commands/generate-app.js +97 -4
  8. package/framework/Console/Commands/generate-media-server.js +2 -1
  9. package/framework/Console/Commands/utils/mediaServerTemplates.js +3 -2
  10. package/framework/Console/Commands/utils/webStructure.js +30 -21
  11. package/framework/Console/config/generator.config.js +3 -3
  12. package/framework/Console/plopfile.js +0 -8
  13. package/framework/Console/templates/api/app.js.hbs +5 -4
  14. package/framework/Console/templates/api/server.js.hbs +8 -2
  15. package/framework/Database/DatabaseServiceProvider.js +1 -1
  16. package/framework/Database/Model.js +9 -0
  17. package/framework/Exceptions/index.js +2 -1
  18. package/framework/Foundation/BaseApp.js +19 -0
  19. package/framework/Foundation/BaseService.js +95 -0
  20. package/framework/Foundation/Container.js +18 -3
  21. package/framework/Foundation/Providers/index.js +0 -1
  22. package/framework/Foundation/ServiceProvider.js +42 -0
  23. package/framework/Http/asyncHandler.js +26 -0
  24. package/framework/Http/index.js +1 -0
  25. package/framework/Services/Log/LogManager.js +26 -5
  26. package/framework/Services/Log/LogServiceProvider.js +48 -0
  27. package/framework/Services/Log/index.js +1 -0
  28. package/framework/Services/Mail/MailServiceProvider.js +36 -0
  29. package/framework/Services/Mail/index.js +1 -0
  30. package/framework/Services/Media/MediaServiceProvider.js +2 -2
  31. package/framework/Services/Payment/PaymentServiceProvider.js +35 -0
  32. package/framework/Services/Payment/index.js +1 -0
  33. package/framework/Services/Security/SecurityService.js +253 -0
  34. package/framework/Services/Security/SecurityServiceProvider.js +33 -0
  35. package/framework/Services/Security/index.js +9 -0
  36. package/framework/Services/Storage/StorageManager.js +7 -1
  37. package/framework/Services/Storage/StorageServiceProvider.js +36 -0
  38. package/framework/Services/Storage/index.js +1 -0
  39. package/framework/Services/Upload/UploadManager.js +179 -0
  40. package/framework/Services/index.js +1 -0
  41. package/framework/Support/Facades/Security.js +14 -0
  42. package/framework/Support/Facades/index.js +1 -0
  43. package/framework/Support/Helpers/index.js +1 -0
  44. package/framework/Support/Helpers/utilities.js +348 -0
  45. package/framework/index.js +2 -0
  46. package/frontend/client/Config/ConfigLoader.js +52 -10
  47. package/frontend/client/Http/ApiHelpers.js +99 -0
  48. package/frontend/client/Http/index.js +1 -0
  49. package/frontend/client/index.js +1 -1
  50. package/frontend/client/package.json +14 -66
  51. package/frontend/client/package.json.backup +41 -0
  52. package/frontend/react-ui/components/Avatars/GradientAvatar.jsx +255 -0
  53. package/frontend/react-ui/components/Avatars/index.js +66 -0
  54. package/frontend/react-ui/components/BreadCrumb/BreadCrumb.jsx +69 -0
  55. package/frontend/react-ui/components/BreadCrumb/index.js +2 -0
  56. package/frontend/react-ui/components/DataTable/ActionDefaults.jsx +171 -0
  57. package/frontend/react-ui/components/DataTable/DataTable.jsx +202 -328
  58. package/frontend/react-ui/components/DataTable/Filters.jsx +69 -56
  59. package/frontend/react-ui/components/DataTable/Pagination.jsx +59 -140
  60. package/frontend/react-ui/components/DataTable/TableActions.jsx +11 -20
  61. package/frontend/react-ui/components/DataTable/TableBody.jsx +168 -168
  62. package/frontend/react-ui/components/DataTable/TableHeader.jsx +93 -96
  63. package/frontend/react-ui/components/DataTable/TableState.jsx +33 -0
  64. package/frontend/react-ui/components/DataTable/index.js +10 -8
  65. package/frontend/react-ui/components/ImageLightbox/ImageLightbox.jsx +118 -0
  66. package/frontend/react-ui/components/ImageLightbox/index.js +1 -0
  67. package/frontend/react-ui/components/OrderTimeline/OrderTimeline.jsx +269 -0
  68. package/frontend/react-ui/components/OrderTimeline/index.js +1 -0
  69. package/frontend/react-ui/components/ReadMore/ReadMore.jsx +34 -0
  70. package/frontend/react-ui/components/ReadMore/index.js +1 -0
  71. package/frontend/react-ui/components/Switch/Switch.jsx +34 -0
  72. package/frontend/react-ui/components/Switch/index.js +1 -0
  73. package/frontend/react-ui/hooks/useAppConfig.js +58 -4
  74. package/frontend/react-ui/hooks/useLocalStorage.js +1 -1
  75. package/frontend/react-ui/hooks/useValidationErrors.js +1 -1
  76. package/frontend/react-ui/index.js +10 -0
  77. package/frontend/react-ui/package.json +17 -108
  78. package/frontend/react-ui/providers/ApiClientProvider.jsx +1 -1
  79. package/frontend/react-ui/providers/AppConfigProvider.jsx +212 -20
  80. package/frontend/react-ui/utils/formatters.js +193 -0
  81. package/frontend/react-ui/utils/index.js +30 -0
  82. package/frontend/react-ui/utils/logger.js +62 -0
  83. package/frontend/react-ui/utils/storage.js +90 -0
  84. package/frontend/react-ui/utils/swal.js +134 -0
  85. package/frontend/react-ui/utils/validation.js +207 -0
  86. package/package.json +6 -2
  87. package/framework/Foundation/Providers/LogServiceProvider.js +0 -33
@@ -3,6 +3,7 @@ export { Response } from './Response.js';
3
3
  export { Controller } from './Controller.js';
4
4
  export { FormRequest } from './Requests/index.js';
5
5
  export { ClientConfigGenerator } from './ClientConfigGenerator.js';
6
+ export { asyncHandler } from './asyncHandler.js';
6
7
  export { requestResponseMiddleware } from './Middleware/RequestResponseMiddleware.js';
7
8
  export { SecurityMiddleware, createSecurityMiddleware, applySecurityMiddleware } from './Middleware/SecurityMiddleware.js';
8
9
  export { MediaServerMiddleware, mediaServer } from './Middleware/MediaServerMiddleware.js';
@@ -156,25 +156,46 @@ export class LogManager {
156
156
  return str.charAt(0).toUpperCase() + str.slice(1);
157
157
  }
158
158
 
159
+ /**
160
+ * Filter context based on debug mode
161
+ * Remove stack trace in production
162
+ */
163
+ filterContext(context = {}) {
164
+ const debugValue = this.app.config('app.debug', false);
165
+ // Handle string 'false' or 'true' from env
166
+ const isDebug = debugValue === true || debugValue === 'true';
167
+
168
+ // In debug mode, return full context
169
+ if (isDebug) {
170
+ return context;
171
+ }
172
+
173
+ // In production, remove stack trace
174
+ const filtered = { ...context };
175
+ delete filtered.stack;
176
+
177
+ return filtered;
178
+ }
179
+
159
180
  // Proxy PSR-3 methods to default channel
160
181
  emergency(message, context = {}) {
161
- return this.channel().emergency(message, context);
182
+ return this.channel().emergency(message, this.filterContext(context));
162
183
  }
163
184
 
164
185
  alert(message, context = {}) {
165
- return this.channel().alert(message, context);
186
+ return this.channel().alert(message, this.filterContext(context));
166
187
  }
167
188
 
168
189
  critical(message, context = {}) {
169
- return this.channel().critical(message, context);
190
+ return this.channel().critical(message, this.filterContext(context));
170
191
  }
171
192
 
172
193
  error(message, context = {}) {
173
- return this.channel().error(message, context);
194
+ return this.channel().error(message, this.filterContext(context));
174
195
  }
175
196
 
176
197
  warning(message, context = {}) {
177
- return this.channel().warning(message, context);
198
+ return this.channel().warning(message, this.filterContext(context));
178
199
  }
179
200
 
180
201
  notice(message, context = {}) {
@@ -0,0 +1,48 @@
1
+ import { ServiceProvider } from '../../Foundation/ServiceProvider.js';
2
+ import { LogManager } from './LogManager.js';
3
+
4
+ /**
5
+ * Log Service Provider
6
+ *
7
+ * Registers Log service in the application container.
8
+ * Provides logging capabilities via multiple channels (Console, File, Syslog, Stack).
9
+ */
10
+ export class LogServiceProvider extends ServiceProvider {
11
+ /**
12
+ * Register the service
13
+ */
14
+ async register() {
15
+ this.singleton('log', (app) => {
16
+ return new LogManager(app);
17
+ });
18
+
19
+ // Create aliases
20
+ this.alias('logger', 'log');
21
+ this.alias('Logger', 'log');
22
+ }
23
+
24
+ /**
25
+ * Bootstrap the service
26
+ */
27
+ async boot() {
28
+ // Initialize default log channel only if config is loaded
29
+ try {
30
+ const defaultChannel = this.config('logging.default');
31
+ if (defaultChannel) {
32
+ const log = this.make('log');
33
+
34
+ // Pre-create default channel to verify configuration
35
+ try {
36
+ log.driver(defaultChannel);
37
+ } catch (error) {
38
+ console.error(`[LogServiceProvider] Failed to initialize log channel [${defaultChannel}]:`, error.message);
39
+ }
40
+ }
41
+ } catch (error) {
42
+ // Config might not be loaded yet - skip initialization
43
+ // This is fine, log will be initialized on first use
44
+ }
45
+ }
46
+ }
47
+
48
+ export default LogServiceProvider;
@@ -1,4 +1,5 @@
1
1
  export { LogManager } from './LogManager.js';
2
+ export { LogServiceProvider } from './LogServiceProvider.js';
2
3
  export { Logger } from './Logger.js';
3
4
  export { ConsoleLogger } from './Drivers/ConsoleLogger.js';
4
5
  export { FileLogger } from './Drivers/FileLogger.js';
@@ -0,0 +1,36 @@
1
+ import { ServiceProvider } from '../../Foundation/ServiceProvider.js';
2
+ import { MailManager } from './MailManager.js';
3
+
4
+ /**
5
+ * Mail Service Provider
6
+ *
7
+ * Registers Mail service in the application container.
8
+ * Provides email sending capabilities via multiple drivers (SMTP, SendGrid, SES).
9
+ */
10
+ export class MailServiceProvider extends ServiceProvider {
11
+ /**
12
+ * Register the service
13
+ */
14
+ async register() {
15
+ this.singleton('mail', (app) => {
16
+ return new MailManager(app);
17
+ });
18
+
19
+ // Create aliases
20
+ this.alias('mailer', 'mail');
21
+ this.alias('Mail', 'mail');
22
+ }
23
+
24
+ /**
25
+ * Bootstrap the service
26
+ */
27
+ async boot() {
28
+ // Mail service is ready to use
29
+ if (this.config('mail.default')) {
30
+ const mail = this.make('mail');
31
+ console.log(`[MailServiceProvider] Mail service initialized with driver: ${this.config('mail.default')}`);
32
+ }
33
+ }
34
+ }
35
+
36
+ export default MailServiceProvider;
@@ -1 +1,2 @@
1
1
  export { MailManager } from './MailManager.js';
2
+ export { MailServiceProvider } from './MailServiceProvider.js';
@@ -11,7 +11,7 @@ export class MediaServiceProvider extends ServiceProvider {
11
11
  * Register the service provider
12
12
  */
13
13
  register() {
14
- this.app.singleton('media', (app) => {
14
+ this.singleton('media', (app) => {
15
15
  return new MediaManager(app);
16
16
  });
17
17
  }
@@ -21,7 +21,7 @@ export class MediaServiceProvider extends ServiceProvider {
21
21
  */
22
22
  boot() {
23
23
  // Ensure cache directory exists
24
- const media = this.app.make('media');
24
+ const media = this.make('media');
25
25
 
26
26
  if (!existsSync(media.cacheDir)) {
27
27
  mkdirSync(media.cacheDir, { recursive: true });
@@ -0,0 +1,35 @@
1
+ import { ServiceProvider } from '../../Foundation/ServiceProvider.js';
2
+ import { PaymentManager } from './PaymentManager.js';
3
+
4
+ /**
5
+ * Payment Service Provider
6
+ *
7
+ * Registers Payment service in the application container.
8
+ * Provides payment gateway capabilities (PhonePe, Razorpay, Stripe).
9
+ */
10
+ export class PaymentServiceProvider extends ServiceProvider {
11
+ /**
12
+ * Register the service
13
+ */
14
+ async register() {
15
+ this.singleton('payment', (app) => {
16
+ return new PaymentManager(app);
17
+ });
18
+
19
+ // Create aliases
20
+ this.alias('Payment', 'payment');
21
+ }
22
+
23
+ /**
24
+ * Bootstrap the service
25
+ */
26
+ async boot() {
27
+ // Payment service is ready to use
28
+ if (this.config('payment.default')) {
29
+ const payment = this.make('payment');
30
+ console.log(`[PaymentServiceProvider] Payment service initialized with gateway: ${this.config('payment.default')}`);
31
+ }
32
+ }
33
+ }
34
+
35
+ export default PaymentServiceProvider;
@@ -1,5 +1,6 @@
1
1
  export { PaymentManager } from "./PaymentManager.js";
2
2
  export { PaymentGateway } from "./PaymentGateway.js";
3
+ export { PaymentServiceProvider } from "./PaymentServiceProvider.js";
3
4
  export { PhonePeGateway } from "./Gateways/PhonePeGateway.js";
4
5
  export { RazorpayGateway } from "./Gateways/RazorpayGateway.js";
5
6
  export { StripeGateway } from "./Gateways/StripeGateway.js";
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Security Service
3
+ * Handles JWT, OTP, hashing, and other security-related operations
4
+ * Laravel-inspired security utilities for Node.js
5
+ */
6
+
7
+ import jwt from 'jsonwebtoken';
8
+ import bcrypt from 'bcryptjs';
9
+ import crypto from 'crypto';
10
+
11
+ export class SecurityService {
12
+ constructor(config = {}) {
13
+ this.jwtSecret = config.jwtSecret || process.env.JWT_SECRET || 'your-secret-key';
14
+ this.jwtExpiresIn = config.jwtExpiresIn || process.env.JWT_EXPIRES_IN || '7d';
15
+ this.otpLength = config.otpLength || 6;
16
+ this.otpExpiryMinutes = config.otpExpiryMinutes || 10;
17
+ this.bcryptRounds = config.bcryptRounds || 10;
18
+ }
19
+
20
+ /**
21
+ * Generate JWT token
22
+ * @param {Object} payload - Data to encode in token
23
+ * @param {string} secret - Optional JWT secret (uses config if not provided)
24
+ * @param {string|number} expiresIn - Optional expiry time (uses config if not provided)
25
+ * @returns {string} JWT token
26
+ */
27
+ generateToken(payload, secret = null, expiresIn = null) {
28
+ const jwtSecret = secret || this.jwtSecret;
29
+ const jwtExpiresIn = expiresIn || this.jwtExpiresIn;
30
+
31
+ return jwt.sign(payload, jwtSecret, { expiresIn: jwtExpiresIn });
32
+ }
33
+
34
+ /**
35
+ * Verify JWT token
36
+ * @param {string} token - JWT token to verify
37
+ * @param {string} secret - Optional JWT secret (uses config if not provided)
38
+ * @returns {Object|null} Decoded payload or null if invalid
39
+ */
40
+ verifyToken(token, secret = null) {
41
+ const jwtSecret = secret || this.jwtSecret;
42
+ try {
43
+ return jwt.verify(token, jwtSecret);
44
+ } catch (error) {
45
+ console.error('JWT verification failed:', error.message);
46
+ return null;
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Decode JWT token without verification
52
+ * @param {string} token - JWT token to decode
53
+ * @returns {Object|null} Decoded payload or null if invalid
54
+ */
55
+ decodeToken(token) {
56
+ try {
57
+ return jwt.decode(token);
58
+ } catch (error) {
59
+ return null;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Generate numeric OTP
65
+ * @param {number} length - OTP length (default: 6)
66
+ * @returns {string} OTP code
67
+ */
68
+ generateOtp(length = this.otpLength) {
69
+ const min = Math.pow(10, length - 1);
70
+ const max = Math.pow(10, length) - 1;
71
+ return Math.floor(min + Math.random() * (max - min + 1)).toString();
72
+ }
73
+
74
+ /**
75
+ * Generate alphanumeric OTP
76
+ * @param {number} length - OTP length
77
+ * @returns {string} Alphanumeric OTP
78
+ */
79
+ generateAlphanumericOtp(length = this.otpLength) {
80
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
81
+ let otp = '';
82
+ for (let i = 0; i < length; i++) {
83
+ otp += chars.charAt(Math.floor(Math.random() * chars.length));
84
+ }
85
+ return otp;
86
+ }
87
+
88
+ /**
89
+ * Hash password using bcrypt
90
+ * @param {string} password - Plain text password
91
+ * @returns {Promise<string>} Hashed password
92
+ */
93
+ async hashPassword(password) {
94
+ return await bcrypt.hash(password, this.bcryptRounds);
95
+ }
96
+
97
+ /**
98
+ * Verify password against hash
99
+ * @param {string} password - Plain text password
100
+ * @param {string} hash - Hashed password
101
+ * @returns {Promise<boolean>} Match result
102
+ */
103
+ async verifyPassword(password, hash) {
104
+ return await bcrypt.compare(password, hash);
105
+ }
106
+
107
+ /**
108
+ * Generate random string
109
+ * @param {number} length - String length
110
+ * @returns {string} Random string
111
+ */
112
+ generateRandomString(length = 32) {
113
+ return crypto.randomBytes(length).toString('hex').substring(0, length);
114
+ }
115
+
116
+ /**
117
+ * Generate UUID v4
118
+ * @returns {string} UUID
119
+ */
120
+ generateUuid() {
121
+ return crypto.randomUUID();
122
+ }
123
+
124
+ /**
125
+ * Hash string using SHA256
126
+ * @param {string} data - Data to hash
127
+ * @returns {string} Hash
128
+ */
129
+ hash(data) {
130
+ return crypto.createHash('sha256').update(data).digest('hex');
131
+ }
132
+
133
+ /**
134
+ * Hash string using MD5
135
+ * @param {string} data - Data to hash
136
+ * @returns {string} Hash
137
+ */
138
+ md5(data) {
139
+ return crypto.createHash('md5').update(data).digest('hex');
140
+ }
141
+
142
+ /**
143
+ * Create HMAC signature
144
+ * @param {string} data - Data to sign
145
+ * @param {string} secret - Secret key
146
+ * @param {string} algorithm - Hash algorithm (default: sha256)
147
+ * @returns {string} Signature
148
+ */
149
+ createHmac(data, secret, algorithm = 'sha256') {
150
+ return crypto.createHmac(algorithm, secret).update(data).digest('hex');
151
+ }
152
+
153
+ /**
154
+ * Verify HMAC signature
155
+ * @param {string} data - Original data
156
+ * @param {string} signature - Signature to verify
157
+ * @param {string} secret - Secret key
158
+ * @param {string} algorithm - Hash algorithm
159
+ * @returns {boolean} Verification result
160
+ */
161
+ verifyHmac(data, signature, secret, algorithm = 'sha256') {
162
+ const expectedSignature = this.createHmac(data, secret, algorithm);
163
+ return crypto.timingSafeEqual(
164
+ Buffer.from(signature),
165
+ Buffer.from(expectedSignature)
166
+ );
167
+ }
168
+
169
+ /**
170
+ * Encrypt data using AES-256-CBC
171
+ * @param {string} data - Data to encrypt
172
+ * @param {string} key - Encryption key (32 bytes)
173
+ * @returns {string} Encrypted data (iv:encrypted format)
174
+ */
175
+ encrypt(data, key) {
176
+ const iv = crypto.randomBytes(16);
177
+ const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key.padEnd(32, '0').slice(0, 32)), iv);
178
+ let encrypted = cipher.update(data, 'utf8', 'hex');
179
+ encrypted += cipher.final('hex');
180
+ return iv.toString('hex') + ':' + encrypted;
181
+ }
182
+
183
+ /**
184
+ * Decrypt data using AES-256-CBC
185
+ * @param {string} encrypted - Encrypted data (iv:encrypted format)
186
+ * @param {string} key - Encryption key (32 bytes)
187
+ * @returns {string} Decrypted data
188
+ */
189
+ decrypt(encrypted, key) {
190
+ const parts = encrypted.split(':');
191
+ const iv = Buffer.from(parts[0], 'hex');
192
+ const encryptedData = parts[1];
193
+ const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key.padEnd(32, '0').slice(0, 32)), iv);
194
+ let decrypted = decipher.update(encryptedData, 'hex', 'utf8');
195
+ decrypted += decipher.final('utf8');
196
+ return decrypted;
197
+ }
198
+
199
+ /**
200
+ * Mask phone number for display
201
+ * @param {string} phone - Phone number
202
+ * @returns {string} Masked phone
203
+ */
204
+ maskPhone(phone) {
205
+ if (phone.length !== 10) return phone;
206
+ return phone.replace(/(\d{3})\d{4}(\d{3})/, '$1****$2');
207
+ }
208
+
209
+ /**
210
+ * Mask email for display
211
+ * @param {string} email - Email address
212
+ * @returns {string} Masked email
213
+ */
214
+ maskEmail(email) {
215
+ const [username, domain] = email.split('@');
216
+ if (!username || !domain) return email;
217
+
218
+ const maskedUsername =
219
+ username.length > 2
220
+ ? `${username[0]}${'*'.repeat(username.length - 2)}${username[username.length - 1]}`
221
+ : username;
222
+
223
+ return `${maskedUsername}@${domain}`;
224
+ }
225
+
226
+ /**
227
+ * Generate OTP with expiry timestamp
228
+ * @param {number} length - OTP length
229
+ * @returns {Object} {otp, expiresAt}
230
+ */
231
+ generateOtpWithExpiry(length = this.otpLength) {
232
+ const otp = this.generateOtp(length);
233
+ const expiresAt = new Date(Date.now() + this.otpExpiryMinutes * 60 * 1000);
234
+ return { otp, expiresAt };
235
+ }
236
+
237
+ /**
238
+ * Verify OTP with expiry check
239
+ * @param {string} inputOtp - User input OTP
240
+ * @param {string} storedOtp - Stored OTP
241
+ * @param {Date} expiresAt - Expiry timestamp
242
+ * @returns {Object} {valid, expired}
243
+ */
244
+ verifyOtp(inputOtp, storedOtp, expiresAt) {
245
+ const now = new Date();
246
+ const expired = now > new Date(expiresAt);
247
+ const valid = inputOtp === storedOtp;
248
+
249
+ return { valid: valid && !expired, expired };
250
+ }
251
+ }
252
+
253
+ export default SecurityService;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Security Service Provider
3
+ * Registers security service in the application container
4
+ */
5
+
6
+ import { ServiceProvider } from '../../Foundation/ServiceProvider.js';
7
+ import { SecurityService } from './SecurityService.js';
8
+
9
+ export class SecurityServiceProvider extends ServiceProvider {
10
+ /**
11
+ * Register security service
12
+ */
13
+ async register() {
14
+ this.app.singleton('security', () => {
15
+ return new SecurityService({
16
+ jwtSecret: this.app.config('app.key') || this.app.config('security.jwt.secret'),
17
+ jwtExpiresIn: this.app.config('security.jwt.expiresIn') || '7d',
18
+ otpLength: this.app.config('security.otp.length') || 6,
19
+ otpExpiryMinutes: this.app.config('security.otp.expiryMinutes') || 10,
20
+ bcryptRounds: this.app.config('security.bcrypt.rounds') || 10,
21
+ });
22
+ });
23
+ }
24
+
25
+ /**
26
+ * Boot security service
27
+ */
28
+ async boot() {
29
+ // Security service is ready
30
+ }
31
+ }
32
+
33
+ export default SecurityServiceProvider;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Security Service Module
3
+ * JWT, OTP, Hashing, and Security utilities
4
+ */
5
+
6
+ export { SecurityService } from './SecurityService.js';
7
+ export { SecurityServiceProvider } from './SecurityServiceProvider.js';
8
+ import { SecurityService } from './SecurityService.js';
9
+ export default SecurityService;
@@ -24,6 +24,7 @@
24
24
 
25
25
  import { LocalStorageProvider } from './Providers/LocalStorageProvider.js';
26
26
  import { S3StorageProvider } from './Providers/S3StorageProvider.js';
27
+ import path from 'path';
27
28
 
28
29
  export class StorageManager {
29
30
  /**
@@ -93,7 +94,12 @@ export class StorageManager {
93
94
  * @private
94
95
  */
95
96
  createLocalDriver(config) {
96
- return new LocalStorageProvider(config);
97
+ // Resolve root path relative to app's rootDir
98
+ const resolvedConfig = { ...config };
99
+ if (config.root && !path.isAbsolute(config.root)) {
100
+ resolvedConfig.root = path.resolve(this.app.rootDir, config.root);
101
+ }
102
+ return new LocalStorageProvider(resolvedConfig);
97
103
  }
98
104
 
99
105
  /**
@@ -0,0 +1,36 @@
1
+ import { ServiceProvider } from '../../Foundation/ServiceProvider.js';
2
+ import { StorageManager } from './StorageManager.js';
3
+
4
+ /**
5
+ * Storage Service Provider
6
+ *
7
+ * Registers Storage service in the application container.
8
+ * Provides file storage capabilities via multiple drivers (Local, S3, MinIO).
9
+ */
10
+ export class StorageServiceProvider extends ServiceProvider {
11
+ /**
12
+ * Register the service
13
+ */
14
+ async register() {
15
+ this.singleton('storage', (app) => {
16
+ return new StorageManager(app);
17
+ });
18
+
19
+ // Create aliases
20
+ this.alias('filesystem', 'storage');
21
+ this.alias('Storage', 'storage');
22
+ }
23
+
24
+ /**
25
+ * Bootstrap the service
26
+ */
27
+ async boot() {
28
+ // Storage service is ready to use
29
+ if (this.config('filesystems.default')) {
30
+ const storage = this.make('storage');
31
+ console.log(`[StorageServiceProvider] Storage service initialized with driver: ${this.config('filesystems.default')}`);
32
+ }
33
+ }
34
+ }
35
+
36
+ export default StorageServiceProvider;
@@ -1,2 +1,3 @@
1
1
  export { StorageManager } from './StorageManager.js';
2
+ export { StorageServiceProvider } from './StorageServiceProvider.js';
2
3
  export * from './Providers/index.js';