ilana-orm 1.0.14 → 1.0.15

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/README.md CHANGED
@@ -104,17 +104,23 @@ A fully-featured, Eloquent-style ORM for Node.js with automatic TypeScript suppo
104
104
  ## Installation
105
105
 
106
106
  ```bash
107
- # npm
108
107
  npm install ilana-orm
108
+ ```
109
109
 
110
- # yarn
111
- yarn add ilana-orm
110
+ ### Database Drivers
112
111
 
113
- # pnpm
114
- pnpm add ilana-orm
115
- ```
112
+ Install only the database driver you need:
116
113
 
117
- **All database drivers (PostgreSQL, MySQL, SQLite) and dotenv are included by default** - no additional installation required!
114
+ ```bash
115
+ # PostgreSQL
116
+ npm install pg
117
+
118
+ # MySQL
119
+ npm install mysql2
120
+
121
+ # SQLite
122
+ npm install sqlite3
123
+ ```
118
124
 
119
125
  ## Quick Start
120
126
 
@@ -4771,6 +4777,32 @@ class CustomCast {
4771
4777
 
4772
4778
  We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
4773
4779
 
4780
+ ## Security
4781
+
4782
+ ### Reporting Vulnerabilities
4783
+
4784
+ If you discover a security vulnerability, please email raphyabak@gmail.com with:
4785
+ - Description of the vulnerability
4786
+ - Steps to reproduce
4787
+ - Potential impact
4788
+
4789
+ We will respond within 48 hours.
4790
+
4791
+ ### Security Considerations
4792
+
4793
+ **Database Drivers**: Database drivers (pg, mysql2, sqlite3) are optional dependencies. Install only what you need to reduce your security surface:
4794
+ ```bash
4795
+ npm install pg # PostgreSQL
4796
+ npm install mysql2 # MySQL
4797
+ npm install sqlite3 # SQLite
4798
+ ```
4799
+
4800
+ **SQL Injection Protection**: IlanaORM uses parameterized queries via Knex.js. Always use query builder methods instead of raw SQL.
4801
+
4802
+ **Filesystem Access**: The CLI and migration tools require filesystem access. Review migration files before running.
4803
+
4804
+ **Network Access**: Database drivers make network connections. Ensure proper firewall and connection security.
4805
+
4774
4806
  ## License
4775
4807
 
4776
4808
  MIT License - see the [LICENSE](LICENSE) file for details.
@@ -10,17 +10,28 @@ class Database {
10
10
 
11
11
  // Initialize all configured connections
12
12
  for (const [name, connConfig] of Object.entries(config.connections)) {
13
- const connection = knex({
14
- ...connConfig,
15
- migrations: config.migrations || {
16
- directory: './migrations',
17
- tableName: 'migrations'
18
- },
19
- seeds: config.seeds || {
20
- directory: './seeds'
13
+ try {
14
+ const connection = knex({
15
+ ...connConfig,
16
+ migrations: config.migrations || {
17
+ directory: './migrations',
18
+ tableName: 'migrations'
19
+ },
20
+ seeds: config.seeds || {
21
+ directory: './seeds'
22
+ }
23
+ });
24
+ this.connections.set(name, connection);
25
+ } catch (error) {
26
+ if (error.code === 'MODULE_NOT_FOUND' && error.message.includes(connConfig.client)) {
27
+ const driverMap = { pg: 'pg', mysql2: 'mysql2', sqlite3: 'sqlite3' };
28
+ const driver = driverMap[connConfig.client] || connConfig.client;
29
+ throw new Error(
30
+ `Database driver '${driver}' not installed. Install it with: npm install ${driver}`
31
+ );
21
32
  }
22
- });
23
- this.connections.set(name, connection);
33
+ throw error;
34
+ }
24
35
  }
25
36
 
26
37
  // Set default instance after all connections are created
package/orm/Model.js CHANGED
@@ -290,20 +290,7 @@ class Model {
290
290
  if (cast === 'json' || cast === 'array') {
291
291
  try { return JSON.parse(val); } catch { return val; }
292
292
  }
293
- if (cast === 'date' && val != null) {
294
- const config = this._getConfig();
295
- const timezone = this.constructor.timezone || config?.timezone || 'UTC';
296
-
297
- try {
298
- // Try moment-timezone first
299
- const moment = require('moment-timezone');
300
- // Parse the stored value as if it's in the configured timezone
301
- return moment.tz(val, timezone).format('YYYY-MM-DD HH:mm:ss');
302
- } catch (e) {
303
- // Fallback: return the stored value as-is since it's already in the correct timezone
304
- return val;
305
- }
306
- }
293
+ if (cast === 'date' && val != null) return val;
307
294
  return val;
308
295
  }
309
296
 
@@ -337,38 +324,29 @@ class Model {
337
324
  }
338
325
 
339
326
  _getCurrentTimestamp() {
327
+ const now = new Date();
340
328
  const config = this._getConfig();
341
329
  const timezone = this.constructor.timezone || config?.timezone || 'UTC';
342
-
343
- try {
344
- // Try to use moment-timezone if available
345
- const moment = require('moment-timezone');
346
- return moment().tz(timezone).toDate();
347
- } catch (e) {
348
- try {
349
- // Try to use date-fns-tz if available
350
- const { zonedTimeToUtc } = require('date-fns-tz');
351
- return zonedTimeToUtc(new Date(), timezone);
352
- } catch (e2) {
353
- // Fallback to simple but accurate method
354
- const now = new Date();
355
- if (timezone === 'UTC') return now;
356
-
357
- // Use toLocaleString for accurate timezone conversion
358
- const utcTime = now.getTime() + (now.getTimezoneOffset() * 60000);
359
- const targetTime = new Date(utcTime + (this._getTimezoneOffset(timezone, now) * 60000));
360
- return targetTime;
361
- }
362
- }
363
- }
364
-
365
- _getTimezoneOffset(timezone, date) {
330
+
331
+ if (timezone === 'UTC') return now;
332
+
366
333
  try {
367
- const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' }));
368
- const targetDate = new Date(date.toLocaleString('en-US', { timeZone: timezone }));
369
- return (targetDate.getTime() - utcDate.getTime()) / 60000;
370
- } catch (e) {
371
- return 0; // Default to UTC
334
+ const formatter = new Intl.DateTimeFormat('en-US', {
335
+ timeZone: timezone,
336
+ year: 'numeric',
337
+ month: '2-digit',
338
+ day: '2-digit',
339
+ hour: '2-digit',
340
+ minute: '2-digit',
341
+ second: '2-digit',
342
+ hour12: false
343
+ });
344
+ const parts = Object.fromEntries(
345
+ formatter.formatToParts(now).map(p => [p.type, p.value])
346
+ );
347
+ return new Date(`${parts.year}-${parts.month}-${parts.day}T${parts.hour}:${parts.minute}:${parts.second}`);
348
+ } catch {
349
+ return now;
372
350
  }
373
351
  }
374
352
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ilana-orm",
3
- "version": "1.0.14",
3
+ "version": "1.0.15",
4
4
  "description": "A fully-featured, Eloquent-style ORM for Node.js with TypeScript support",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -114,14 +114,15 @@
114
114
  "ilana.png"
115
115
  ],
116
116
  "dependencies": {
117
- "knex": "^3.0.0",
118
- "uuid": "^9.0.0",
119
- "@faker-js/faker": "^8.0.0",
120
- "pg": "^8.0.0",
121
- "mysql2": "^3.0.0",
122
- "sqlite3": "^5.0.0",
123
- "dotenv": "^16.3.1",
124
- "moment-timezone": "^0.6.0"
117
+ "knex": "^3.1.0",
118
+ "uuid": "^10.0.0",
119
+ "@faker-js/faker": "^9.0.0",
120
+ "dotenv": "^16.4.0"
121
+ },
122
+ "optionalDependencies": {
123
+ "pg": "^8.13.0",
124
+ "mysql2": "^3.11.0",
125
+ "sqlite3": "^5.1.7"
125
126
  },
126
127
  "devDependencies": {
127
128
  "@types/node": "^20.0.0",