@mlagie/sql-connector 1.4.9 → 2.0.0

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/docs/fr/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Documentation du module sql-connector
2
2
 
3
+ ![GitHub package.json version](https://img.shields.io/github/package-json/v/lagie-marin/sql-connector?color=#008000) ![NPM Downloads](https://img.shields.io/npm/d18m/%40mlagie%2Fsql-connector?color=#008000) ![NPM Downloads](https://img.shields.io/npm/dw/%40mlagie%2Fsql-connector?color=#008000) ![GitHub followers](https://img.shields.io/github/followers/lagie-marin?style=plastic&color=color%3D%23008000) ![GitHub repo size](https://img.shields.io/github/repo-size/lagie-marin/sql-connector?color=%green)
4
+ ![GitHub last commit](https://img.shields.io/github/last-commit/lagie-marin/sql-connector)
5
+
3
6
  [English](../../README.md) | Français
4
7
 
5
8
  Le module sql-connector permet de gérer des connexions MySQL, de définir des schémas, de synchroniser automatiquement des tables et d'exposer des modèles pour manipuler les données simplement.
@@ -36,18 +39,18 @@ await logout();
36
39
 
37
40
  `Schema` décrit la structure d'une table. Chaque champ peut utiliser les propriétés suivantes.
38
41
 
39
- | Propriété | Type | Description |
40
- |---|---|---|
41
- | type | `SqlType` ou `{ name: SqlType }` | Type SQL du champ |
42
- | length | `number` | Longueur maximale |
43
- | required | `boolean` | Champ obligatoire |
44
- | default | `any` | Valeur par défaut |
45
- | unique | `boolean` | Valeur unique |
46
- | auto_increment | `boolean` | Auto-incrément |
47
- | foreignKey | `string` | Référence de clé étrangère |
48
- | enum | `string[]` | Liste de valeurs autorisées |
49
- | primary_key | `boolean` | Clé primaire |
50
- | customize | `string` | Options SQL additionnelles |
42
+ | Propriété | Type | Description |
43
+ |----------------|----------------------------------|-----------------------------|
44
+ | type | `SqlType` ou `{ name: SqlType }` | Type SQL du champ |
45
+ | length | `number` | Longueur maximale |
46
+ | required | `boolean` | Champ obligatoire |
47
+ | default | `any` | Valeur par défaut |
48
+ | unique | `boolean` | Valeur unique |
49
+ | auto_increment | `boolean` | Auto-incrément |
50
+ | foreignKey | `string` | Référence de clé étrangère |
51
+ | enum | `string[]` | Liste de valeurs autorisées |
52
+ | primary_key | `boolean` | Clé primaire |
53
+ | customize | `string` | Options SQL additionnelles |
51
54
 
52
55
  ```javascript
53
56
  const userSchema = new Schema({
@@ -66,7 +69,22 @@ const userSchema = new Schema({
66
69
  type: String,
67
70
  enum: ['active', 'inactive', 'pending'],
68
71
  default: 'pending'
69
- }
72
+ },
73
+ uuid: {
74
+ type: String,
75
+ required: true,
76
+ primary_key: true,
77
+ length: 36
78
+ },
79
+ my_uuid: {
80
+ type: String,
81
+ required: true,
82
+ length: 36
83
+ },
84
+ created_at: {
85
+ type: Date,
86
+ default: sqlTypeMap.CurrentTimestamp
87
+ }
70
88
  });
71
89
  ```
72
90
 
@@ -75,13 +93,9 @@ const userSchema = new Schema({
75
93
  `Model.syncAllTables()` compare les schémas JS avec la base et applique uniquement les différences utiles.
76
94
 
77
95
  - Ajout de colonne: automatique.
78
- - Suppression de colonne: uniquement avec `dangerousSync: true`.
79
- - Renommage de colonne: possible avec `oldName`.
80
- - Tables orphelines: sauvegarde avant suppression dans un fichier `backup_*.sql`.
81
96
 
82
97
  ```javascript
83
98
  await Model.syncAllTables();
84
- await Model.syncAllTables({ dangerousSync: true });
85
99
  ```
86
100
 
87
101
  Point important: ne combinez pas `primary_key: true` et `unique: true` sur le même champ. Une clé primaire est déjà unique et non nulle.
@@ -93,24 +107,190 @@ Point important: ne combinez pas `primary_key: true` et `unique: true` sur le m
93
107
  Méthodes principales:
94
108
 
95
109
  - `save(data)` pour insérer une ligne
96
- - `findOne(filter, fields)` pour récupérer une seule entrée
97
110
  - `find(filter, fields)` pour récupérer plusieurs entrées
98
- - `findAll(options)` pour les recherches avancées
99
111
  - `count(filter)` pour compter les lignes
100
112
  - `customRequest(custom)` pour exécuter une requête SQL personnalisée
101
113
  - `delete(filter)` pour supprimer une entrée
102
114
  - `dropTable()` pour supprimer la table
103
115
  - `generate_uuid()` pour générer un UUID unique
104
- - `Model.createAllTables()` pour créer toutes les tables dans le bon ordre
105
116
 
106
117
  ```javascript
107
118
  const userModel = new Model('users', userSchema);
108
119
 
109
- await Model.createAllTables();
120
+ await Model.syncAllTables();
110
121
  await userModel.save({ email: 'user@example.com', status: 'active' });
111
122
 
112
- const user = await userModel.findOne({ email: 'user@example.com' });
113
- await userModel.delete({ email: 'user@example.com' });
123
+ const user = await userModel.find({ where: { email: 'user@example.com' }});
124
+ await user[0].deleteOne();
125
+ ```
126
+
127
+ ## Fonction save
128
+
129
+ Enregistre les données dans la table de la base de données.
130
+
131
+ - **Parameters** `data` *(Object)* - Les données à insérer dans la table.
132
+ - **Returns** `Promise<Object>` - Une promesse avec le résultat de l'insertion.
133
+ - **Throws** `Error` - Lève une erreur si l'insertion échoue.
134
+
135
+ ```js
136
+ const User = require("user");
137
+
138
+ async function createUser(email, stat) {
139
+ if (!email || !stat) {
140
+ console.error("Email & stat is required");
141
+ return;
142
+ }
143
+ await User.save({ email: email, status: stat });
144
+
145
+ }
146
+ ```
147
+
148
+ ## Fonction find
149
+
150
+ Récupère des entrées de la table.
151
+
152
+ - **Parameters** `options` *(Object)* - Options de requête
153
+ - **Parameters** `options.select` *(string[])* - Champs à renvoyer.
154
+ - **Parameters** `options.where` *(Object)* - Filtre (key/value).
155
+ - **Parameters** `options.order` *(Array)* - Ex: [['points', 'DESC']]
156
+ - **Parameters** `options.limit` *(number)* - Limite de résultats.
157
+ - **Returns** `Promise<Array<ModelInstance>>`
158
+
159
+ ### Options de find
160
+
161
+ | Option | Type | Description | Example |
162
+ |------------|-----------------|----------------------------------------------------------|----------------------------------------------|
163
+ | `select` | Array | Champs ou transformations à récupérer | `['date_day']` |
164
+ | `where` | Object / String | Conditions de filtrage | `{ project_id: 1 }` |
165
+ | `groupBy` | Array | Champs utilisés pour regrouper les résultats | `['period']` |
166
+ | `orderBy` | Array | Règles de tri | `[{ field: 'date_day', direction: 'DESC' }]` |
167
+ | `having` | String | Clause HAVING pour les requêtes agrégées | `'SUM(total_runs) > 100'` |
168
+ | `limit` | Number | Limite le nombre de résultats | `100` |
169
+
170
+ ## Exemple find
171
+
172
+ ```js
173
+ const User = require("user");
174
+
175
+ await User.find({
176
+ select: [
177
+ { dateFormat: ['date_day', '%Y-%m'], as: 'period' },
178
+ { sum: 'error' },
179
+ { sum: 'reload' },
180
+ ],
181
+ groupBy: ['period'],
182
+ orderBy: [{ field: 'period', direction: 'ASC' }],
183
+ limit: 10
184
+ });
185
+ ```
186
+
187
+ ```js
188
+ const User = require("user");
189
+
190
+ await User.find({
191
+ select: [
192
+ "email"
193
+ ],
194
+ where: {
195
+ id: 1
196
+ }
197
+ })
198
+ ```
199
+
200
+ ## Fonction count
201
+
202
+ Compte le nombre d'enregistrements correspondant au filtre donné.
203
+
204
+ - **Parameters** `filter` *(Object)* Les critères de filtrage de la requête. Il doit s'agir d'un objet dont les clés sont les noms des colonnes et les valeurs sont les valeurs de filtrage.
205
+ - **Returns** `Promise<ModelInstance|number>` - Une promesse qui se résout en une instance `ModelInstance` si un enregistrement est trouvé, ou en `0` si aucun enregistrement ne correspond au filtre.
206
+
207
+ ## Exemple count
208
+
209
+ ```js
210
+ const User = require("user");
211
+
212
+ await User.count({
213
+ id: id
214
+ })
215
+ ```
216
+
217
+ ## Fonction customRequest
218
+
219
+ La fonction customRequest vous permet d'exécuter des requêtes SQL non prises en charge par sql-connector ; cela peut concerner des requêtes utilisant des mots-clés qui ne sont pas encore implémentés.
220
+
221
+ - **Parameters** `custom` *(string)* La requête SQL personnalisée à exécuter.
222
+ - **Returns** `Promise<void>` Valeur retournée
223
+ - **Throws** `Error` Lève une erreur si l'exécution de la requête échoue.
224
+
225
+ ## Exemple customRequest
226
+
227
+ ```js
228
+ const User = require("user");
229
+
230
+ await User.customRequest("SELECT id, email, status
231
+ FROM users
232
+ WHERE status IN ('active', 'pending')
233
+ AND email LIKE '%gmail.com';")
234
+ ```
235
+
236
+ ## Fonction delete
237
+
238
+ Supprime de la table SQL une entrée correspondant au filtre fourni.
239
+
240
+ - **Parameters** `filter` *(Object)* Un objet représentant les conditions de filtrage pour la suppression.
241
+ - **Returns** `Promise<number>` Une promesse qui se résout à 0 si aucune ligne n'a été supprimée, ou à une instance de modèle représentant la ligne supprimée.
242
+ - **Throws** `Error` Une promesse qui se résout à 0 si aucune ligne n'a été supprimée, ou à une instance de modèle représentant la ligne supprimée.
243
+
244
+ ## Exemple delete
245
+
246
+ ```js
247
+ const User = require("user");
248
+
249
+ await User.delete({
250
+ email: my@gmail.com
251
+ })
252
+ ```
253
+
254
+ ## Fonction dropTable
255
+
256
+ Supprime de manière asynchrone une table si elle existe dans la base de données.
257
+
258
+ Cette fonction construit une requête SQL pour supprimer la table dont le nom est spécifié par la propriété `this.name`. Elle exécute ensuite la requête en utilisant une approche basée sur les promesses.
259
+ Si la requête aboutit, le résultat est consigné dans la console.
260
+
261
+ En cas d'erreur lors de l'exécution de la requête, un message d'erreur est consigné.
262
+
263
+ - **Returns** `Promise<void>` Une promesse qui se résout une fois l'exécution de la requête terminée.
264
+
265
+ ## Example dropTable
266
+
267
+ ```js
268
+ const User = require("user");
269
+
270
+ await User.dropTable();
271
+ ```
272
+
273
+ ## generate_uuid function
274
+
275
+ Génère un UUID unique pour le modèle actuel.
276
+
277
+ Cette fonction génère un UUID à l'aide de la fonction `UUID()` de SQL_request et vérifie si cet UUID existe déjà dans la base de données pour le modèle actuel. Si l'UUID est unique, il est renvoyé.
278
+
279
+ Sinon, la fonction renvoie `null`.
280
+
281
+ - **Parameters** `string` var_uuid Par defaut il vaut uuid
282
+ - **Returns** `Promise<string|null>` Une promesse qui se résout en une chaîne UUID unique en cas de succès, ou en `null` si une erreur survient ou si l'UUID n'est pas unique.
283
+ - **Throws** `Error` S'il y a une erreur lors de l'exécution de la requête SQL_request.
284
+
285
+ ## Example generate_uuid
286
+
287
+ ```js
288
+ const User = require("user");
289
+
290
+ const uuid = await User.generate_uuid();
291
+ const my_uuid = await User.generate_uuid("my_uuid");
292
+
293
+ await User.save{ email: "user@example.com", status: "active", uuid: uuid, my_uuid: my_uuid }
114
294
  ```
115
295
 
116
296
  ## Instances de modèle
@@ -155,4 +335,4 @@ module.exports = client => {
155
335
 
156
336
  ## Résumé
157
337
 
158
- sql-connector fournit une couche simple pour connecter une base MySQL, décrire des schémas, synchroniser les tables et manipuler les données avec des modèles typés.
338
+ sql-connector fournit une couche simple pour connecter une base MySQL, décrire des schémas, synchroniser les tables et manipuler les données avec des modèles typés.
@@ -0,0 +1,12 @@
1
+ import security from "eslint-plugin-security";
2
+
3
+ export default [
4
+ {
5
+ plugins: {
6
+ security
7
+ },
8
+ rules: {
9
+ ...security.configs.recommended.rules
10
+ }
11
+ }
12
+ ];
package/index.d.ts CHANGED
@@ -95,10 +95,10 @@ export class Model {
95
95
  schema: Schema;
96
96
  constructor(name: string, schema: Schema);
97
97
  /**
98
- * Crée toutes les tables dans l'ordre correct en fonction des foreign keys.
98
+ * Creates all tables in the correct order based on foreign keys.
99
99
  * @returns {Promise<void>}
100
100
  */
101
- static syncAllTables({ dangerousSync = false } = {}): Promise<void>;
101
+ static syncAllTables(): Promise<void>;
102
102
  /**
103
103
  * Saves data to the database table.
104
104
  * @param {Object} data The data to insert into the table.
@@ -107,50 +107,20 @@ export class Model {
107
107
  */
108
108
  save(data: Record<string, any>): Promise<any>;
109
109
  /**
110
- * Récupère plusieurs entrées de la table.
111
- * @param {Object} [options] - Options de requête (attributs, where, order, limit).
112
- * @param {string[]} [options.attributes] - Champs à retourner.
113
- * @param {Object} [options.where] - Filtres (clé/valeur).
114
- * @param {Array} [options.order] - Ex: [['points', 'DESC']]
115
- * @param {number} [options.limit] - Limite de résultats.
110
+ * Retrieves multiple rows from the table.
111
+ * @param {Object} [options] - Query options (attributes, where, order, limit).
112
+ * @param {string[]} [options.select] - Fields to return.
113
+ * @param {Object} [options.where] - Filters (key/value).
114
+ * @param {Array} [options.order] - Example: [['points', 'DESC']]
115
+ * @param {number} [options.limit] - Result limit.
116
116
  * @returns {Promise<Array<Object>>}
117
117
  */
118
- findAll(options?: {
119
- attributes?: string[];
118
+ static find(options?: {
119
+ select?: string[];
120
120
  where?: Record<string, any>;
121
121
  order?: [string, string][];
122
122
  limit?: number;
123
123
  }): Promise<any[]>;
124
- /**
125
- * Finds a unique entry in the database table based on the filter provided.
126
- * @param {Object} filter An object containing the key-value pairs to use to generate the search condition.
127
- * @param {string[]} [fields=["*"]] An array of field names to return in the result.
128
- * @returns {Promise<ModelInstance|number>} A promise that resolves to a ModelInstance if an entry is found, otherwise 0.
129
- */
130
- findOne(filter: Record<string, any>, fields?: string[]): Promise<ModelInstance | number>;
131
- /**
132
- * Finds a record in the database based on the provided filter.
133
- *
134
- * @async
135
- * @param {Object} filter - The filter criteria for the query. Should be an object where keys are column names and values are the values to filter by.
136
- * @param {Array<string>} [fields=["*"]] - The fields to select in the query. Defaults to selecting all fields.
137
- * @returns {Promise<ModelInstance|number>} - A promise that resolves to a `ModelInstance` if a record is found, or `0` if no records match the filter.
138
- *
139
- * @example
140
- * // Example usage:
141
- * const filter = { id: 1 };
142
- * const fields = ["id", "name"];
143
- * MyTable.find(filter, fields).then((result) => {
144
- * if (result === 0) {
145
- * console.log("No records found.");
146
- * } else {
147
- * console.log("Record found:", result);
148
- * }
149
- * }).catch((err) => {
150
- * console.error("Error:", err);
151
- * });
152
- */
153
- find(filter: Record<string, any>, fields?: string[]): Promise<ModelInstance | number>;
154
124
  /**
155
125
  *
156
126
  * @param {Object} filter The filter criteria for the query. Should be an object where keys are column names and values are the values to filter by.
@@ -165,14 +135,14 @@ export class Model {
165
135
  */
166
136
  customRequest(custom: string): Promise<any>;
167
137
  /**
168
- * Supprime une entrée de la table SQL correspondant au filtre fourni.
138
+ * Deletes a record from the SQL table corresponding to the provided filter.
169
139
  *
170
140
  * @async
171
141
  * @function delete
172
- * @param {Object} filter - Un objet représentant les conditions de filtre pour la suppression.
173
- * @returns {Promise<number>} Une promesse qui se résout à 0 si aucune ligne n'a été supprimée,
174
- * ou à une instance de ModelInstance représentant la ligne supprimée.
175
- * @throws {Error} Lance une erreur si la requête SQL échoue.
142
+ * @param {Object} filter - An object representing the filter conditions for the deletion.
143
+ * @returns {Promise<number>} A promise that resolves to 0 if no rows were deleted,
144
+ * or an instance of ModelInstance representing the deleted row.
145
+ * @throws {Error} Throws an error if the SQL query fails.
176
146
  */
177
147
  delete(filter: Record<string, any>): Promise<number | ModelInstance>;
178
148
  /**
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@mlagie/sql-connector",
3
- "version": "1.4.9",
3
+ "version": "2.0.0",
4
4
  "description": "Le module sql-connector permet de gérer les connexions à une base de données MySQL, de définir des schémas de tables, et d'interagir avec les données de manière simple et efficace.",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
7
+ "security": "npx eslint . --max-warnings 0"
8
8
  },
9
9
  "repository": {
10
10
  "type": "git",
@@ -37,6 +37,10 @@
37
37
  "dependencies": {
38
38
  "@mlagie/logger": "1.0.2",
39
39
  "glob": "^13.0.6",
40
- "mysql2": "3.22.4"
40
+ "mysql2": "3.22.5"
41
+ },
42
+ "devDependencies": {
43
+ "eslint": "^10.6.0",
44
+ "eslint-plugin-security": "^4.0.1"
41
45
  }
42
46
  }
@@ -0,0 +1,127 @@
1
+ # **Release v1.5 — sql-connector**
2
+
3
+ ## Overview
4
+
5
+ This release introduces a major improvement to the query system in sql-connector, focusing on flexibility, performance, and developer experience.
6
+
7
+ The new version simplifies query building, adds support for advanced SQL features (such as aggregation and date formatting), and improves consistency across model operations.
8
+
9
+ ---
10
+
11
+ ## New Features
12
+
13
+ ### Enhanced Query Builder (findAll)
14
+
15
+ - findAll() now supports advanced SQL features through a clean and extensible configuration object.
16
+ - Developers can build complex queries without writing raw SQL.
17
+
18
+ Supported features:
19
+
20
+ - SUM, DATE_FORMAT, and custom field transformations
21
+ - GROUP BY, ORDER BY, HAVING, and LIMIT
22
+ - Multiple aggregations in a single query
23
+
24
+ Example:
25
+
26
+ ```js
27
+ Model.findAll({
28
+ select: [
29
+ { dateFormat: ['date_day', '%Y-%m'], as: 'period' },
30
+ { sum: 'error' },
31
+ { sum: 'reload' },
32
+ ],
33
+ groupBy: ['period'],
34
+ orderBy: [{ field: 'period', direction: 'ASC' }]
35
+ });
36
+ ```
37
+
38
+ ---
39
+
40
+ ### Dynamic Field Builder
41
+
42
+ - Query fields are now processed individually through a modular builder.
43
+ - Enables combining multiple transformations (e.g., multiple SUM, DATE_FORMAT) without hardcoding specific cases.
44
+ - Improves extensibility for future SQL functions (AVG, COUNT, etc.).
45
+
46
+ ---
47
+
48
+ ### Simplified Query Construction
49
+
50
+ - Query generation now follows a fixed SQL order (WHERE → GROUP BY → HAVING → ORDER BY → LIMIT) without unnecessary sorting.
51
+ - Improves performance and avoids overhead from dynamic reordering.
52
+ - Keeps the implementation simple and predictable.
53
+
54
+ ---
55
+
56
+ ### Improved Aggregation Support
57
+
58
+ - Designed for analytics use cases:
59
+ - Time-based grouping (day, month, year)
60
+ - Multi-metric aggregation
61
+ - Clean integration with frontend dashboards
62
+
63
+ ---
64
+
65
+ ### Better Developer Experience
66
+
67
+ - No need to write raw SQL for common queries
68
+ - Clear and readable query configuration
69
+ - Consistent API across simple and advanced queries
70
+
71
+ ---
72
+
73
+ ## Improvements
74
+
75
+ ### customRequest function
76
+
77
+ - customRequest provides all the information instead of taking the first element of the request.
78
+
79
+ ### Model Usage
80
+
81
+ - findAll() is now instance-based instead of static for better flexibility and dependency injection.
82
+ - Enables multiple database connections and improved testability.
83
+
84
+ ---
85
+
86
+ ### Performance Optimization
87
+
88
+ - Removed unnecessary iteration and sorting logic in query building.
89
+ - Query generation now runs in constant time structure (no scaling overhead with new features).
90
+
91
+ ---
92
+
93
+ ### Code Maintainability
94
+
95
+ - Cleaner separation between:
96
+ - field building
97
+ - query parts
98
+ - execution
99
+
100
+ - Easier to extend without modifying core logic.
101
+
102
+ ## Migration from v1.4.x
103
+
104
+ ### Main changes
105
+
106
+ 1. Switch to instance-based model usage
107
+ 2. Update findAll calls to use the new select format
108
+ 3. Adapt queries using aggregation to the new field builder system
109
+
110
+ ### Recommendation
111
+
112
+ - Replace raw SQL queries with the new findAll configuration when possible
113
+ - Review existing analytics queries to leverage built-in aggregation support
114
+
115
+ ## Documentation
116
+
117
+ See the updated documentation in:
118
+
119
+ - [README.md](../README.md)
120
+
121
+ ## Useful Links
122
+
123
+ - GitHub Repository: <https://github.com/lagie-marin/sql-connector>
124
+
125
+ - npm Package: <https://www.npmjs.com/package/@mlagie/sql-connector>
126
+
127
+ - Issues: <https://github.com/lagie-marin/sql-connector/issues>
@@ -0,0 +1,32 @@
1
+ # **Release v2.0.0 — Security Hardening & Prototype Pollution Prevention**
2
+
3
+ This release focuses heavily on `security improvements` across the ORM's core model management and data access layers. We have successfully mitigated potential security vulnerabilities regarding dynamic property access and file path operations, satisfying `eslint-plugin-security` analysis.
4
+
5
+ ## **Key Changes & Security Fixes**
6
+
7
+ ### **1. Prototype Pollution & Object Injection Prevention**
8
+
9
+ - **Problem**: Using dynamic bracket notations like obj[key] where key originates from user inputs or database schemas exposed the application to **Object Injection** and **Prototype Pollution** (allowing attackers to alter critical global properties via keys like `__proto__` or `constructor`).
10
+
11
+ - **Fix**: Introduced a centralized `safe.js` security utility leveraging `Reflect.get()` and `Reflect.set()` coupled with a strict property blacklist (`__proto__`, `constructor`, `prototype`).
12
+ - Migrated all dynamic model lookups and topological sorting dictionaries in `Model.js` to safe wrappers.
13
+ - Secured dynamic getters and setters mapped to data columns in `ModelInstance.js`.
14
+
15
+ ### **2. Path Traversal & Safe Database Backups**
16
+
17
+ - **Problem**: Dynamically naming automated backup files (**.sql**) based on database table names without validation triggered `detect-non-literal-fs-filename` warnings, opening up potential `Path Traversal` vector concerns.
18
+
19
+ - **Fix**: Implemented string sanitization via regex (`/[^a-zA-Z0-9_]/g`) on table-driven variables prior to passing arguments to standard `fs` sync methods (`writeFileSync`, `readFileSync`, `unlinkSync`, `renameSync`).
20
+ - Fully resolved all local `fs` filename security alerts.
21
+
22
+ ### **3. General Code Refactoring**
23
+
24
+ - Replaced native object literals `{}` with prototype-less structures `(Object.create(null))` for configuration mappings and dependency graph resolution arrays to prevent unexpected inheritance bugs.
25
+
26
+ ## **Component Impact**
27
+
28
+ | File | Changes Made | Warning Cleared |
29
+ |-------------------------------|-------------------------------------------------------------------|-------------------------------------------------------------|
30
+ | `src/utils/security/safe.js` | Created utility with `Reflect` API + validation blacklist | None (Fully clean) |
31
+ | `src/models/Model.js` | Patched `syncAllTables`, topological sort, and `fs` operations | `detect-object-injection`, `detect-non-literal-fs-filename` |
32
+ | `src/models/ModelInstance.js` | Secured active schema columns maps inside constructor proxies | `detect-object-injection` |