fiberx-backend-toolkit 0.1.21 → 1.0.1
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 +207 -139
- package/dist/code_templates/sequelize_code_template.d.ts +1 -1
- package/dist/code_templates/sequelize_code_template.js +127 -74
- package/dist/config/constants.d.ts +1 -0
- package/dist/config/constants.js +82 -15
- package/dist/database/connectors/sequelize_connector.d.ts +2 -0
- package/dist/database/connectors/sequelize_connector.js +43 -21
- package/dist/database/main.d.ts +3 -2
- package/dist/database/main.js +4 -2
- package/dist/database/schema/schema_diff_util.d.ts +0 -1
- package/dist/database/schema/schema_diff_util.js +7 -15
- package/dist/database/scripts/create_schema_script.js +6 -3
- package/dist/database/scripts/make_migrations_script.js +17 -10
- package/dist/database/scripts/migration_runner_script.d.ts +3 -1
- package/dist/database/scripts/migration_runner_script.js +58 -23
- package/dist/database/scripts/seeder_runner_script.d.ts +3 -1
- package/dist/database/scripts/seeder_runner_script.js +49 -17
- package/dist/database/scripts/sequelize_model_generator_script.d.ts +2 -2
- package/dist/database/scripts/sequelize_model_generator_script.js +11 -5
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/mailer/main.d.ts +1 -1
- package/dist/mailer/processors/email_delivery_processor.js +45 -13
- package/dist/mailer/processors/email_enqueue_processor.js +23 -7
- package/dist/mailer/utils/mailer_data_loader_util.d.ts +4 -4
- package/dist/mailer/utils/mailer_data_loader_util.js +5 -5
- package/dist/middle_ware/authentication_middle_ware.d.ts +3 -3
- package/dist/middle_ware/authentication_middle_ware.js +27 -25
- package/dist/middle_ware/cookie_manager_middle_ware.js +1 -1
- package/dist/middle_ware/main.d.ts +3 -2
- package/dist/middle_ware/main.js +4 -2
- package/dist/middle_ware/rate_limiter_middle_ware.js +0 -1
- package/dist/middle_ware/request_logger_middle_ware.js +2 -1
- package/dist/middle_ware/response_formatter_middle_ware.js +5 -4
- package/dist/middle_ware/secure_headers_middle_ware.js +2 -1
- package/dist/rbac/rbac_loader_util.js +2 -2
- package/dist/storage/drivers/gcs_storage_driver.js +5 -5
- package/dist/storage/drivers/local_storage_driver.js +2 -2
- package/dist/storage/main.d.ts +1 -1
- package/dist/storage/processors/file_upload_processor.js +4 -4
- package/dist/storage/utils/storage_driver_util.d.ts +1 -1
- package/dist/storage/utils/storage_driver_util.js +12 -10
- package/dist/types/express_decelaration.d.ts +1 -1
- package/dist/types/express_decelaration.js +0 -1
- package/dist/types/middle_ware_type.d.ts +14 -12
- package/dist/types/middle_ware_type.js +0 -2
- package/dist/types/schema_type.js +0 -1
- package/dist/types/util_type.js +0 -1
- package/dist/utils/content_manager_util.js +11 -9
- package/dist/utils/crypto_key_util.js +9 -10
- package/dist/utils/encryptor_decryptor_util.js +19 -9
- package/dist/utils/env_manager_util.d.ts +1 -0
- package/dist/utils/env_manager_util.js +10 -2
- package/dist/utils/fs_actions_util.js +1 -1
- package/dist/utils/input_transformer_util.js +11 -25
- package/dist/utils/input_validator_util.d.ts +1 -1
- package/dist/utils/input_validator_util.js +75 -27
- package/dist/utils/logger_util.d.ts +2 -2
- package/dist/utils/logger_util.js +23 -9
- package/dist/utils/main.d.ts +1 -1
- package/dist/utils/safe_execute_util.js +21 -11
- package/dist/utils/sql_formatter_util.js +1 -5
- package/dist/utils/totp_service_util.js +3 -7
- package/dist/utils/uuid_gen_util.js +6 -2
- package/dist/validators/file_validator_util.js +2 -2
- package/dist/validators/query_validator_util.js +3 -3
- package/package.json +68 -2
|
@@ -6,7 +6,7 @@ const indentBlock = (code, level) => {
|
|
|
6
6
|
const indentation = INDENT.repeat(level);
|
|
7
7
|
return code
|
|
8
8
|
.split("\n")
|
|
9
|
-
.map(line => line.trim().length ? indentation + line : line)
|
|
9
|
+
.map((line) => (line.trim().length ? indentation + line : line))
|
|
10
10
|
.join("\n");
|
|
11
11
|
};
|
|
12
12
|
const serializeSequelizeDataType = (type) => {
|
|
@@ -54,8 +54,8 @@ const serializeIndexDefinition = (index) => {
|
|
|
54
54
|
delete clone.fields;
|
|
55
55
|
delete clone.comment;
|
|
56
56
|
const entries = Object.entries(clone)
|
|
57
|
-
.map(([key, value]) => `${key}: ${JSON.stringify(value)}
|
|
58
|
-
.join("
|
|
57
|
+
.map(([key, value]) => `${key}: ${JSON.stringify(value)},`)
|
|
58
|
+
.join("\n");
|
|
59
59
|
return entries;
|
|
60
60
|
};
|
|
61
61
|
const serializeSequelizeColumnsObject = (columns) => {
|
|
@@ -71,13 +71,15 @@ ${indentBlock("}", 3)}
|
|
|
71
71
|
`;
|
|
72
72
|
};
|
|
73
73
|
const serializeSequelizeIndexesArray = (indexes) => {
|
|
74
|
-
return indexes
|
|
74
|
+
return indexes
|
|
75
|
+
.map((index) => {
|
|
75
76
|
return `{
|
|
76
77
|
name: "${index.name}",
|
|
77
78
|
fields: ${JSON.stringify(index.fields)},
|
|
78
79
|
${serializeIndexDefinition(index).replace(/^{|}$/g, "")}
|
|
79
80
|
}`;
|
|
80
|
-
})
|
|
81
|
+
})
|
|
82
|
+
.join(",\n ");
|
|
81
83
|
};
|
|
82
84
|
const SEQUELIZE_SCHEMA_CODE_TEMPLATE = (schema_name, table_name, model_name, migration_priority) => {
|
|
83
85
|
return `
|
|
@@ -138,25 +140,29 @@ class Create${schema_model_name}TableMigration {
|
|
|
138
140
|
|
|
139
141
|
constructor() {}
|
|
140
142
|
|
|
141
|
-
public async up(queryInterface: QueryInterface, Sequelize: Sequelize) {
|
|
143
|
+
public async up(queryInterface: QueryInterface, Sequelize: Sequelize, migration_options: any = {}) {
|
|
142
144
|
try {
|
|
143
145
|
const table_name = "${schema_table_name}";
|
|
144
146
|
|
|
145
147
|
await queryInterface.createTable(
|
|
146
148
|
table_name,
|
|
147
|
-
${indentBlock(rendered_columns, 1)}
|
|
149
|
+
${indentBlock(rendered_columns, 1)},
|
|
150
|
+
migration_options
|
|
148
151
|
);
|
|
149
152
|
|
|
150
|
-
${schema_definition.indexes
|
|
153
|
+
${schema_definition.indexes
|
|
154
|
+
?.map((index) => `
|
|
151
155
|
await queryInterface.addIndex(
|
|
152
156
|
table_name,
|
|
153
157
|
${JSON.stringify(index.fields)},
|
|
154
158
|
{
|
|
155
159
|
name: "${index.name}",
|
|
156
160
|
${indentBlock(serializeIndexDefinition(index), 1)}
|
|
161
|
+
...migration_options,
|
|
157
162
|
}
|
|
158
163
|
);
|
|
159
|
-
`)
|
|
164
|
+
`)
|
|
165
|
+
.join("")}
|
|
160
166
|
|
|
161
167
|
this.logger.success(\`✅ Table "\${table_name}" created successfully.\`);
|
|
162
168
|
}
|
|
@@ -166,9 +172,9 @@ class Create${schema_model_name}TableMigration {
|
|
|
166
172
|
}
|
|
167
173
|
}
|
|
168
174
|
|
|
169
|
-
public async down(queryInterface: QueryInterface, Sequelize: Sequelize) {
|
|
175
|
+
public async down(queryInterface: QueryInterface, Sequelize: Sequelize, migration_options: any = {}) {
|
|
170
176
|
try {
|
|
171
|
-
await queryInterface.dropTable("${schema_table_name}");
|
|
177
|
+
await queryInterface.dropTable("${schema_table_name}", migration_options);
|
|
172
178
|
this.logger.success(\`🗑️ Table "${schema_table_name}" dropped successfully.\`);
|
|
173
179
|
} catch (error: any) {
|
|
174
180
|
this.logger.error(\`🚫 Rollback failed: "\${error.message}"\`, { error });
|
|
@@ -192,66 +198,85 @@ class Update${model_name}TableMigration {
|
|
|
192
198
|
|
|
193
199
|
constructor() {}
|
|
194
200
|
|
|
195
|
-
public async up(queryInterface: QueryInterface, Sequelize: Sequelize) {
|
|
201
|
+
public async up(queryInterface: QueryInterface, Sequelize: Sequelize, migration_options: any = {}) {
|
|
196
202
|
try {
|
|
197
203
|
let table_name = "${table_name}";
|
|
198
204
|
|
|
199
|
-
${diff.table_renamed
|
|
205
|
+
${diff.table_renamed
|
|
206
|
+
? `
|
|
200
207
|
await queryInterface.renameTable(
|
|
201
208
|
"${diff.table_renamed.from}",
|
|
202
|
-
"${diff.table_renamed.to}"
|
|
209
|
+
"${diff.table_renamed.to}",
|
|
210
|
+
migration_options
|
|
203
211
|
);
|
|
204
212
|
table_name = "${diff.table_renamed.to}";
|
|
205
|
-
`
|
|
213
|
+
`
|
|
214
|
+
: ""}
|
|
206
215
|
|
|
207
216
|
// ----------- ADD COLUMNS -----------
|
|
208
|
-
${diff.columns.added
|
|
217
|
+
${diff.columns.added
|
|
218
|
+
.map((col) => `
|
|
209
219
|
await queryInterface.addColumn(
|
|
210
220
|
table_name,
|
|
211
221
|
"${col}",
|
|
212
|
-
${indentBlock(serializeSequelizeColumnDefinition(current_schema.columns[col]), 1)}
|
|
222
|
+
${indentBlock(serializeSequelizeColumnDefinition(current_schema.columns[col]), 1)},
|
|
223
|
+
migration_options
|
|
213
224
|
);
|
|
214
|
-
`)
|
|
225
|
+
`)
|
|
226
|
+
.join("")}
|
|
215
227
|
|
|
216
228
|
// ----------- MODIFY COLUMNS -----------
|
|
217
|
-
${diff.columns.modified
|
|
229
|
+
${diff.columns.modified
|
|
230
|
+
.map((col) => `
|
|
218
231
|
await queryInterface.changeColumn(
|
|
219
232
|
table_name,
|
|
220
233
|
"${col}",
|
|
221
|
-
${indentBlock(serializeSequelizeColumnDefinition(current_schema.columns[col]), 1)}
|
|
234
|
+
${indentBlock(serializeSequelizeColumnDefinition(current_schema.columns[col]), 1)},
|
|
235
|
+
migration_options
|
|
222
236
|
);
|
|
223
|
-
`)
|
|
237
|
+
`)
|
|
238
|
+
.join("")}
|
|
224
239
|
|
|
225
240
|
// ----------- REMOVE COLUMNS -----------
|
|
226
|
-
${diff.columns.removed
|
|
241
|
+
${diff.columns.removed
|
|
242
|
+
.map((col) => `
|
|
227
243
|
await queryInterface.removeColumn(
|
|
228
244
|
table_name,
|
|
229
|
-
"${col}"
|
|
245
|
+
"${col}",
|
|
246
|
+
migration_options
|
|
230
247
|
);
|
|
231
|
-
`)
|
|
248
|
+
`)
|
|
249
|
+
.join("")}
|
|
232
250
|
|
|
233
251
|
// ----------- ADD INDEXES -----------
|
|
234
|
-
${diff.indexes.added
|
|
252
|
+
${diff.indexes.added
|
|
253
|
+
.map((name) => {
|
|
235
254
|
const curr_indxs = current_schema?.indexes || [];
|
|
236
|
-
const idx = curr_indxs.find(i => i.name === name);
|
|
237
|
-
return idx
|
|
255
|
+
const idx = curr_indxs.find((i) => i.name === name);
|
|
256
|
+
return idx
|
|
257
|
+
? `
|
|
238
258
|
await queryInterface.addIndex(
|
|
239
259
|
table_name,
|
|
240
260
|
${JSON.stringify(idx.fields)},
|
|
241
261
|
{
|
|
242
262
|
name: "${idx.name}",
|
|
243
263
|
${indentBlock(serializeIndexDefinition(idx).replace(/^{|}$/g, ""), 1)}
|
|
264
|
+
...migration_options,
|
|
244
265
|
}
|
|
245
266
|
);
|
|
246
|
-
`
|
|
247
|
-
|
|
267
|
+
`
|
|
268
|
+
: "";
|
|
269
|
+
})
|
|
270
|
+
.join("")}
|
|
248
271
|
|
|
249
272
|
// ----------- MODIFY INDEXES -----------
|
|
250
|
-
${diff.indexes.modified
|
|
273
|
+
${diff.indexes.modified
|
|
274
|
+
.map((name) => {
|
|
251
275
|
const curr_indxs = current_schema?.indexes || [];
|
|
252
|
-
const idx = curr_indxs.find(i => i.name === name);
|
|
253
|
-
return idx
|
|
254
|
-
|
|
276
|
+
const idx = curr_indxs.find((i) => i.name === name);
|
|
277
|
+
return idx
|
|
278
|
+
? `
|
|
279
|
+
await queryInterface.removeIndex(table_name, "${name}", migration_options);
|
|
255
280
|
|
|
256
281
|
await queryInterface.addIndex(
|
|
257
282
|
table_name,
|
|
@@ -259,15 +284,20 @@ class Update${model_name}TableMigration {
|
|
|
259
284
|
{
|
|
260
285
|
name: "${idx.name}",
|
|
261
286
|
${indentBlock(serializeIndexDefinition(idx).replace(/^{|}$/g, ""), 1)}
|
|
287
|
+
...migration_options,
|
|
262
288
|
}
|
|
263
289
|
);
|
|
264
|
-
`
|
|
265
|
-
|
|
290
|
+
`
|
|
291
|
+
: "";
|
|
292
|
+
})
|
|
293
|
+
.join("")}
|
|
266
294
|
|
|
267
295
|
// ----------- REMOVE INDEXES -----------
|
|
268
|
-
${diff.indexes.removed
|
|
269
|
-
|
|
270
|
-
|
|
296
|
+
${diff.indexes.removed
|
|
297
|
+
.map((name) => `
|
|
298
|
+
await queryInterface.removeIndex(table_name, "${name}", migration_options);
|
|
299
|
+
`)
|
|
300
|
+
.join("")}
|
|
271
301
|
|
|
272
302
|
this.logger.success(\`✅ Table "\${table_name}" updated successfully.\`);
|
|
273
303
|
}
|
|
@@ -277,20 +307,24 @@ class Update${model_name}TableMigration {
|
|
|
277
307
|
}
|
|
278
308
|
}
|
|
279
309
|
|
|
280
|
-
public async down(queryInterface: QueryInterface, Sequelize: Sequelize) {
|
|
310
|
+
public async down(queryInterface: QueryInterface, Sequelize: Sequelize, migration_options: any = {}) {
|
|
281
311
|
try {
|
|
282
312
|
let table_name = "${table_name}";
|
|
283
313
|
|
|
284
314
|
// ----------- REVERT INDEXES -----------
|
|
285
|
-
${diff.indexes.added
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
315
|
+
${diff.indexes.added
|
|
316
|
+
.map((name) => `
|
|
317
|
+
await queryInterface.removeIndex(table_name, "${name}", migration_options);
|
|
318
|
+
`)
|
|
319
|
+
.join("")}
|
|
320
|
+
|
|
321
|
+
${diff.indexes.modified
|
|
322
|
+
.map((name) => {
|
|
290
323
|
const prev_indxs = previous_schema?.indexes || [];
|
|
291
|
-
const idx = prev_indxs.find(i => i.name === name);
|
|
292
|
-
return idx
|
|
293
|
-
|
|
324
|
+
const idx = prev_indxs.find((i) => i.name === name);
|
|
325
|
+
return idx
|
|
326
|
+
? `
|
|
327
|
+
await queryInterface.removeIndex(table_name, "${name}", migration_options);
|
|
294
328
|
|
|
295
329
|
await queryInterface.addIndex(
|
|
296
330
|
table_name,
|
|
@@ -298,53 +332,72 @@ class Update${model_name}TableMigration {
|
|
|
298
332
|
{
|
|
299
333
|
name: "${idx.name}",
|
|
300
334
|
${indentBlock(serializeIndexDefinition(idx).replace(/^{|}$/g, ""), 1)}
|
|
335
|
+
...migration_options,
|
|
301
336
|
}
|
|
302
337
|
);
|
|
303
|
-
`
|
|
304
|
-
|
|
338
|
+
`
|
|
339
|
+
: "";
|
|
340
|
+
})
|
|
341
|
+
.join("")}
|
|
305
342
|
|
|
306
|
-
${diff.indexes.removed
|
|
343
|
+
${diff.indexes.removed
|
|
344
|
+
.map((name) => {
|
|
307
345
|
const prev_indxs = previous_schema?.indexes || [];
|
|
308
|
-
const idx = prev_indxs.find(i => i.name === name);
|
|
309
|
-
return idx
|
|
346
|
+
const idx = prev_indxs.find((i) => i.name === name);
|
|
347
|
+
return idx
|
|
348
|
+
? `
|
|
310
349
|
await queryInterface.addIndex(
|
|
311
350
|
table_name,
|
|
312
351
|
${JSON.stringify(idx.fields)},
|
|
313
352
|
{
|
|
314
353
|
name: "${idx.name}",
|
|
315
354
|
${indentBlock(serializeIndexDefinition(idx).replace(/^{|}$/g, ""), 1)}
|
|
355
|
+
...migration_options,
|
|
316
356
|
}
|
|
317
357
|
);
|
|
318
|
-
`
|
|
319
|
-
|
|
358
|
+
`
|
|
359
|
+
: "";
|
|
360
|
+
})
|
|
361
|
+
.join("")}
|
|
320
362
|
|
|
321
363
|
// ----------- REVERT COLUMNS -----------
|
|
322
|
-
${diff.columns.modified
|
|
364
|
+
${diff.columns.modified
|
|
365
|
+
.map((col) => `
|
|
323
366
|
await queryInterface.changeColumn(
|
|
324
367
|
table_name,
|
|
325
368
|
"${col}",
|
|
326
|
-
${indentBlock(serializeSequelizeColumnDefinition(previous_schema.columns[col]), 1)}
|
|
369
|
+
${indentBlock(serializeSequelizeColumnDefinition(previous_schema.columns[col]), 1)},
|
|
370
|
+
migration_options
|
|
327
371
|
);
|
|
328
|
-
`)
|
|
372
|
+
`)
|
|
373
|
+
.join("")}
|
|
329
374
|
|
|
330
|
-
${diff.columns.added
|
|
331
|
-
|
|
332
|
-
|
|
375
|
+
${diff.columns.added
|
|
376
|
+
.map((col) => `
|
|
377
|
+
await queryInterface.removeColumn(table_name, "${col}", migration_options);
|
|
378
|
+
`)
|
|
379
|
+
.join("")}
|
|
333
380
|
|
|
334
|
-
${diff.columns.removed
|
|
381
|
+
${diff.columns.removed
|
|
382
|
+
.map((col) => `
|
|
335
383
|
await queryInterface.addColumn(
|
|
336
384
|
table_name,
|
|
337
385
|
"${col}",
|
|
338
|
-
${indentBlock(serializeSequelizeColumnDefinition(previous_schema.columns[col]), 1)}
|
|
386
|
+
${indentBlock(serializeSequelizeColumnDefinition(previous_schema.columns[col]), 1)},
|
|
387
|
+
migration_options
|
|
339
388
|
);
|
|
340
|
-
`)
|
|
389
|
+
`)
|
|
390
|
+
.join("")}
|
|
341
391
|
|
|
342
|
-
${diff.table_renamed
|
|
392
|
+
${diff.table_renamed
|
|
393
|
+
? `
|
|
343
394
|
await queryInterface.renameTable(
|
|
344
395
|
"${diff.table_renamed.to}",
|
|
345
|
-
"${diff.table_renamed.from}"
|
|
396
|
+
"${diff.table_renamed.from}",
|
|
397
|
+
migration_options
|
|
346
398
|
);
|
|
347
|
-
`
|
|
399
|
+
`
|
|
400
|
+
: ""}
|
|
348
401
|
|
|
349
402
|
this.logger.success(\`🗑️ Rollback completed successfully.\`);
|
|
350
403
|
}
|
|
@@ -369,29 +422,29 @@ class ${class_name}Seeder {
|
|
|
369
422
|
/**
|
|
370
423
|
* Seed method
|
|
371
424
|
*/
|
|
372
|
-
public async up(queryInterface: QueryInterface): Promise<void> {
|
|
425
|
+
public async up(queryInterface: QueryInterface, Sequelize?: unknown, seeder_options: any = {}): Promise<void> {
|
|
373
426
|
const seed_data = this.getSeedData();
|
|
374
427
|
|
|
375
428
|
if (!seed_data || seed_data.length === 0) {
|
|
376
429
|
throw new Error("❌ Seeder data for '${table_name.toLowerCase()}' is empty. Aborting bulk insert.");
|
|
377
430
|
}
|
|
378
431
|
|
|
379
|
-
await queryInterface.bulkInsert('${table_name.toLowerCase()}', seed_data);
|
|
432
|
+
await queryInterface.bulkInsert('${table_name.toLowerCase()}', seed_data, seeder_options);
|
|
380
433
|
}
|
|
381
434
|
|
|
382
435
|
/**
|
|
383
436
|
* Undo seed method
|
|
384
437
|
*/
|
|
385
|
-
public async down(queryInterface: QueryInterface): Promise<void> {
|
|
438
|
+
public async down(queryInterface: QueryInterface, Sequelize?: unknown, seeder_options: any = {}): Promise<void> {
|
|
386
439
|
const seed_data = this.getSeedData();
|
|
387
440
|
|
|
388
441
|
if (!seed_data || seed_data.length === 0) {
|
|
389
|
-
throw new Error("❌ Seeder data for ${table_name.toLowerCase()}' is empty. Nothing to delete.");
|
|
442
|
+
throw new Error("❌ Seeder data for '${table_name.toLowerCase()}' is empty. Nothing to delete.");
|
|
390
443
|
}
|
|
391
444
|
|
|
392
445
|
const ids = seed_data.map(row => row.id);
|
|
393
446
|
|
|
394
|
-
await queryInterface.bulkDelete('${table_name.toLowerCase()}', { id: ids });
|
|
447
|
+
await queryInterface.bulkDelete('${table_name.toLowerCase()}', { id: ids }, seeder_options);
|
|
395
448
|
}
|
|
396
449
|
|
|
397
450
|
/**
|
|
@@ -409,7 +462,7 @@ export default ${class_name}Seeder;
|
|
|
409
462
|
exports.SEQUELIZE_SEEDER_TEMPLATE = SEQUELIZE_SEEDER_TEMPLATE;
|
|
410
463
|
const SEQUELIZE_MODEL_CODE_TEMPLATE = (schema_model_name, schema_file_name, schema_columns) => {
|
|
411
464
|
const attributes = Object.keys(schema_columns)
|
|
412
|
-
.map(col => ` declare ${col}: any;`)
|
|
465
|
+
.map((col) => ` declare ${col}: any;`)
|
|
413
466
|
.join("\n");
|
|
414
467
|
return `
|
|
415
468
|
import { Model, Sequelize } from "sequelize";
|
|
@@ -510,14 +563,14 @@ for (const register of associationMethods) {
|
|
|
510
563
|
// -------------------------
|
|
511
564
|
// Create named initialized exports
|
|
512
565
|
// -------------------------
|
|
513
|
-
${model_names.map(m => `const ${m}Model: typeof ${m} = initializedModels["${m}"];`).join("\n")}
|
|
566
|
+
${model_names.map((m) => `const ${m}Model: typeof ${m} = initializedModels["${m}"];`).join("\n")}
|
|
514
567
|
|
|
515
568
|
// -------------------------
|
|
516
569
|
// Export raw + initialized
|
|
517
570
|
// -------------------------
|
|
518
571
|
export {
|
|
519
572
|
${export_raw},
|
|
520
|
-
${model_names.map(m => ` ${m}Model`).join(",\n")}
|
|
573
|
+
${model_names.map((m) => ` ${m}Model`).join(",\n")}
|
|
521
574
|
};
|
|
522
575
|
`;
|
|
523
576
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare const BASE_DIR: string;
|
|
2
2
|
export declare const LOG_DIR: string;
|
|
3
3
|
export declare const ENV_VAR_DIR: string;
|
|
4
|
+
export declare const LEGACY_ENV_VAR_DIR: string;
|
|
4
5
|
export declare const SCHEMAS_DIR: string;
|
|
5
6
|
export declare const SCHEMA_SNAPSHOTS_DIR: string;
|
|
6
7
|
export declare const MODELS_DIR: string;
|
package/dist/config/constants.js
CHANGED
|
@@ -3,11 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.FILE_UPLOAD_ALLOWED_MIME_TYPES = exports.FILE_UPLOAD_ENV_KEYS = exports.FILE_UPLOAD_LIMITS = exports.DEFAULT_CONTENT_CACHE_TTL = exports.DEFAULT_CONTENT_LANG = exports.DEFAULT_CONTENT_URL = exports.CONTENT_LANG_KEY = exports.CONTENT_URL_KEY = exports.CONTENT_CACHE_TTL_KEY = exports.EMAIL_ENQUEUE_UTIL_FILE_NAME = exports.EMAIL_ENQUEUE_TYPES_FILE_NAME = exports.DEFAULT_MAILER_CACHE_TTL = exports.DEFAULT_MAILER_CACHE_KEY = exports.DEFAULT_RBAC_CACHE_TTL = exports.DEFAULT_RBAC_CACHE_KEY = exports.DEFAULT_TOTP_WINDOW = exports.DEFAULT_TOTP_DIGITS = exports.DEFAULT_TOTP_STEP = exports.ALPHABET_CORPUS = exports.CHARACTER_CORPUS = exports.REQUEST_RATE_LIMITTER_OPTIONS = exports.CORS_MAX_AGE_IN_MICRO_SECONDS = exports.CORS_MAX_AGE_IN_SECONDS = exports.CORS_ALLOWED_HEADERS = exports.HEADERS_KEY_NAME = exports.CORS_ALLOWED_METHODS = exports.DEVICE_ID_HEADERS_NAME = exports.DEVICE_ID_COOKIE_NAME = exports.DEVICE_ID_COOKIE_MAX_AGE = exports.REQUEST_ID_HEADERS_NAME = exports.REQUEST_ID_COOKIE_NAME = exports.REQUEST_ID_COOKIE_MAX_AGE = exports.SEQUELIZE_SEEDER_META_TABLE_NAME = exports.SEQUELIZE_META_TABLE_NAME = exports.EMAIL_PREVIEW_DIR = exports.EMAIL_ENQUEUE_DIR = exports.SEEDERS_DIR = exports.MIGRATIONS_DIR = exports.MODELS_DIR = exports.SCHEMA_SNAPSHOTS_DIR = exports.SCHEMAS_DIR = exports.ENV_VAR_DIR = exports.LOG_DIR = exports.BASE_DIR = void 0;
|
|
6
|
+
exports.FILE_UPLOAD_ALLOWED_MIME_TYPES = exports.FILE_UPLOAD_ENV_KEYS = exports.FILE_UPLOAD_LIMITS = exports.DEFAULT_CONTENT_CACHE_TTL = exports.DEFAULT_CONTENT_LANG = exports.DEFAULT_CONTENT_URL = exports.CONTENT_LANG_KEY = exports.CONTENT_URL_KEY = exports.CONTENT_CACHE_TTL_KEY = exports.EMAIL_ENQUEUE_UTIL_FILE_NAME = exports.EMAIL_ENQUEUE_TYPES_FILE_NAME = exports.DEFAULT_MAILER_CACHE_TTL = exports.DEFAULT_MAILER_CACHE_KEY = exports.DEFAULT_RBAC_CACHE_TTL = exports.DEFAULT_RBAC_CACHE_KEY = exports.DEFAULT_TOTP_WINDOW = exports.DEFAULT_TOTP_DIGITS = exports.DEFAULT_TOTP_STEP = exports.ALPHABET_CORPUS = exports.CHARACTER_CORPUS = exports.REQUEST_RATE_LIMITTER_OPTIONS = exports.CORS_MAX_AGE_IN_MICRO_SECONDS = exports.CORS_MAX_AGE_IN_SECONDS = exports.CORS_ALLOWED_HEADERS = exports.HEADERS_KEY_NAME = exports.CORS_ALLOWED_METHODS = exports.DEVICE_ID_HEADERS_NAME = exports.DEVICE_ID_COOKIE_NAME = exports.DEVICE_ID_COOKIE_MAX_AGE = exports.REQUEST_ID_HEADERS_NAME = exports.REQUEST_ID_COOKIE_NAME = exports.REQUEST_ID_COOKIE_MAX_AGE = exports.SEQUELIZE_SEEDER_META_TABLE_NAME = exports.SEQUELIZE_META_TABLE_NAME = exports.EMAIL_PREVIEW_DIR = exports.EMAIL_ENQUEUE_DIR = exports.SEEDERS_DIR = exports.MIGRATIONS_DIR = exports.MODELS_DIR = exports.SCHEMA_SNAPSHOTS_DIR = exports.SCHEMAS_DIR = exports.LEGACY_ENV_VAR_DIR = exports.ENV_VAR_DIR = exports.LOG_DIR = exports.BASE_DIR = void 0;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
exports.BASE_DIR = process.cwd();
|
|
9
9
|
exports.LOG_DIR = path_1.default.join(exports.BASE_DIR, "logs");
|
|
10
|
-
exports.ENV_VAR_DIR = path_1.default.join(exports.BASE_DIR, "
|
|
10
|
+
exports.ENV_VAR_DIR = path_1.default.join(exports.BASE_DIR, "environment_variables");
|
|
11
|
+
exports.LEGACY_ENV_VAR_DIR = path_1.default.join(exports.BASE_DIR, "environment_variables");
|
|
11
12
|
exports.SCHEMAS_DIR = path_1.default.join(exports.BASE_DIR, "src/database/schemas");
|
|
12
13
|
exports.SCHEMA_SNAPSHOTS_DIR = path_1.default.join(exports.BASE_DIR, "src/database/schema_snapshots");
|
|
13
14
|
exports.MODELS_DIR = path_1.default.join(exports.BASE_DIR, "src/database/models");
|
|
@@ -17,10 +18,10 @@ exports.EMAIL_ENQUEUE_DIR = path_1.default.join(exports.BASE_DIR, "src/");
|
|
|
17
18
|
exports.EMAIL_PREVIEW_DIR = path_1.default.join(exports.BASE_DIR, "local_media/email/email_preview");
|
|
18
19
|
exports.SEQUELIZE_META_TABLE_NAME = "sequelize_database_tables_meta";
|
|
19
20
|
exports.SEQUELIZE_SEEDER_META_TABLE_NAME = "sequelize_database_table_seeder_meta";
|
|
20
|
-
exports.REQUEST_ID_COOKIE_MAX_AGE =
|
|
21
|
+
exports.REQUEST_ID_COOKIE_MAX_AGE = 1000 * 60 * 60 * 24 * 30; // 7 days
|
|
21
22
|
exports.REQUEST_ID_COOKIE_NAME = "request_id";
|
|
22
23
|
exports.REQUEST_ID_HEADERS_NAME = "X-Request-Id";
|
|
23
|
-
exports.DEVICE_ID_COOKIE_MAX_AGE =
|
|
24
|
+
exports.DEVICE_ID_COOKIE_MAX_AGE = 1000 * 60 * 60 * 24 * 180; // 180 days
|
|
24
25
|
exports.DEVICE_ID_COOKIE_NAME = "device_id";
|
|
25
26
|
exports.DEVICE_ID_HEADERS_NAME = "X-Device-Id";
|
|
26
27
|
// CORS constants
|
|
@@ -95,23 +96,89 @@ exports.CORS_ALLOWED_HEADERS = [
|
|
|
95
96
|
exports.HEADERS_KEY_NAME.access_control_allow_credentials,
|
|
96
97
|
exports.HEADERS_KEY_NAME.access_control_max_age,
|
|
97
98
|
];
|
|
98
|
-
exports.CORS_MAX_AGE_IN_SECONDS =
|
|
99
|
-
exports.CORS_MAX_AGE_IN_MICRO_SECONDS =
|
|
99
|
+
exports.CORS_MAX_AGE_IN_SECONDS = 600; // default: 10 min
|
|
100
|
+
exports.CORS_MAX_AGE_IN_MICRO_SECONDS = 1000 * 60 * 10; // 10 minutes
|
|
100
101
|
// Rate limitter
|
|
101
102
|
exports.REQUEST_RATE_LIMITTER_OPTIONS = {
|
|
102
|
-
window_ms:
|
|
103
|
+
window_ms: 60 * 1000, // 1 MINS
|
|
103
104
|
max_requests: 50,
|
|
104
|
-
message: "⏳ Too many requests from this IP, please try again later"
|
|
105
|
+
message: "⏳ Too many requests from this IP, please try again later",
|
|
105
106
|
};
|
|
106
|
-
exports.CHARACTER_CORPUS = [
|
|
107
|
+
exports.CHARACTER_CORPUS = [
|
|
108
|
+
"6",
|
|
109
|
+
";",
|
|
110
|
+
"s",
|
|
111
|
+
"[",
|
|
112
|
+
"w",
|
|
113
|
+
"*",
|
|
114
|
+
"n",
|
|
115
|
+
"K",
|
|
116
|
+
"h",
|
|
117
|
+
"U",
|
|
118
|
+
"#",
|
|
119
|
+
"P",
|
|
120
|
+
"T",
|
|
121
|
+
"&",
|
|
122
|
+
"M",
|
|
123
|
+
"2",
|
|
124
|
+
"}",
|
|
125
|
+
"x",
|
|
126
|
+
")",
|
|
127
|
+
"{",
|
|
128
|
+
"|",
|
|
129
|
+
"i",
|
|
130
|
+
"%",
|
|
131
|
+
"m",
|
|
132
|
+
":",
|
|
133
|
+
"E",
|
|
134
|
+
"q",
|
|
135
|
+
"?",
|
|
136
|
+
"0",
|
|
137
|
+
"@",
|
|
138
|
+
"1",
|
|
139
|
+
"v",
|
|
140
|
+
"A",
|
|
141
|
+
"W",
|
|
142
|
+
"<",
|
|
143
|
+
"y",
|
|
144
|
+
"Y",
|
|
145
|
+
"4",
|
|
146
|
+
"5",
|
|
147
|
+
".",
|
|
148
|
+
"e",
|
|
149
|
+
"G",
|
|
150
|
+
",",
|
|
151
|
+
"D",
|
|
152
|
+
"7",
|
|
153
|
+
"I",
|
|
154
|
+
"j",
|
|
155
|
+
">",
|
|
156
|
+
"g",
|
|
157
|
+
"t",
|
|
158
|
+
"k",
|
|
159
|
+
"c",
|
|
160
|
+
"V",
|
|
161
|
+
"9",
|
|
162
|
+
"J",
|
|
163
|
+
"L",
|
|
164
|
+
"u",
|
|
165
|
+
"H",
|
|
166
|
+
"b",
|
|
167
|
+
"Z",
|
|
168
|
+
"+",
|
|
169
|
+
'"',
|
|
170
|
+
"'",
|
|
171
|
+
"a",
|
|
172
|
+
"f",
|
|
173
|
+
];
|
|
107
174
|
exports.ALPHABET_CORPUS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
|
108
175
|
exports.DEFAULT_TOTP_STEP = 30;
|
|
109
176
|
exports.DEFAULT_TOTP_DIGITS = 6;
|
|
110
177
|
exports.DEFAULT_TOTP_WINDOW = 1;
|
|
111
178
|
exports.DEFAULT_RBAC_CACHE_KEY = "RBAC_SNAPSHOT";
|
|
112
|
-
exports.DEFAULT_RBAC_CACHE_TTL =
|
|
179
|
+
exports.DEFAULT_RBAC_CACHE_TTL = 1000 * 60 * 60 * 24; // 24 hours
|
|
113
180
|
exports.DEFAULT_MAILER_CACHE_KEY = "MAILER_SNAPSHOT";
|
|
114
|
-
exports.DEFAULT_MAILER_CACHE_TTL =
|
|
181
|
+
exports.DEFAULT_MAILER_CACHE_TTL = 1000 * 60 * 60 * 24; // 24 hours
|
|
115
182
|
exports.EMAIL_ENQUEUE_TYPES_FILE_NAME = "types/email_enqueue_type.generated.ts";
|
|
116
183
|
exports.EMAIL_ENQUEUE_UTIL_FILE_NAME = "utils/email_enqueue_util.generated.ts";
|
|
117
184
|
exports.CONTENT_CACHE_TTL_KEY = "CONTENT_CACHE_TTL";
|
|
@@ -119,13 +186,13 @@ exports.CONTENT_URL_KEY = "CONTENT_URL";
|
|
|
119
186
|
exports.CONTENT_LANG_KEY = "CONTENT_LANG";
|
|
120
187
|
exports.DEFAULT_CONTENT_URL = "http://localhost:4000/content/{{type}}_content/{{lang}}.json";
|
|
121
188
|
exports.DEFAULT_CONTENT_LANG = "en-GB";
|
|
122
|
-
exports.DEFAULT_CONTENT_CACHE_TTL =
|
|
189
|
+
exports.DEFAULT_CONTENT_CACHE_TTL = 1000 * 60 * 60 * 24; // 24 hours
|
|
123
190
|
// src/config/constants.ts
|
|
124
191
|
// src/config/constants.ts
|
|
125
192
|
exports.FILE_UPLOAD_LIMITS = {
|
|
126
193
|
IMAGE_MAX_SIZE: 5 * 1024 * 1024,
|
|
127
194
|
VIDEO_MAX_SIZE: 50 * 1024 * 1024,
|
|
128
|
-
DOCUMENT_MAX_SIZE: 10 * 1024 * 1024
|
|
195
|
+
DOCUMENT_MAX_SIZE: 10 * 1024 * 1024,
|
|
129
196
|
};
|
|
130
197
|
exports.FILE_UPLOAD_ENV_KEYS = {
|
|
131
198
|
IMAGE_MAX_SIZE: "FILE_UPLOAD_IMAGE_MAX_SIZE",
|
|
@@ -140,10 +207,10 @@ exports.FILE_UPLOAD_ENV_KEYS = {
|
|
|
140
207
|
GCS_BUCKET_NAME: "FILE_UPLOAD_GCS_BUCKET_NAME",
|
|
141
208
|
GCS_CLIENT_EMAIL: "FILE_UPLOAD_GCS_CLIENT_EMAIL",
|
|
142
209
|
GCS_PRIVATE_KEY: "FILE_UPLOAD_GCS_PRIVATE_KEY",
|
|
143
|
-
STORAGE_DRIVER_NAME: "FILE_UPLOAD_STORAGE_DRIVER_NAME"
|
|
210
|
+
STORAGE_DRIVER_NAME: "FILE_UPLOAD_STORAGE_DRIVER_NAME",
|
|
144
211
|
};
|
|
145
212
|
exports.FILE_UPLOAD_ALLOWED_MIME_TYPES = {
|
|
146
213
|
image: ["image/png", "image/jpeg", "image/webp"],
|
|
147
214
|
video: ["video/mp4", "video/webm"],
|
|
148
|
-
document: ["application/pdf", "application/msword"]
|
|
215
|
+
document: ["application/pdf", "application/msword"],
|
|
149
216
|
};
|
|
@@ -7,6 +7,8 @@ declare class SequelizeConnector extends BaseConnector<Sequelize> {
|
|
|
7
7
|
private constructor();
|
|
8
8
|
static getInstance(): SequelizeConnector;
|
|
9
9
|
private formatSQLQueryLog;
|
|
10
|
+
private coerceBoolean;
|
|
11
|
+
private coerceNumber;
|
|
10
12
|
private createSequelizeInstance;
|
|
11
13
|
private ensureDatabaseExists;
|
|
12
14
|
connect(options?: SequelizeConnectionOptions): Promise<Sequelize>;
|
|
@@ -35,18 +35,32 @@ class SequelizeConnector extends base_connector_1.default {
|
|
|
35
35
|
this.logger.error("Failed to log SQL query", { error });
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
+
coerceBoolean(value, fallback) {
|
|
39
|
+
if (typeof value === "boolean")
|
|
40
|
+
return value;
|
|
41
|
+
if (typeof value === "string") {
|
|
42
|
+
return ["true", "1", "yes", "on"].includes(value.trim().toLowerCase());
|
|
43
|
+
}
|
|
44
|
+
if (typeof value === "number")
|
|
45
|
+
return value === 1;
|
|
46
|
+
return fallback;
|
|
47
|
+
}
|
|
48
|
+
coerceNumber(value, fallback) {
|
|
49
|
+
const parsed = Number(value);
|
|
50
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
51
|
+
}
|
|
38
52
|
// ------------------------------------------------
|
|
39
53
|
// Create Sequelize instance (shared)
|
|
40
54
|
// ------------------------------------------------
|
|
41
55
|
createSequelizeInstance(options = {}) {
|
|
42
56
|
const dialect = options.dialect ?? this.env_manager.getEnvVar("DB_DIALECT", "postgres");
|
|
43
|
-
const logging_enabled = options.logging ?? this.env_manager.getEnvVar("DB_LOGGING", false);
|
|
57
|
+
const logging_enabled = this.coerceBoolean(options.logging ?? this.env_manager.getEnvVar("DB_LOGGING", false), false);
|
|
44
58
|
const logging = logging_enabled ? this.formatSQLQueryLog : false;
|
|
45
59
|
const database = options.database ?? this.env_manager.getEnvVar("DB_NAME");
|
|
46
60
|
const username = options.username ?? this.env_manager.getEnvVar("DB_USER");
|
|
47
61
|
const password = options.password ?? this.env_manager.getEnvVar("DB_PASSWORD");
|
|
48
62
|
const host = options.host ?? this.env_manager.getEnvVar("DB_HOST");
|
|
49
|
-
const port = options.port ?? this.env_manager.getEnvVar("DB_PORT", 5432);
|
|
63
|
+
const port = this.coerceNumber(options.port ?? this.env_manager.getEnvVar("DB_PORT", 5432), 5432);
|
|
50
64
|
return new sequelize_1.Sequelize({
|
|
51
65
|
database,
|
|
52
66
|
username,
|
|
@@ -79,28 +93,36 @@ class SequelizeConnector extends base_connector_1.default {
|
|
|
79
93
|
dialect,
|
|
80
94
|
logging: false,
|
|
81
95
|
});
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
96
|
+
try {
|
|
97
|
+
await admin.authenticate();
|
|
98
|
+
const queryInterface = admin.getQueryInterface();
|
|
99
|
+
const quoted_database = queryInterface.quoteIdentifier(database);
|
|
100
|
+
switch (dialect) {
|
|
101
|
+
case "postgres": {
|
|
102
|
+
const [rows] = await admin.query(`SELECT 1 FROM pg_database WHERE datname = :db`, { replacements: { db: database } });
|
|
103
|
+
if (rows.length === 0) {
|
|
104
|
+
await admin.query(`CREATE DATABASE ${quoted_database}`);
|
|
105
|
+
this.logger.info(`📦 Created DB ${database}`);
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case "mysql":
|
|
110
|
+
case "mariadb":
|
|
111
|
+
await admin.query(`CREATE DATABASE IF NOT EXISTS ${quoted_database}`);
|
|
112
|
+
break;
|
|
113
|
+
case "mssql": {
|
|
114
|
+
const escaped_database = database.replace(/'/g, "''");
|
|
115
|
+
await admin.query(`
|
|
116
|
+
IF DB_ID('${escaped_database}') IS NULL
|
|
117
|
+
CREATE DATABASE ${quoted_database}
|
|
118
|
+
`);
|
|
119
|
+
break;
|
|
89
120
|
}
|
|
90
|
-
break;
|
|
91
121
|
}
|
|
92
|
-
case "mysql":
|
|
93
|
-
case "mariadb":
|
|
94
|
-
await admin.query(`CREATE DATABASE IF NOT EXISTS \`${database}\``);
|
|
95
|
-
break;
|
|
96
|
-
case "mssql":
|
|
97
|
-
await admin.query(`
|
|
98
|
-
IF DB_ID('${database}') IS NULL
|
|
99
|
-
CREATE DATABASE [${database}]
|
|
100
|
-
`);
|
|
101
|
-
break;
|
|
102
122
|
}
|
|
103
|
-
|
|
123
|
+
finally {
|
|
124
|
+
await admin.close();
|
|
125
|
+
}
|
|
104
126
|
}
|
|
105
127
|
catch (error) {
|
|
106
128
|
this.logger.error(`DB auto-create skipped: ${database}`, { error });
|