node-server-engine 1.10.3 → 1.10.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.
@@ -7,17 +7,20 @@ exports.test = exports.staging = exports.production = exports.development = expo
7
7
  var _Sequelize = require("./Sequelize.validate");
8
8
  // Check that environment variables are correctly set
9
9
  (0, _Sequelize.validateSequelizeEnvironment)();
10
+
11
+ // Check if SQL_HOST is a Unix socket path (Cloud SQL)
12
+ const isUnixSocket = process.env.SQL_HOST?.startsWith('/');
10
13
  const config = {
11
14
  username: process.env.SQL_USER,
12
15
  password: process.env.SQL_PASSWORD,
13
16
  database: process.env.SQL_DB,
14
17
  host: process.env.SQL_HOST,
15
- port: process.env.SQL_PORT ? parseInt(process.env.SQL_PORT) : 5432,
16
- // Default port for PostgreSQL
18
+ // Don't set port for Unix socket connections (Cloud SQL)
19
+ port: isUnixSocket ? undefined : process.env.SQL_PORT ? parseInt(process.env.SQL_PORT) : 5432,
17
20
  dialect: process.env.SQL_TYPE ?? 'postgres',
18
21
  // Dynamically set the dialect (postgres, mysql, mssql)
19
- logging: false,
20
- // Set to true for debugging SQL queries
22
+ logging: process.env.SQL_LOGGING === 'true' ? console.log : false,
23
+ // Enable SQL logging with SQL_LOGGING=true
21
24
  define: {
22
25
  freezeTableName: false,
23
26
  // Prevent automatic pluralization of table names
@@ -1 +1 @@
1
- {"version":3,"file":"Sequelize.config.js","names":["_Sequelize","require","validateSequelizeEnvironment","config","username","process","env","SQL_USER","password","SQL_PASSWORD","database","SQL_DB","host","SQL_HOST","port","SQL_PORT","parseInt","dialect","SQL_TYPE","logging","define","freezeTableName","charset","collate","retry","max","NODE_ENV","dialectOptions","pool","min","acquire","idle","evict","requestTimeout","connectTimeout","encrypt","trustServerCertificate","timezone","ssl","PG_SSL","rejectUnauthorized","development","exports","staging","production","test","_default","default"],"sources":["../../../src/entities/Sequelize/Sequelize.config.ts"],"sourcesContent":["import { Options, Dialect } from 'sequelize';\nimport { validateSequelizeEnvironment } from './Sequelize.validate';\n\n// Check that environment variables are correctly set\nvalidateSequelizeEnvironment();\n\nconst config: Options = {\n username: process.env.SQL_USER,\n password: process.env.SQL_PASSWORD,\n database: process.env.SQL_DB,\n host: process.env.SQL_HOST,\n port: process.env.SQL_PORT ? parseInt(process.env.SQL_PORT) : 5432, // Default port for PostgreSQL\n dialect: (process.env.SQL_TYPE ?? 'postgres') as Dialect, // Dynamically set the dialect (postgres, mysql, mssql)\n logging: false, // Set to true for debugging SQL queries\n define: {\n freezeTableName: false, // Prevent automatic pluralization of table names\n charset: 'utf8mb4', // Set character set for MySQL/MariaDB\n collate: 'utf8mb4_unicode_ci' // Set collation for MySQL/MariaDB\n },\n retry: {\n max: process.env.NODE_ENV === 'test' ? 0 : 3 // Disable retries in test environment to prevent unhandled rejections\n },\n dialectOptions: {},\n pool: {\n max: process.env.NODE_ENV === 'test' ? 1 : 5,\n min: 0,\n acquire: process.env.NODE_ENV === 'test' ? 1000 : 30000, // Reduce acquire timeout in test\n idle: process.env.NODE_ENV === 'test' ? 1000 : 10000, // Reduce idle time in test\n evict: process.env.NODE_ENV === 'test' ? 100 : 1000 // How often to check for idle connections\n },\n};\n\n// Additional configurations for MSSQL\nif (config.dialect === 'mssql') {\n config.dialectOptions = {\n requestTimeout: 30000, // Increase request timeout for MSSQL\n connectTimeout: 30000, // Increase connection timeout for MSSQL\n encrypt: true, // Use encryption for MSSQL (set to false if not needed)\n trustServerCertificate: true, // Set to true if using self-signed certificates\n };\n}\n\n// Add specific dialect configurations if necessary for MySQL/PostgreSQL\nif (config.dialect === 'mysql') {\n config.dialectOptions = {\n timezone: 'Z', // Set timezone for MySQL\n };\n}\n\nif (config.dialect === 'postgres') {\n config.dialectOptions = {\n ssl: process.env.PG_SSL === 'true' ? { rejectUnauthorized: false } : false, // SSL options for PostgreSQL (if required)\n };\n}\n\nexport const development = config;\nexport const staging = config;\nexport const production = config;\nexport const test = config;\nexport default config;\n"],"mappings":";;;;;;AACA,IAAAA,UAAA,GAAAC,OAAA;AAEA;AACA,IAAAC,uCAA4B,EAAC,CAAC;AAE9B,MAAMC,MAAe,GAAG;EACtBC,QAAQ,EAAEC,OAAO,CAACC,GAAG,CAACC,QAAQ;EAC9BC,QAAQ,EAAEH,OAAO,CAACC,GAAG,CAACG,YAAY;EAClCC,QAAQ,EAAEL,OAAO,CAACC,GAAG,CAACK,MAAM;EAC5BC,IAAI,EAAEP,OAAO,CAACC,GAAG,CAACO,QAAQ;EAC1BC,IAAI,EAAET,OAAO,CAACC,GAAG,CAACS,QAAQ,GAAGC,QAAQ,CAACX,OAAO,CAACC,GAAG,CAACS,QAAQ,CAAC,GAAG,IAAI;EAAE;EACpEE,OAAO,EAAGZ,OAAO,CAACC,GAAG,CAACY,QAAQ,IAAI,UAAsB;EAAE;EAC1DC,OAAO,EAAE,KAAK;EAAE;EAChBC,MAAM,EAAE;IACNC,eAAe,EAAE,KAAK;IAAE;IACxBC,OAAO,EAAE,SAAS;IAAE;IACpBC,OAAO,EAAE,oBAAoB,CAAC;EAChC,CAAC;EACDC,KAAK,EAAE;IACLC,GAAG,EAAEpB,OAAO,CAACC,GAAG,CAACoB,QAAQ,KAAK,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;EAC/C,CAAC;EACDC,cAAc,EAAE,CAAC,CAAC;EAClBC,IAAI,EAAE;IACJH,GAAG,EAAEpB,OAAO,CAACC,GAAG,CAACoB,QAAQ,KAAK,MAAM,GAAG,CAAC,GAAG,CAAC;IAC5CG,GAAG,EAAE,CAAC;IACNC,OAAO,EAAEzB,OAAO,CAACC,GAAG,CAACoB,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG,KAAK;IAAE;IACzDK,IAAI,EAAE1B,OAAO,CAACC,GAAG,CAACoB,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG,KAAK;IAAE;IACtDM,KAAK,EAAE3B,OAAO,CAACC,GAAG,CAACoB,QAAQ,KAAK,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC;EACtD;AACF,CAAC;;AAED;AACA,IAAIvB,MAAM,CAACc,OAAO,KAAK,OAAO,EAAE;EAC9Bd,MAAM,CAACwB,cAAc,GAAG;IACtBM,cAAc,EAAE,KAAK;IAAE;IACvBC,cAAc,EAAE,KAAK;IAAE;IACvBC,OAAO,EAAE,IAAI;IAAE;IACfC,sBAAsB,EAAE,IAAI,CAAE;EAChC,CAAC;AACH;;AAEA;AACA,IAAIjC,MAAM,CAACc,OAAO,KAAK,OAAO,EAAE;EAC9Bd,MAAM,CAACwB,cAAc,GAAG;IACtBU,QAAQ,EAAE,GAAG,CAAE;EACjB,CAAC;AACH;AAEA,IAAIlC,MAAM,CAACc,OAAO,KAAK,UAAU,EAAE;EACjCd,MAAM,CAACwB,cAAc,GAAG;IACtBW,GAAG,EAAEjC,OAAO,CAACC,GAAG,CAACiC,MAAM,KAAK,MAAM,GAAG;MAAEC,kBAAkB,EAAE;IAAM,CAAC,GAAG,KAAK,CAAE;EAC9E,CAAC;AACH;AAEO,MAAMC,WAAW,GAAAC,OAAA,CAAAD,WAAA,GAAGtC,MAAM;AAC1B,MAAMwC,OAAO,GAAAD,OAAA,CAAAC,OAAA,GAAGxC,MAAM;AACtB,MAAMyC,UAAU,GAAAF,OAAA,CAAAE,UAAA,GAAGzC,MAAM;AACzB,MAAM0C,IAAI,GAAAH,OAAA,CAAAG,IAAA,GAAG1C,MAAM;AAAC,IAAA2C,QAAA,GAAAJ,OAAA,CAAAK,OAAA,GACZ5C,MAAM","ignoreList":[]}
1
+ {"version":3,"file":"Sequelize.config.js","names":["_Sequelize","require","validateSequelizeEnvironment","isUnixSocket","process","env","SQL_HOST","startsWith","config","username","SQL_USER","password","SQL_PASSWORD","database","SQL_DB","host","port","undefined","SQL_PORT","parseInt","dialect","SQL_TYPE","logging","SQL_LOGGING","console","log","define","freezeTableName","charset","collate","retry","max","NODE_ENV","dialectOptions","pool","min","acquire","idle","evict","requestTimeout","connectTimeout","encrypt","trustServerCertificate","timezone","ssl","PG_SSL","rejectUnauthorized","development","exports","staging","production","test","_default","default"],"sources":["../../../src/entities/Sequelize/Sequelize.config.ts"],"sourcesContent":["import { Options, Dialect } from 'sequelize';\nimport { validateSequelizeEnvironment } from './Sequelize.validate';\n\n// Check that environment variables are correctly set\nvalidateSequelizeEnvironment();\n\n// Check if SQL_HOST is a Unix socket path (Cloud SQL)\nconst isUnixSocket = process.env.SQL_HOST?.startsWith('/');\n\nconst config: Options = {\n username: process.env.SQL_USER,\n password: process.env.SQL_PASSWORD,\n database: process.env.SQL_DB,\n host: process.env.SQL_HOST,\n // Don't set port for Unix socket connections (Cloud SQL)\n port: isUnixSocket ? undefined : (process.env.SQL_PORT ? parseInt(process.env.SQL_PORT) : 5432),\n dialect: (process.env.SQL_TYPE ?? 'postgres') as Dialect, // Dynamically set the dialect (postgres, mysql, mssql)\n logging: process.env.SQL_LOGGING === 'true' ? console.log : false, // Enable SQL logging with SQL_LOGGING=true\n define: {\n freezeTableName: false, // Prevent automatic pluralization of table names\n charset: 'utf8mb4', // Set character set for MySQL/MariaDB\n collate: 'utf8mb4_unicode_ci' // Set collation for MySQL/MariaDB\n },\n retry: {\n max: process.env.NODE_ENV === 'test' ? 0 : 3 // Disable retries in test environment to prevent unhandled rejections\n },\n dialectOptions: {},\n pool: {\n max: process.env.NODE_ENV === 'test' ? 1 : 5,\n min: 0,\n acquire: process.env.NODE_ENV === 'test' ? 1000 : 30000, // Reduce acquire timeout in test\n idle: process.env.NODE_ENV === 'test' ? 1000 : 10000, // Reduce idle time in test\n evict: process.env.NODE_ENV === 'test' ? 100 : 1000 // How often to check for idle connections\n },\n};\n\n// Additional configurations for MSSQL\nif (config.dialect === 'mssql') {\n config.dialectOptions = {\n requestTimeout: 30000, // Increase request timeout for MSSQL\n connectTimeout: 30000, // Increase connection timeout for MSSQL\n encrypt: true, // Use encryption for MSSQL (set to false if not needed)\n trustServerCertificate: true, // Set to true if using self-signed certificates\n };\n}\n\n// Add specific dialect configurations if necessary for MySQL/PostgreSQL\nif (config.dialect === 'mysql') {\n config.dialectOptions = {\n timezone: 'Z', // Set timezone for MySQL\n };\n}\n\nif (config.dialect === 'postgres') {\n config.dialectOptions = {\n ssl: process.env.PG_SSL === 'true' ? { rejectUnauthorized: false } : false, // SSL options for PostgreSQL (if required)\n };\n}\n\nexport const development = config;\nexport const staging = config;\nexport const production = config;\nexport const test = config;\nexport default config;\n"],"mappings":"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","ignoreList":[]}
@@ -49,9 +49,40 @@ function init() {
49
49
  // In test environment, authentication happens automatically with SQLite
50
50
  // For other environments, authenticate and log the result
51
51
  if (process.env.NODE_ENV !== 'test') {
52
- void sequelizeClient.authenticate().then(() => (0, _report.reportInfo)({
53
- message: 'Connected to database successfully'
54
- })).catch(err => (0, _report.reportError)(err));
52
+ // Add timeout to prevent hanging on connection issues
53
+ const authTimeout = setTimeout(() => {
54
+ (0, _report.reportError)({
55
+ message: 'Database authentication timeout after 30 seconds',
56
+ data: {
57
+ host: process.env.SQL_HOST,
58
+ database: process.env.SQL_DB,
59
+ user: process.env.SQL_USER
60
+ }
61
+ });
62
+ }, 30000);
63
+ void sequelizeClient.authenticate().then(() => {
64
+ clearTimeout(authTimeout);
65
+ (0, _report.reportInfo)({
66
+ message: 'Connected to database successfully',
67
+ data: {
68
+ host: process.env.SQL_HOST,
69
+ database: process.env.SQL_DB,
70
+ dialect: sequelizeClient?.getDialect()
71
+ }
72
+ });
73
+ }).catch(err => {
74
+ clearTimeout(authTimeout);
75
+ (0, _report.reportError)({
76
+ message: 'Failed to connect to database',
77
+ data: {
78
+ error: err.message,
79
+ host: process.env.SQL_HOST,
80
+ database: process.env.SQL_DB,
81
+ user: process.env.SQL_USER
82
+ }
83
+ });
84
+ (0, _report.reportError)(err);
85
+ });
55
86
  }
56
87
  _LifecycleController.LifecycleController.register(sequelize);
57
88
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Sequelize.js","names":["_sequelizeTypescript","require","_Sequelize","_interopRequireDefault","_Sequelize2","_EngineError","_LifecycleController","_report","sequelizeClient","exports","sequelize","Proxy","get","target","property","init","shutdown","addModels","EngineError","message","createSequelizeClient","process","env","NODE_ENV","authenticate","then","reportInfo","catch","err","reportError","LifecycleController","register","close","error","console","undefined","models","addHook","result","convertToPlain","instance","toJSON","plain","Object","keys","forEach","key","Array","isArray","sync","Sequelize","dialect","storage","logging","validateSequelizeEnvironment","SQL_DB","SQL_USER","SQL_PASSWORD","dbConfig"],"sources":["../../../src/entities/Sequelize/Sequelize.ts"],"sourcesContent":["import { Sequelize, ModelCtor } from 'sequelize-typescript';\nimport dbConfig from './Sequelize.config';\nimport { Sequelize as SequelizeInterface } from './Sequelize.types';\nimport { validateSequelizeEnvironment } from './Sequelize.validate';\nimport { EngineError } from 'entities/EngineError';\nimport { LifecycleController } from 'entities/LifecycleController';\nimport { reportInfo, reportError } from 'utils/report';\n\nexport let sequelizeClient: undefined | Sequelize;\n\n/**\n * We use a proxy to extend the Sequelize behavior and allow initialization of the client only when needed while keeping the same interface\n */\nexport const sequelize = new Proxy<SequelizeInterface>(\n // Due to how we do the proxying, we are forced to ignore ts-errors, we could never create an object that respects the interface properly\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n {},\n {\n get: function (target, property): unknown {\n if (property === 'init') return init;\n if (property === 'shutdown') return shutdown;\n if (property === 'addModels') return addModels;\n // Create the sequelize client if it does not exist\n if (!sequelizeClient)\n throw new EngineError({\n message: 'Sequelize client was not initialized'\n });\n // Call the function on the sequelize client\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n return sequelizeClient[property] as unknown;\n }\n }\n);\n\n/** On init create client and connect */\nexport function init(): void {\n // Ignore if already initialized\n if (sequelizeClient) return;\n sequelizeClient = createSequelizeClient();\n \n // In test environment, authentication happens automatically with SQLite\n // For other environments, authenticate and log the result\n if (process.env.NODE_ENV !== 'test') {\n void sequelizeClient\n .authenticate()\n .then(() => reportInfo({ message: 'Connected to database successfully' }))\n .catch((err: Error) => reportError(err));\n }\n \n LifecycleController.register(sequelize);\n}\n\n/** On shutdown close connection and clear client */\nexport async function shutdown(): Promise<void> {\n if (sequelizeClient) {\n try {\n // For SQLite, just close the client (closing connection manager first causes SQLITE_MISUSE)\n // For other dialects, sequelize.close() handles everything properly\n await sequelizeClient.close();\n } catch (error) {\n // Ignore errors during shutdown\n if (process.env.NODE_ENV !== 'test') {\n console.error('Error closing sequelize client:', error);\n }\n }\n }\n sequelizeClient = undefined;\n}\n\nexport function addModels(models: Array<ModelCtor>): void {\n if (!sequelizeClient)\n throw new EngineError({\n message: 'Sequelize client was not initialized'\n });\n sequelizeClient.addModels(models);\n \n // Override toJSON behavior globally to ensure consistency between dev and prod\n // In dev (ts-node), property access works directly on instances\n // In prod (compiled), we need explicit serialization\n // This hook intercepts all afterFind results and converts them to plain objects\n sequelizeClient.addHook('afterFind', (result) => {\n if (!result) return;\n \n const convertToPlain = (instance: any) => {\n if (!instance || !instance.toJSON) return instance;\n const plain = instance.toJSON();\n // Copy the plain object properties back to the instance\n // This makes property access work without .toJSON() in compiled code\n Object.keys(plain).forEach(key => {\n instance[key] = plain[key];\n });\n };\n \n if (Array.isArray(result)) {\n result.forEach(convertToPlain);\n } else {\n convertToPlain(result);\n }\n });\n \n sequelizeClient.sync();\n}\n\n/** Create Sequelize client */\nexport function createSequelizeClient(): Sequelize {\n // Use in-memory SQLite for test environment to avoid real database connections\n if (process.env.NODE_ENV === 'test') {\n return new Sequelize({\n dialect: 'sqlite',\n storage: ':memory:',\n logging: false\n });\n }\n \n // Throw an error if there is no host initial\n validateSequelizeEnvironment();\n return new Sequelize(\n process.env.SQL_DB as string,\n process.env.SQL_USER as string,\n process.env.SQL_PASSWORD as string,\n dbConfig\n );\n}\n"],"mappings":";;;;;;;;;;;AAAA,IAAAA,oBAAA,GAAAC,OAAA;AACA,IAAAC,UAAA,GAAAC,sBAAA,CAAAF,OAAA;AAEA,IAAAG,WAAA,GAAAH,OAAA;AACA,IAAAI,YAAA,GAAAJ,OAAA;AACA,IAAAK,oBAAA,GAAAL,OAAA;AACA,IAAAM,OAAA,GAAAN,OAAA;AAEO,IAAIO,eAAsC,GAAAC,OAAA,CAAAD,eAAA;;AAEjD;AACA;AACA;AACO,MAAME,SAAS,GAAAD,OAAA,CAAAC,SAAA,GAAG,IAAIC,KAAK;AAChC;AACA;AACA;AACA,CAAC,CAAC,EACF;EACEC,GAAG,EAAE,SAAAA,CAAUC,MAAM,EAAEC,QAAQ,EAAW;IACxC,IAAIA,QAAQ,KAAK,MAAM,EAAE,OAAOC,IAAI;IACpC,IAAID,QAAQ,KAAK,UAAU,EAAE,OAAOE,QAAQ;IAC5C,IAAIF,QAAQ,KAAK,WAAW,EAAE,OAAOG,SAAS;IAC9C;IACA,IAAI,CAACT,eAAe,EAClB,MAAM,IAAIU,wBAAW,CAAC;MACpBC,OAAO,EAAE;IACX,CAAC,CAAC;IACJ;IACA;IACA;IACA,OAAOX,eAAe,CAACM,QAAQ,CAAC;EAClC;AACF,CACF,CAAC;;AAED;AACO,SAASC,IAAIA,CAAA,EAAS;EAC3B;EACA,IAAIP,eAAe,EAAE;EACrBC,OAAA,CAAAD,eAAA,GAAAA,eAAe,GAAGY,qBAAqB,CAAC,CAAC;;EAEzC;EACA;EACA,IAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ,KAAK,MAAM,EAAE;IACnC,KAAKf,eAAe,CACjBgB,YAAY,CAAC,CAAC,CACdC,IAAI,CAAC,MAAM,IAAAC,kBAAU,EAAC;MAAEP,OAAO,EAAE;IAAqC,CAAC,CAAC,CAAC,CACzEQ,KAAK,CAAEC,GAAU,IAAK,IAAAC,mBAAW,EAACD,GAAG,CAAC,CAAC;EAC5C;EAEAE,wCAAmB,CAACC,QAAQ,CAACrB,SAAS,CAAC;AACzC;;AAEA;AACO,eAAeM,QAAQA,CAAA,EAAkB;EAC9C,IAAIR,eAAe,EAAE;IACnB,IAAI;MACF;MACA;MACA,MAAMA,eAAe,CAACwB,KAAK,CAAC,CAAC;IAC/B,CAAC,CAAC,OAAOC,KAAK,EAAE;MACd;MACA,IAAIZ,OAAO,CAACC,GAAG,CAACC,QAAQ,KAAK,MAAM,EAAE;QACnCW,OAAO,CAACD,KAAK,CAAC,iCAAiC,EAAEA,KAAK,CAAC;MACzD;IACF;EACF;EACAxB,OAAA,CAAAD,eAAA,GAAAA,eAAe,GAAG2B,SAAS;AAC7B;AAEO,SAASlB,SAASA,CAACmB,MAAwB,EAAQ;EACxD,IAAI,CAAC5B,eAAe,EAClB,MAAM,IAAIU,wBAAW,CAAC;IACpBC,OAAO,EAAE;EACX,CAAC,CAAC;EACJX,eAAe,CAACS,SAAS,CAACmB,MAAM,CAAC;;EAEjC;EACA;EACA;EACA;EACA5B,eAAe,CAAC6B,OAAO,CAAC,WAAW,EAAGC,MAAM,IAAK;IAC/C,IAAI,CAACA,MAAM,EAAE;IAEb,MAAMC,cAAc,GAAIC,QAAa,IAAK;MACxC,IAAI,CAACA,QAAQ,IAAI,CAACA,QAAQ,CAACC,MAAM,EAAE,OAAOD,QAAQ;MAClD,MAAME,KAAK,GAAGF,QAAQ,CAACC,MAAM,CAAC,CAAC;MAC/B;MACA;MACAE,MAAM,CAACC,IAAI,CAACF,KAAK,CAAC,CAACG,OAAO,CAACC,GAAG,IAAI;QAChCN,QAAQ,CAACM,GAAG,CAAC,GAAGJ,KAAK,CAACI,GAAG,CAAC;MAC5B,CAAC,CAAC;IACJ,CAAC;IAED,IAAIC,KAAK,CAACC,OAAO,CAACV,MAAM,CAAC,EAAE;MACzBA,MAAM,CAACO,OAAO,CAACN,cAAc,CAAC;IAChC,CAAC,MAAM;MACLA,cAAc,CAACD,MAAM,CAAC;IACxB;EACF,CAAC,CAAC;EAEF9B,eAAe,CAACyC,IAAI,CAAC,CAAC;AACxB;;AAEA;AACO,SAAS7B,qBAAqBA,CAAA,EAAc;EACjD;EACA,IAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ,KAAK,MAAM,EAAE;IACnC,OAAO,IAAI2B,8BAAS,CAAC;MACnBC,OAAO,EAAE,QAAQ;MACjBC,OAAO,EAAE,UAAU;MACnBC,OAAO,EAAE;IACX,CAAC,CAAC;EACJ;;EAEA;EACA,IAAAC,wCAA4B,EAAC,CAAC;EAC9B,OAAO,IAAIJ,8BAAS,CAClB7B,OAAO,CAACC,GAAG,CAACiC,MAAM,EAClBlC,OAAO,CAACC,GAAG,CAACkC,QAAQ,EACpBnC,OAAO,CAACC,GAAG,CAACmC,YAAY,EACxBC,kBACF,CAAC;AACH","ignoreList":[]}
1
+ {"version":3,"file":"Sequelize.js","names":["_sequelizeTypescript","require","_Sequelize","_interopRequireDefault","_Sequelize2","_EngineError","_LifecycleController","_report","sequelizeClient","exports","sequelize","Proxy","get","target","property","init","shutdown","addModels","EngineError","message","createSequelizeClient","process","env","NODE_ENV","authTimeout","setTimeout","reportError","data","host","SQL_HOST","database","SQL_DB","user","SQL_USER","authenticate","then","clearTimeout","reportInfo","dialect","getDialect","catch","err","error","LifecycleController","register","close","console","undefined","models","addHook","result","convertToPlain","instance","toJSON","plain","Object","keys","forEach","key","Array","isArray","sync","Sequelize","storage","logging","validateSequelizeEnvironment","SQL_PASSWORD","dbConfig"],"sources":["../../../src/entities/Sequelize/Sequelize.ts"],"sourcesContent":["import { Sequelize, ModelCtor } from 'sequelize-typescript';\nimport dbConfig from './Sequelize.config';\nimport { Sequelize as SequelizeInterface } from './Sequelize.types';\nimport { validateSequelizeEnvironment } from './Sequelize.validate';\nimport { EngineError } from 'entities/EngineError';\nimport { LifecycleController } from 'entities/LifecycleController';\nimport { reportInfo, reportError } from 'utils/report';\n\nexport let sequelizeClient: undefined | Sequelize;\n\n/**\n * We use a proxy to extend the Sequelize behavior and allow initialization of the client only when needed while keeping the same interface\n */\nexport const sequelize = new Proxy<SequelizeInterface>(\n // Due to how we do the proxying, we are forced to ignore ts-errors, we could never create an object that respects the interface properly\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n {},\n {\n get: function (target, property): unknown {\n if (property === 'init') return init;\n if (property === 'shutdown') return shutdown;\n if (property === 'addModels') return addModels;\n // Create the sequelize client if it does not exist\n if (!sequelizeClient)\n throw new EngineError({\n message: 'Sequelize client was not initialized'\n });\n // Call the function on the sequelize client\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n return sequelizeClient[property] as unknown;\n }\n }\n);\n\n/** On init create client and connect */\nexport function init(): void {\n // Ignore if already initialized\n if (sequelizeClient) return;\n sequelizeClient = createSequelizeClient();\n \n // In test environment, authentication happens automatically with SQLite\n // For other environments, authenticate and log the result\n if (process.env.NODE_ENV !== 'test') {\n // Add timeout to prevent hanging on connection issues\n const authTimeout = setTimeout(() => {\n reportError({\n message: 'Database authentication timeout after 30 seconds',\n data: {\n host: process.env.SQL_HOST,\n database: process.env.SQL_DB,\n user: process.env.SQL_USER\n }\n });\n }, 30000);\n\n void sequelizeClient\n .authenticate()\n .then(() => {\n clearTimeout(authTimeout);\n reportInfo({ \n message: 'Connected to database successfully',\n data: {\n host: process.env.SQL_HOST,\n database: process.env.SQL_DB,\n dialect: sequelizeClient?.getDialect()\n }\n });\n })\n .catch((err: Error) => {\n clearTimeout(authTimeout);\n reportError({\n message: 'Failed to connect to database',\n data: {\n error: err.message,\n host: process.env.SQL_HOST,\n database: process.env.SQL_DB,\n user: process.env.SQL_USER\n }\n });\n reportError(err);\n });\n }\n \n LifecycleController.register(sequelize);\n}\n\n/** On shutdown close connection and clear client */\nexport async function shutdown(): Promise<void> {\n if (sequelizeClient) {\n try {\n // For SQLite, just close the client (closing connection manager first causes SQLITE_MISUSE)\n // For other dialects, sequelize.close() handles everything properly\n await sequelizeClient.close();\n } catch (error) {\n // Ignore errors during shutdown\n if (process.env.NODE_ENV !== 'test') {\n console.error('Error closing sequelize client:', error);\n }\n }\n }\n sequelizeClient = undefined;\n}\n\nexport function addModels(models: Array<ModelCtor>): void {\n if (!sequelizeClient)\n throw new EngineError({\n message: 'Sequelize client was not initialized'\n });\n sequelizeClient.addModels(models);\n \n // Override toJSON behavior globally to ensure consistency between dev and prod\n // In dev (ts-node), property access works directly on instances\n // In prod (compiled), we need explicit serialization\n // This hook intercepts all afterFind results and converts them to plain objects\n sequelizeClient.addHook('afterFind', (result) => {\n if (!result) return;\n \n const convertToPlain = (instance: any) => {\n if (!instance || !instance.toJSON) return instance;\n const plain = instance.toJSON();\n // Copy the plain object properties back to the instance\n // This makes property access work without .toJSON() in compiled code\n Object.keys(plain).forEach(key => {\n instance[key] = plain[key];\n });\n };\n \n if (Array.isArray(result)) {\n result.forEach(convertToPlain);\n } else {\n convertToPlain(result);\n }\n });\n \n sequelizeClient.sync();\n}\n\n/** Create Sequelize client */\nexport function createSequelizeClient(): Sequelize {\n // Use in-memory SQLite for test environment to avoid real database connections\n if (process.env.NODE_ENV === 'test') {\n return new Sequelize({\n dialect: 'sqlite',\n storage: ':memory:',\n logging: false\n });\n }\n \n // Throw an error if there is no host initial\n validateSequelizeEnvironment();\n return new Sequelize(\n process.env.SQL_DB as string,\n process.env.SQL_USER as string,\n process.env.SQL_PASSWORD as string,\n dbConfig\n );\n}\n"],"mappings":";;;;;;;;;;;AAAA,IAAAA,oBAAA,GAAAC,OAAA;AACA,IAAAC,UAAA,GAAAC,sBAAA,CAAAF,OAAA;AAEA,IAAAG,WAAA,GAAAH,OAAA;AACA,IAAAI,YAAA,GAAAJ,OAAA;AACA,IAAAK,oBAAA,GAAAL,OAAA;AACA,IAAAM,OAAA,GAAAN,OAAA;AAEO,IAAIO,eAAsC,GAAAC,OAAA,CAAAD,eAAA;;AAEjD;AACA;AACA;AACO,MAAME,SAAS,GAAAD,OAAA,CAAAC,SAAA,GAAG,IAAIC,KAAK;AAChC;AACA;AACA;AACA,CAAC,CAAC,EACF;EACEC,GAAG,EAAE,SAAAA,CAAUC,MAAM,EAAEC,QAAQ,EAAW;IACxC,IAAIA,QAAQ,KAAK,MAAM,EAAE,OAAOC,IAAI;IACpC,IAAID,QAAQ,KAAK,UAAU,EAAE,OAAOE,QAAQ;IAC5C,IAAIF,QAAQ,KAAK,WAAW,EAAE,OAAOG,SAAS;IAC9C;IACA,IAAI,CAACT,eAAe,EAClB,MAAM,IAAIU,wBAAW,CAAC;MACpBC,OAAO,EAAE;IACX,CAAC,CAAC;IACJ;IACA;IACA;IACA,OAAOX,eAAe,CAACM,QAAQ,CAAC;EAClC;AACF,CACF,CAAC;;AAED;AACO,SAASC,IAAIA,CAAA,EAAS;EAC3B;EACA,IAAIP,eAAe,EAAE;EACrBC,OAAA,CAAAD,eAAA,GAAAA,eAAe,GAAGY,qBAAqB,CAAC,CAAC;;EAEzC;EACA;EACA,IAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ,KAAK,MAAM,EAAE;IACnC;IACA,MAAMC,WAAW,GAAGC,UAAU,CAAC,MAAM;MACnC,IAAAC,mBAAW,EAAC;QACVP,OAAO,EAAE,kDAAkD;QAC3DQ,IAAI,EAAE;UACJC,IAAI,EAAEP,OAAO,CAACC,GAAG,CAACO,QAAQ;UAC1BC,QAAQ,EAAET,OAAO,CAACC,GAAG,CAACS,MAAM;UAC5BC,IAAI,EAAEX,OAAO,CAACC,GAAG,CAACW;QACpB;MACF,CAAC,CAAC;IACJ,CAAC,EAAE,KAAK,CAAC;IAET,KAAKzB,eAAe,CACjB0B,YAAY,CAAC,CAAC,CACdC,IAAI,CAAC,MAAM;MACVC,YAAY,CAACZ,WAAW,CAAC;MACzB,IAAAa,kBAAU,EAAC;QACTlB,OAAO,EAAE,oCAAoC;QAC7CQ,IAAI,EAAE;UACJC,IAAI,EAAEP,OAAO,CAACC,GAAG,CAACO,QAAQ;UAC1BC,QAAQ,EAAET,OAAO,CAACC,GAAG,CAACS,MAAM;UAC5BO,OAAO,EAAE9B,eAAe,EAAE+B,UAAU,CAAC;QACvC;MACF,CAAC,CAAC;IACJ,CAAC,CAAC,CACDC,KAAK,CAAEC,GAAU,IAAK;MACrBL,YAAY,CAACZ,WAAW,CAAC;MACzB,IAAAE,mBAAW,EAAC;QACVP,OAAO,EAAE,+BAA+B;QACxCQ,IAAI,EAAE;UACJe,KAAK,EAAED,GAAG,CAACtB,OAAO;UAClBS,IAAI,EAAEP,OAAO,CAACC,GAAG,CAACO,QAAQ;UAC1BC,QAAQ,EAAET,OAAO,CAACC,GAAG,CAACS,MAAM;UAC5BC,IAAI,EAAEX,OAAO,CAACC,GAAG,CAACW;QACpB;MACF,CAAC,CAAC;MACF,IAAAP,mBAAW,EAACe,GAAG,CAAC;IAClB,CAAC,CAAC;EACN;EAEAE,wCAAmB,CAACC,QAAQ,CAAClC,SAAS,CAAC;AACzC;;AAEA;AACO,eAAeM,QAAQA,CAAA,EAAkB;EAC9C,IAAIR,eAAe,EAAE;IACnB,IAAI;MACF;MACA;MACA,MAAMA,eAAe,CAACqC,KAAK,CAAC,CAAC;IAC/B,CAAC,CAAC,OAAOH,KAAK,EAAE;MACd;MACA,IAAIrB,OAAO,CAACC,GAAG,CAACC,QAAQ,KAAK,MAAM,EAAE;QACnCuB,OAAO,CAACJ,KAAK,CAAC,iCAAiC,EAAEA,KAAK,CAAC;MACzD;IACF;EACF;EACAjC,OAAA,CAAAD,eAAA,GAAAA,eAAe,GAAGuC,SAAS;AAC7B;AAEO,SAAS9B,SAASA,CAAC+B,MAAwB,EAAQ;EACxD,IAAI,CAACxC,eAAe,EAClB,MAAM,IAAIU,wBAAW,CAAC;IACpBC,OAAO,EAAE;EACX,CAAC,CAAC;EACJX,eAAe,CAACS,SAAS,CAAC+B,MAAM,CAAC;;EAEjC;EACA;EACA;EACA;EACAxC,eAAe,CAACyC,OAAO,CAAC,WAAW,EAAGC,MAAM,IAAK;IAC/C,IAAI,CAACA,MAAM,EAAE;IAEb,MAAMC,cAAc,GAAIC,QAAa,IAAK;MACxC,IAAI,CAACA,QAAQ,IAAI,CAACA,QAAQ,CAACC,MAAM,EAAE,OAAOD,QAAQ;MAClD,MAAME,KAAK,GAAGF,QAAQ,CAACC,MAAM,CAAC,CAAC;MAC/B;MACA;MACAE,MAAM,CAACC,IAAI,CAACF,KAAK,CAAC,CAACG,OAAO,CAACC,GAAG,IAAI;QAChCN,QAAQ,CAACM,GAAG,CAAC,GAAGJ,KAAK,CAACI,GAAG,CAAC;MAC5B,CAAC,CAAC;IACJ,CAAC;IAED,IAAIC,KAAK,CAACC,OAAO,CAACV,MAAM,CAAC,EAAE;MACzBA,MAAM,CAACO,OAAO,CAACN,cAAc,CAAC;IAChC,CAAC,MAAM;MACLA,cAAc,CAACD,MAAM,CAAC;IACxB;EACF,CAAC,CAAC;EAEF1C,eAAe,CAACqD,IAAI,CAAC,CAAC;AACxB;;AAEA;AACO,SAASzC,qBAAqBA,CAAA,EAAc;EACjD;EACA,IAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ,KAAK,MAAM,EAAE;IACnC,OAAO,IAAIuC,8BAAS,CAAC;MACnBxB,OAAO,EAAE,QAAQ;MACjByB,OAAO,EAAE,UAAU;MACnBC,OAAO,EAAE;IACX,CAAC,CAAC;EACJ;;EAEA;EACA,IAAAC,wCAA4B,EAAC,CAAC;EAC9B,OAAO,IAAIH,8BAAS,CAClBzC,OAAO,CAACC,GAAG,CAACS,MAAM,EAClBV,OAAO,CAACC,GAAG,CAACW,QAAQ,EACpBZ,OAAO,CAACC,GAAG,CAAC4C,YAAY,EACxBC,kBACF,CAAC;AACH","ignoreList":[]}
@@ -42,67 +42,107 @@ async function runPendingMigrations() {
42
42
  if (!_Sequelize.sequelize) throw new _EngineError.EngineError({
43
43
  message: 'Sequelize is not initialized'
44
44
  });
45
- // First make sure that the metadata table is up to date
46
- await (0, _migrateMetadataTable.migrateMetadataTable)(_Sequelize.sequelize);
47
- const migrationPaths = getMigrationPaths();
48
- if (!migrationPaths || migrationPaths.length <= 0) {
45
+ try {
49
46
  (0, _report.reportDebug)({
50
47
  namespace,
51
- message: 'No valid migration paths found.',
48
+ message: 'Starting migration process',
52
49
  data: {
53
- migrationPaths
50
+ sqlHost: process.env.SQL_HOST,
51
+ sqlDb: process.env.SQL_DB,
52
+ sqlUser: process.env.SQL_USER,
53
+ nodeEnv: process.env.NODE_ENV
54
54
  }
55
55
  });
56
- return;
57
- }
58
56
 
59
- // Process migrations sequentially to avoid race conditions
60
- for (const path of migrationPaths) {
61
- const migrator = new _umzug.Umzug({
62
- migrations: {
63
- glob: path,
64
- resolve: ({
65
- name,
66
- path,
67
- context
68
- }) => {
69
- const nameWithoutExtension = name.replace(/\.(ts|js)$/, '');
57
+ // First make sure that the metadata table is up to date
58
+ (0, _report.reportDebug)({
59
+ namespace,
60
+ message: 'Migrating metadata table'
61
+ });
62
+ await (0, _migrateMetadataTable.migrateMetadataTable)(_Sequelize.sequelize);
63
+ const migrationPaths = getMigrationPaths();
64
+ if (!migrationPaths || migrationPaths.length <= 0) {
65
+ (0, _report.reportDebug)({
66
+ namespace,
67
+ message: 'No valid migration paths found.',
68
+ data: {
69
+ migrationPaths
70
+ }
71
+ });
72
+ return;
73
+ }
70
74
 
71
- // Use dynamic import for better TypeScript/ES module support
72
- const migrationPromise = (specifier => new Promise(r => r(`${specifier}`)).then(s => _interopRequireWildcard(require(s))))(path || '');
73
- return {
74
- name: nameWithoutExtension,
75
- up: async () => {
76
- const migration = await migrationPromise;
77
- return migration.up(context);
78
- },
79
- down: async () => {
80
- const migration = await migrationPromise;
81
- return migration.down(context);
82
- }
83
- };
75
+ // Process migrations sequentially to avoid race conditions
76
+ for (const path of migrationPaths) {
77
+ (0, _report.reportDebug)({
78
+ namespace,
79
+ message: 'Processing migration path',
80
+ data: {
81
+ path
84
82
  }
85
- },
86
- context: _Sequelize.sequelize.getQueryInterface(),
87
- storage: new _umzug.SequelizeStorage({
88
- sequelize: _Sequelize.sequelize
89
- }),
90
- logger: console
91
- });
83
+ });
84
+ const migrator = new _umzug.Umzug({
85
+ migrations: {
86
+ glob: path,
87
+ resolve: ({
88
+ name,
89
+ path,
90
+ context
91
+ }) => {
92
+ const nameWithoutExtension = name.replace(/\.(ts|js)$/, '');
93
+
94
+ // Use dynamic import for better TypeScript/ES module support
95
+ const migrationPromise = (specifier => new Promise(r => r(`${specifier}`)).then(s => _interopRequireWildcard(require(s))))(path || '');
96
+ return {
97
+ name: nameWithoutExtension,
98
+ up: async () => {
99
+ (0, _report.reportDebug)({
100
+ namespace,
101
+ message: `Running migration: ${nameWithoutExtension}`
102
+ });
103
+ const migration = await migrationPromise;
104
+ return migration.up(context);
105
+ },
106
+ down: async () => {
107
+ const migration = await migrationPromise;
108
+ return migration.down(context);
109
+ }
110
+ };
111
+ }
112
+ },
113
+ context: _Sequelize.sequelize.getQueryInterface(),
114
+ storage: new _umzug.SequelizeStorage({
115
+ sequelize: _Sequelize.sequelize
116
+ }),
117
+ logger: console
118
+ });
119
+ (0, _report.reportDebug)({
120
+ namespace,
121
+ message: 'Starting pending database migrations',
122
+ data: {
123
+ path
124
+ }
125
+ });
126
+ await migrator.up();
127
+ (0, _report.reportInfo)({
128
+ message: 'Database migration completed successfully',
129
+ data: {
130
+ path
131
+ }
132
+ });
133
+ }
134
+ } catch (error) {
92
135
  (0, _report.reportDebug)({
93
136
  namespace,
94
- message: 'Starting pending database migrations',
95
- data: {
96
- path
97
- }
98
- });
99
- await migrator.up();
100
- (0, _report.reportInfo)({
101
- message: 'Database migration completed successfully',
137
+ message: 'Migration failed with error',
102
138
  data: {
103
- path
139
+ error: error instanceof Error ? error.message : String(error),
140
+ stack: error instanceof Error ? error.stack : undefined,
141
+ sqlHost: process.env.SQL_HOST,
142
+ sqlDb: process.env.SQL_DB
104
143
  }
105
144
  });
145
+ throw error;
106
146
  }
107
147
  }
108
148
 
@@ -1 +1 @@
1
- {"version":3,"file":"dbMigration.js","names":["_fs","require","_path","_umzug","_migrateMetadataTable","_models","_EngineError","_Sequelize","_report","_semverCompare","_interopRequireWildcard","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","namespace","getMigrationPaths","prodDefaultPath","join","process","cwd","devDefaultPath","path","env","DB_MIGRATIONS_DIR","NODE_ENV","filter","existsSync","lstatSync","isDirectory","reportDebug","message","data","prodPath","devPath","customPath","map","p","runPendingMigrations","sequelize","EngineError","migrateMetadataTable","migrationPaths","length","migrator","Umzug","migrations","glob","resolve","name","context","nameWithoutExtension","replace","migrationPromise","specifier","Promise","then","s","up","migration","down","getQueryInterface","storage","SequelizeStorage","logger","console","reportInfo","rollbackMigrations","BUILD_ID","SequelizeMeta","findAll","order","raw","rollbackUntil","find","version","semverCompare","buildId","to","testRecreateDB","options","query","SQL_TYPE","clean","testClearDB","transaction","clearDbTransaction","model","keys","models","includeMetadata","table","tableName"],"sources":["../../../src/utils/dbMigration/dbMigration.ts"],"sourcesContent":["import { existsSync, lstatSync } from 'fs';\nimport { join } from 'path';\nimport { Sequelize, Transaction } from 'sequelize';\nimport { Umzug, SequelizeStorage } from 'umzug';\nimport { ClearDbOptions, RecreateDbOptions } from './dbMigration.types';\nimport { migrateMetadataTable } from './migrateMetadataTable';\nimport { SequelizeMeta } from 'db/models';\nimport { EngineError } from 'entities/EngineError';\nimport { sequelize } from 'entities/Sequelize';\nimport { reportDebug, reportInfo } from 'utils/report';\nimport { semverCompare } from 'utils/semverCompare';\n\nconst namespace = 'engine:utils:dbMigration';\n\nfunction getMigrationPaths(): Array<string> | undefined {\n // We look between possibilities for the first directory that exists and matches our expectations\n // First a user specified one, then the production default, then the development default\n const prodDefaultPath = join(process.cwd(), './dist/db/migrations');\n const devDefaultPath = join(process.cwd(), './src/db/migrations');\n const path = [\n process.env.DB_MIGRATIONS_DIR,\n process.env.NODE_ENV === 'prod' ? prodDefaultPath : devDefaultPath\n ].filter((path) => path && existsSync(path) && lstatSync(path).isDirectory());\n reportDebug({\n namespace,\n message: 'Obtaining Umzug migration options',\n data: {\n path,\n prodPath: prodDefaultPath,\n devPath: devDefaultPath,\n customPath: process.env.DB_MIGRATIONS_DIR\n }\n });\n return path.map((p) =>\n process.env.NODE_ENV === 'prod' ? `${p}/*.js` : `${p}/*.ts`\n );\n}\n\n/** Run all the non-executed migrations one by one */\nexport async function runPendingMigrations(): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n // First make sure that the metadata table is up to date\n await migrateMetadataTable(sequelize);\n const migrationPaths = getMigrationPaths();\n\n if (!migrationPaths || migrationPaths.length <= 0) {\n reportDebug({\n namespace,\n message: 'No valid migration paths found.',\n data: { migrationPaths }\n });\n return;\n }\n\n // Process migrations sequentially to avoid race conditions\n for (const path of migrationPaths) {\n const migrator = new Umzug({\n migrations: {\n glob: path,\n resolve: ({ name, path, context }) => {\n const nameWithoutExtension = name.replace(/\\.(ts|js)$/, '');\n \n // Use dynamic import for better TypeScript/ES module support\n const migrationPromise = import(path || '');\n return {\n name: nameWithoutExtension,\n up: async () => {\n const migration = await migrationPromise;\n return migration.up(context);\n },\n down: async () => {\n const migration = await migrationPromise;\n return migration.down(context);\n }\n };\n }\n },\n context: sequelize.getQueryInterface(),\n storage: new SequelizeStorage({ sequelize }),\n logger: console\n });\n\n reportDebug({\n namespace,\n message: 'Starting pending database migrations',\n data: { path }\n });\n await migrator.up();\n reportInfo({\n message: 'Database migration completed successfully',\n data: { path }\n });\n }\n}\n\n/** Rollback all migrations up to a specified target version */\nexport async function rollbackMigrations(): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n if (!process.env.BUILD_ID)\n throw new EngineError({ message: 'BUILD_ID is not defined' });\n\n // Fetch executed migrations in ascending order\n const migrations = await SequelizeMeta.findAll({\n order: [['name', 'ASC']],\n raw: true\n });\n const rollbackUntil = migrations.find(\n (migration) =>\n migration.version &&\n semverCompare(migration.version, process.env.BUILD_ID as string) === 1\n );\n\n if (!rollbackUntil) {\n reportDebug({\n namespace,\n message: 'No rollback target found for the current BUILD_ID.',\n data: { buildId: process.env.BUILD_ID }\n });\n return;\n }\n\n const migrationPaths = getMigrationPaths();\n\n if (!migrationPaths || migrationPaths.length <= 0) {\n reportDebug({\n namespace,\n message: 'No valid migration paths found for rollback.',\n data: { migrationPaths }\n });\n return;\n }\n\n // Process rollback migrations sequentially\n for (const path of migrationPaths) {\n const migrator = new Umzug({\n migrations: {\n glob: path,\n resolve: ({ name, path, context }) => {\n // Strip file extension to ensure consistent naming across .ts and .js files\n const nameWithoutExtension = name.replace(/\\.(ts|js)$/, '');\n \n const migrationPromise = import(path || '');\n return {\n name: nameWithoutExtension,\n up: async () => {\n const migration = await migrationPromise;\n return migration.up(context);\n },\n down: async () => {\n const migration = await migrationPromise;\n return migration.down(context);\n }\n };\n }\n },\n context: sequelize.getQueryInterface(),\n storage: new SequelizeStorage({ sequelize }),\n logger: console\n });\n\n reportDebug({\n namespace,\n message: `Rolling back migrations up to: ${rollbackUntil.name}`,\n data: { path }\n });\n\n await migrator.down({ to: rollbackUntil.name });\n }\n}\n\n/**\n * Recreate the whole database\n * Quick way to make sure that we are working on a clean database\n * /!\\ Should only be used when running tests\n */\nexport async function testRecreateDB(\n options: RecreateDbOptions = {}\n): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n await sequelize.query(\n `DROP SCHEMA public${process.env.SQL_TYPE === 'postgres' ? ' CASCADE' : ''}`\n );\n await sequelize.query(`CREATE SCHEMA public`);\n if (!options.clean) await runPendingMigrations();\n}\n\n/**\n * Empty all the schemas in the database\n * Quick way to flush the database data while keep the structure\n * /!\\ Should only be used when running tests\n */\nexport async function testClearDB(options: ClearDbOptions = {}): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n await sequelize.transaction(clearDbTransaction(sequelize, options));\n}\n\n/** DB clearing transaction */\nfunction clearDbTransaction(sequelize: Sequelize, options: ClearDbOptions) {\n return async (t: Transaction): Promise<void> => {\n for (const model of Object.keys(sequelize.models)) {\n // We ignore the migration metadata schema\n if (!options.includeMetadata && model === 'sequelizeMeta') continue;\n const table = sequelize.models[model].tableName;\n await sequelize.query(\n `TRUNCATE ${table}${process.env.SQL_TYPE === 'postgres' ? ' CASCADE' : ''};`,\n {\n raw: true,\n transaction: t\n }\n );\n }\n };\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"dbMigration.js","names":["_fs","require","_path","_umzug","_migrateMetadataTable","_models","_EngineError","_Sequelize","_report","_semverCompare","_interopRequireWildcard","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","namespace","getMigrationPaths","prodDefaultPath","join","process","cwd","devDefaultPath","path","env","DB_MIGRATIONS_DIR","NODE_ENV","filter","existsSync","lstatSync","isDirectory","reportDebug","message","data","prodPath","devPath","customPath","map","p","runPendingMigrations","sequelize","EngineError","sqlHost","SQL_HOST","sqlDb","SQL_DB","sqlUser","SQL_USER","nodeEnv","migrateMetadataTable","migrationPaths","length","migrator","Umzug","migrations","glob","resolve","name","context","nameWithoutExtension","replace","migrationPromise","specifier","Promise","then","s","up","migration","down","getQueryInterface","storage","SequelizeStorage","logger","console","reportInfo","error","Error","String","stack","undefined","rollbackMigrations","BUILD_ID","SequelizeMeta","findAll","order","raw","rollbackUntil","find","version","semverCompare","buildId","to","testRecreateDB","options","query","SQL_TYPE","clean","testClearDB","transaction","clearDbTransaction","model","keys","models","includeMetadata","table","tableName"],"sources":["../../../src/utils/dbMigration/dbMigration.ts"],"sourcesContent":["import { existsSync, lstatSync } from 'fs';\nimport { join } from 'path';\nimport { Sequelize, Transaction } from 'sequelize';\nimport { Umzug, SequelizeStorage } from 'umzug';\nimport { ClearDbOptions, RecreateDbOptions } from './dbMigration.types';\nimport { migrateMetadataTable } from './migrateMetadataTable';\nimport { SequelizeMeta } from 'db/models';\nimport { EngineError } from 'entities/EngineError';\nimport { sequelize } from 'entities/Sequelize';\nimport { reportDebug, reportInfo } from 'utils/report';\nimport { semverCompare } from 'utils/semverCompare';\n\nconst namespace = 'engine:utils:dbMigration';\n\nfunction getMigrationPaths(): Array<string> | undefined {\n // We look between possibilities for the first directory that exists and matches our expectations\n // First a user specified one, then the production default, then the development default\n const prodDefaultPath = join(process.cwd(), './dist/db/migrations');\n const devDefaultPath = join(process.cwd(), './src/db/migrations');\n const path = [\n process.env.DB_MIGRATIONS_DIR,\n process.env.NODE_ENV === 'prod' ? prodDefaultPath : devDefaultPath\n ].filter((path) => path && existsSync(path) && lstatSync(path).isDirectory());\n reportDebug({\n namespace,\n message: 'Obtaining Umzug migration options',\n data: {\n path,\n prodPath: prodDefaultPath,\n devPath: devDefaultPath,\n customPath: process.env.DB_MIGRATIONS_DIR\n }\n });\n return path.map((p) =>\n process.env.NODE_ENV === 'prod' ? `${p}/*.js` : `${p}/*.ts`\n );\n}\n\n/** Run all the non-executed migrations one by one */\nexport async function runPendingMigrations(): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n \n try {\n reportDebug({\n namespace,\n message: 'Starting migration process',\n data: {\n sqlHost: process.env.SQL_HOST,\n sqlDb: process.env.SQL_DB,\n sqlUser: process.env.SQL_USER,\n nodeEnv: process.env.NODE_ENV\n }\n });\n\n // First make sure that the metadata table is up to date\n reportDebug({\n namespace,\n message: 'Migrating metadata table'\n });\n await migrateMetadataTable(sequelize);\n \n const migrationPaths = getMigrationPaths();\n\n if (!migrationPaths || migrationPaths.length <= 0) {\n reportDebug({\n namespace,\n message: 'No valid migration paths found.',\n data: { migrationPaths }\n });\n return;\n }\n\n // Process migrations sequentially to avoid race conditions\n for (const path of migrationPaths) {\n reportDebug({\n namespace,\n message: 'Processing migration path',\n data: { path }\n });\n\n const migrator = new Umzug({\n migrations: {\n glob: path,\n resolve: ({ name, path, context }) => {\n const nameWithoutExtension = name.replace(/\\.(ts|js)$/, '');\n \n // Use dynamic import for better TypeScript/ES module support\n const migrationPromise = import(path || '');\n return {\n name: nameWithoutExtension,\n up: async () => {\n reportDebug({\n namespace,\n message: `Running migration: ${nameWithoutExtension}`\n });\n const migration = await migrationPromise;\n return migration.up(context);\n },\n down: async () => {\n const migration = await migrationPromise;\n return migration.down(context);\n }\n };\n }\n },\n context: sequelize.getQueryInterface(),\n storage: new SequelizeStorage({ sequelize }),\n logger: console\n });\n\n reportDebug({\n namespace,\n message: 'Starting pending database migrations',\n data: { path }\n });\n \n await migrator.up();\n \n reportInfo({\n message: 'Database migration completed successfully',\n data: { path }\n });\n }\n } catch (error) {\n reportDebug({\n namespace,\n message: 'Migration failed with error',\n data: {\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n sqlHost: process.env.SQL_HOST,\n sqlDb: process.env.SQL_DB\n }\n });\n throw error;\n }\n}\n\n/** Rollback all migrations up to a specified target version */\nexport async function rollbackMigrations(): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n if (!process.env.BUILD_ID)\n throw new EngineError({ message: 'BUILD_ID is not defined' });\n\n // Fetch executed migrations in ascending order\n const migrations = await SequelizeMeta.findAll({\n order: [['name', 'ASC']],\n raw: true\n });\n const rollbackUntil = migrations.find(\n (migration) =>\n migration.version &&\n semverCompare(migration.version, process.env.BUILD_ID as string) === 1\n );\n\n if (!rollbackUntil) {\n reportDebug({\n namespace,\n message: 'No rollback target found for the current BUILD_ID.',\n data: { buildId: process.env.BUILD_ID }\n });\n return;\n }\n\n const migrationPaths = getMigrationPaths();\n\n if (!migrationPaths || migrationPaths.length <= 0) {\n reportDebug({\n namespace,\n message: 'No valid migration paths found for rollback.',\n data: { migrationPaths }\n });\n return;\n }\n\n // Process rollback migrations sequentially\n for (const path of migrationPaths) {\n const migrator = new Umzug({\n migrations: {\n glob: path,\n resolve: ({ name, path, context }) => {\n // Strip file extension to ensure consistent naming across .ts and .js files\n const nameWithoutExtension = name.replace(/\\.(ts|js)$/, '');\n \n const migrationPromise = import(path || '');\n return {\n name: nameWithoutExtension,\n up: async () => {\n const migration = await migrationPromise;\n return migration.up(context);\n },\n down: async () => {\n const migration = await migrationPromise;\n return migration.down(context);\n }\n };\n }\n },\n context: sequelize.getQueryInterface(),\n storage: new SequelizeStorage({ sequelize }),\n logger: console\n });\n\n reportDebug({\n namespace,\n message: `Rolling back migrations up to: ${rollbackUntil.name}`,\n data: { path }\n });\n\n await migrator.down({ to: rollbackUntil.name });\n }\n}\n\n/**\n * Recreate the whole database\n * Quick way to make sure that we are working on a clean database\n * /!\\ Should only be used when running tests\n */\nexport async function testRecreateDB(\n options: RecreateDbOptions = {}\n): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n await sequelize.query(\n `DROP SCHEMA public${process.env.SQL_TYPE === 'postgres' ? ' CASCADE' : ''}`\n );\n await sequelize.query(`CREATE SCHEMA public`);\n if (!options.clean) await runPendingMigrations();\n}\n\n/**\n * Empty all the schemas in the database\n * Quick way to flush the database data while keep the structure\n * /!\\ Should only be used when running tests\n */\nexport async function testClearDB(options: ClearDbOptions = {}): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n await sequelize.transaction(clearDbTransaction(sequelize, options));\n}\n\n/** DB clearing transaction */\nfunction clearDbTransaction(sequelize: Sequelize, options: ClearDbOptions) {\n return async (t: Transaction): Promise<void> => {\n for (const model of Object.keys(sequelize.models)) {\n // We ignore the migration metadata schema\n if (!options.includeMetadata && model === 'sequelizeMeta') continue;\n const table = sequelize.models[model].tableName;\n await sequelize.query(\n `TRUNCATE ${table}${process.env.SQL_TYPE === 'postgres' ? ' CASCADE' : ''};`,\n {\n raw: true,\n transaction: t\n }\n );\n }\n };\n}\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-server-engine",
3
- "version": "1.10.3",
3
+ "version": "1.10.4",
4
4
  "description": "Framework used to develop backend services. This package ships with a lot of features to standardize the creation of services, letting you focus on the business logic.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {