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 +39 -7
- package/database/connection.js +21 -10
- package/orm/Model.js +21 -43
- package/package.json +10 -9
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
|
-
|
|
111
|
-
yarn add ilana-orm
|
|
110
|
+
### Database Drivers
|
|
112
111
|
|
|
113
|
-
|
|
114
|
-
pnpm add ilana-orm
|
|
115
|
-
```
|
|
112
|
+
Install only the database driver you need:
|
|
116
113
|
|
|
117
|
-
|
|
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.
|
package/database/connection.js
CHANGED
|
@@ -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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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
|
-
|
|
344
|
-
|
|
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
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
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.
|
|
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.
|
|
118
|
-
"uuid": "^
|
|
119
|
-
"@faker-js/faker": "^
|
|
120
|
-
"
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
"
|
|
124
|
-
"
|
|
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",
|