From a619733a08bfcbde2296180ff41331721824e66a Mon Sep 17 00:00:00 2001 From: Pringgosutono Date: Wed, 8 Oct 2025 13:12:00 +0700 Subject: [PATCH] cron tracks month --- config/dbConnCron.js | 74 +++++++++++++++ cron/ReverseGeocodeWorker.js | 5 +- cron/TripsWorker.js | 170 +++++++++++++++++++++++++++++++++++ models/GpsTracksModels.js | 16 ++++ package.json | 2 + pnpm-lock.yaml | 88 +++++++++++++++++- 6 files changed, 351 insertions(+), 4 deletions(-) create mode 100644 config/dbConnCron.js create mode 100644 cron/TripsWorker.js diff --git a/config/dbConnCron.js b/config/dbConnCron.js new file mode 100644 index 0000000..95bd18e --- /dev/null +++ b/config/dbConnCron.js @@ -0,0 +1,74 @@ +const mysql = require("mysql2") +const pool = mysql.createPool({ + host: process.env.DBHOST, + port: process.env.DBPORT, + user: process.env.DBUSER, + password: process.env.DBPASSWORD, + database: process.env.DATABASE, + connectionLimit: 100, + multipleStatements: true, + // waitForConnections: true, + maxIdle: 10, // max idle connections, the default value is the same as `connectionLimit` + idleTimeout: 60000, // idle connections timeout, in milliseconds, the default value 60000 + queueLimit: 50, + // enableKeepAlive: true, + // keepAliveInitialDelay: 0, +}) + +const connection = () => { + return new Promise((resolve, reject) => { + pool.getConnection((err, connection) => { + if (err) { + // Log the error and reject the promise + console.error("Error getting connection from pool:", err) + return reject(err) + } + const query = (sql, binding) => { + return new Promise((resolve, reject) => { + connection.query(sql, binding, (err, result) => { + if (err) { + // Log the query error for debugging + console.error("Error executing query:", err, { sql, binding }) + return reject(err) + } + resolve(result) + }) + }) + } + + const release = () => { + return new Promise((resolve, reject) => { + if (err) { + // Log error in release method if exists + console.error("Error during connection release:", err) + return reject(err) + } + resolve(connection.release()) + }) + } + + resolve({ + query, + release, + }) + }) + }) +} + +const query = (sql, binding) => { + return new Promise((resolve, reject) => { + pool.query(sql, binding, (err, result, fields) => { + if (err) { + // Log the error for debugging + console.error("Error executing pooled query:", err, { sql, binding }) + return reject(err) + } + resolve(result) + }) + }) +} +module.exports = { + pool, + connection, + query, +} diff --git a/cron/ReverseGeocodeWorker.js b/cron/ReverseGeocodeWorker.js index e3f74ab..8d0437b 100644 --- a/cron/ReverseGeocodeWorker.js +++ b/cron/ReverseGeocodeWorker.js @@ -28,6 +28,9 @@ const go = async () => { }) const urlBase = request.osm_reverse_geo.urlFull + // let tracks = []; + let tracks = await GpsTracksModels.get2ForReverseGeo(10) + function processTrack(track, i) { return (async () => { console.log("track:", track.id, track.device_id, track.latitude, track.longitude) @@ -288,8 +291,6 @@ const go = async () => { } })() } - // let tracks = []; - let tracks = await GpsTracksModels.get2ForReverseGeo(10) await Promise.allSettled(tracks.map(processTrack)) diff --git a/cron/TripsWorker.js b/cron/TripsWorker.js new file mode 100644 index 0000000..df61db0 --- /dev/null +++ b/cron/TripsWorker.js @@ -0,0 +1,170 @@ +const path = require("path") +require("dotenv").config({ path: path.resolve(__dirname, "../.env") }) + +const cron = require("node-cron") +const db = require("../config/dbConnCron") +const moment = require("moment") +const TIMEFIX = 25200 + +cron.schedule("0 0 * * * *", job) +// job() + +async function job() { + console.log("Monthly table job executed:", moment().format("YYYY-MM-DD HH:mm:ss")) + const currentDate = moment() + const lasYearDate = currentDate.clone().subtract(1, "years") + const databaseName = process.env.DATABASE + + for (let i = 0; i <= 14; i++) { + const targetMonth = lasYearDate.clone().add(i, "months") + const yy = targetMonth.format("YY") // Two-digit year + const mm = targetMonth.format("MM") // Two-digit month + const tableName = `tracks_${yy}${mm}` + + try { + // Check if table exists + console.log(`Checking existence of table '${tableName}'...`) + const checkQuery = ` + SELECT TABLE_NAME + FROM information_schema.TABLES + WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? + ` + const checkParams = [databaseName, tableName] + const existenceResult = await db.query(checkQuery, checkParams) + + if (existenceResult.length === 0) { + // Table does not exist; create it + const createQuery = ` + CREATE TABLE ${tableName} ( + id bigint NOT NULL AUTO_INCREMENT, + original_hex text, + protocol enum('gt06','tk119','smartphone') DEFAULT NULL, + action enum('login','heartbeat','location','alarm','other') DEFAULT NULL, + device_id varchar(16) DEFAULT NULL, + latitude double DEFAULT NULL, + longitude double DEFAULT NULL, + speed int DEFAULT NULL COMMENT 'km/h', + orientation int NOT NULL DEFAULT '0' COMMENT 'in 360 degrees', + ignition int NOT NULL DEFAULT '0' COMMENT 'pengapian. 1=>on, 2=>off, 3=>acc_low, 4=>acc_high', + stts_engine int NOT NULL DEFAULT '0' COMMENT '1=>idling, 2=>moving, 3=>stopping', + stts_gps int NOT NULL DEFAULT '0' COMMENT '1=>on, 2=>off', + length_gps int NOT NULL DEFAULT '0' COMMENT 'length of GPS information,', + pos_stlt_gps int NOT NULL DEFAULT '0' COMMENT 'quantity of positioning satellites', + pos_type_gps int NOT NULL DEFAULT '0' COMMENT 'GPS real-time/differential positioning. 1=>diff_positioning,2=>realtime_positioning', + is_pos_gps int NOT NULL DEFAULT '0' COMMENT 'GPS having been positioning or not. 1=>not,2=>positioning', + stts_gsm int NOT NULL DEFAULT '0' COMMENT '1=>no signal, 2=>extremely weak signal 3=>very weak signal, 4=>good signal, 5=>strong signal', + stts_oil_electricity int NOT NULL DEFAULT '0' COMMENT '1=>on, 2=>off', + stts_alarm int NOT NULL DEFAULT '0' COMMENT '1=>normal,2=>shock,3=>power_cut,4=>low_battery,5=>sos', + stts_charge int NOT NULL DEFAULT '0' COMMENT '1=>off,2=>on', + stts_acc int NOT NULL DEFAULT '0' COMMENT '1=>low,2=>high', + stts_volt int NOT NULL DEFAULT '0' COMMENT '1=>shutdown,2=>extreme_low_battery,3=>very_low_batter,4=>low_battery,5=>medium,6=>high,7=>very_high', + stts_switch int NOT NULL DEFAULT '0' COMMENT '1=>off, 2=>on', + stts_reverse_geo int NOT NULL DEFAULT '0' COMMENT '1=>success, 2=>not, 3=>error, 4=>lost', + pre_milleage double NOT NULL DEFAULT '0' COMMENT 'in km. distance from prev to now', + sum_milleage double NOT NULL DEFAULT '0' COMMENT 'in km. summary device milleage. calculated based on this device', + vhc_milleage double NOT NULL DEFAULT '0' COMMENT 'in km. summary vhc milleage. calculated based on vhc, every change vhc this will get last milleage on that vhc', + drv_milleage double NOT NULL DEFAULT '0' COMMENT 'in km. summary drv milleage. calculated based on drv, every change drv this will get last milleage on that drv', + vhc_id int NOT NULL DEFAULT '0', + drv_id int NOT NULL DEFAULT '0', + source int NOT NULL DEFAULT '1' COMMENT '1=>gps_tracker, 2=>smartphone', + crt int NOT NULL, + crt_format datetime NOT NULL, + crt_d int NOT NULL DEFAULT '0' COMMENT 'from device/terminal', + crt_d_format datetime DEFAULT NULL, + crt_s int NOT NULL DEFAULT '0' COMMENT 'from server (receive time)', + crt_s_format datetime DEFAULT NULL, + crt_device_raw bigint DEFAULT '0' COMMENT 'device raw time', + daily_trip_id int unsigned DEFAULT NULL, + PRIMARY KEY (id), + KEY tracks_device_id (device_id), + KEY tracks_vhc_id (vhc_id), + KEY tracks_drv_id (drv_id), + KEY idx_crt_d (crt_d), + KEY idx_vhc_crt_d (vhc_id,crt_d), + KEY idx_vhc_id_engine (vhc_id,stts_engine), + KEY idx_vhc_lat_long_crt (vhc_id,latitude,longitude,crt), + KEY idx_geo_stts_id (stts_reverse_geo,latitude,longitude,id), + KEY idx_gps_valid_geo (latitude,longitude,stts_reverse_geo), + KEY idx_gps_order (id), + KEY t_gps_tracks_latitude_IDX (latitude,longitude,vhc_id,crt_d,action) USING BTREE, + KEY t_gps_tracks_crt_s_IDX (crt_s,action) USING BTREE, + KEY t_gps_tracks_stts_reverse_geo_IDX (stts_reverse_geo,action,id,latitude,longitude) USING BTREE + ) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4; + ` + const createParams = [] // No parameters for this CREATE statement + await db.query(createQuery, createParams) + console.log(`Table '${tableName}' created successfully.`) + } else { + console.log(`Table '${tableName}' already exists.`) + } + } catch (error) { + console.error(`Error processing table '${tableName}':`, error.message) + } + } + // drop tables older than 12 months + const dropMonth = currentDate.clone().subtract(13, "months") + const dropYy = dropMonth.format("YY") + const dropMm = dropMonth.format("MM") + const dropTableName = `tracks_${dropYy}${dropMm}` + + try { + const dropQuery = `DROP TABLE IF EXISTS ${dropTableName}` + await db.query(dropQuery, []) + console.log(`Table '${dropTableName}' dropped successfully (if it existed).`) + } catch (error) { + console.error(`Error dropping table '${dropTableName}':`, error.message) + } + + // insert prev data (3 months ago) to history table + for (let i = 0; i <= 12; i++) { + const histMonth = lasYearDate.clone().add(i, "months") + const histYy = histMonth.format("YY") + const histMm = histMonth.format("MM") + const histTableName = `tracks_${histYy}${histMm}` + console.log(`Processing history insertion for table '${histTableName}'...`) + + try { + // const q1 = `SELECT count(*) jmlData FROM ${histTableName}` + // const r1 = await db.query(q1) + // const jmlData = r1[0].jmlData + // if (jmlData == 0) { + const startOfMonth = histMonth.clone().startOf("month").unix() - TIMEFIX + const endOfMonth = histMonth.clone().endOf("month").unix() - TIMEFIX + console.log( + `Inserting data into history table '${histTableName}' for records from ${startOfMonth} to ${endOfMonth}` + ) + + const q2 = ` + INSERT INTO ${histTableName} + SELECT *, null FROM t_gps_tracks a + WHERE + crt_d < ? AND crt_d >= ? + and action = 'location' + and not exists ( + select 1 from ${histTableName} b + where b.id = a.id + ) + ` + const d2 = [endOfMonth, startOfMonth] + const r2 = await db.query(q2, d2) + console.log(`Inserted ${r2.affectedRows} rows into '${histTableName}'`) + // } else { + // console.log(`Table '${histTableName}' already has data (${jmlData} rows). Skipping insertion.`) + // } + } catch (error) { + console.error(`Error inserting data into history table '${histTableName}':`, error.message) + } + } + console.log("Monthly table job completed.") +} + +async function tripGrouping() { + console.log("Trip grouping job executed:", moment().format("YYYY-MM-DD HH:mm:ss")) +} + +// Keep the process running +// console.log("Cron scheduler ") +process.on("SIGINT", () => { + console.log("Stopping cron scheduler...") + process.exit(0) +}) diff --git a/models/GpsTracksModels.js b/models/GpsTracksModels.js index 7ad5955..f519313 100755 --- a/models/GpsTracksModels.js +++ b/models/GpsTracksModels.js @@ -1,5 +1,6 @@ const db = require(`../config/dbMysqlConn`) const MysqlHelpers = require(`../library/LibMysqlHelper`) +const moment = require(`moment`) class GpsTracksModels { static DEFAULT_COUNTRY_ID = 1 @@ -186,6 +187,21 @@ class GpsTracksModels { ) } + if (logs.action == "location") { + const date = logs.crt_d + const mm = moment.unix(date).format("MM") + const yy = moment.unix(date).format("YY") + logs.id = resLogs.insertId + await MysqlHelpers.queryTrx( + conn, + ` + INSERT INTO tracks_${yy}${mm} + SET ? + `, + [logs] + ) + } + await MysqlHelpers.commit(conn) resolve({ type: "success", diff --git a/package.json b/package.json index 55a8f05..b5d591f 100755 --- a/package.json +++ b/package.json @@ -35,7 +35,9 @@ "moment": "^2.29.1", "morgan": "^1.10.0", "mysql": "^2.18.1", + "mysql2": "^3.15.1", "nanoid": "^3.3.1", + "node-cron": "^4.2.1", "nodemailer": "^6.7.2", "path": "^0.12.7", "udp-packet": "^2.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f7e21a9..a3e4d24 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,9 +71,15 @@ importers: mysql: specifier: ^2.18.1 version: 2.18.1 + mysql2: + specifier: ^3.15.1 + version: 3.15.1 nanoid: specifier: ^3.3.1 version: 3.3.11 + node-cron: + specifier: ^4.2.1 + version: 4.2.1 nodemailer: specifier: ^6.7.2 version: 6.10.1 @@ -522,6 +528,10 @@ packages: async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} + engines: {node: '>= 6.0.0'} + axios@0.25.0: resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==} @@ -931,6 +941,9 @@ packages: resolution: {integrity: sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==} engines: {node: '>=10'} + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -1032,6 +1045,10 @@ packages: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} + iconv-lite@0.7.0: + resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -1078,6 +1095,9 @@ packages: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -1199,9 +1219,17 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + lru-memoizer@2.3.0: resolution: {integrity: sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==} + lru.min@1.1.2: + resolution: {integrity: sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + luxon@3.7.1: resolution: {integrity: sha512-RkRWjA926cTvz5rAb1BqyWkKbbjzCGchDUIKMCUvNi17j6f6j8uHGDV82Aqcqtzd+icoYpELmG3ksgGiFNNcNg==} engines: {node: '>=12'} @@ -1304,10 +1332,18 @@ packages: msgpackr@1.11.5: resolution: {integrity: sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==} + mysql2@3.15.1: + resolution: {integrity: sha512-WZMIRZstT2MFfouEaDz/AGFnGi1A2GwaDe7XvKTdRJEYiAHbOrh4S3d8KFmQeh11U85G+BFjIvS1Di5alusZsw==} + engines: {node: '>= 8.0'} + mysql@2.18.1: resolution: {integrity: sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==} engines: {node: '>= 0.6'} + named-placeholders@1.1.3: + resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} + engines: {node: '>=12.0.0'} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1320,6 +1356,10 @@ packages: node-addon-api@5.1.0: resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} + node-cron@4.2.1: + resolution: {integrity: sha512-lgimEHPE/QDgFlywTd8yTR61ptugX3Qer29efeyWw2rv259HtGBNn1vZVmp8lB9uo9wC0t/AT4iGqXxia+CJFg==} + engines: {node: '>=6.0.0'} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -1596,6 +1636,9 @@ packages: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} + seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + serve-static@1.14.2: resolution: {integrity: sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==} engines: {node: '>= 0.8.0'} @@ -1636,6 +1679,10 @@ packages: resolution: {integrity: sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==} engines: {node: '>= 0.6'} + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + stack-trace@0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} @@ -2438,6 +2485,8 @@ snapshots: async@3.2.6: {} + aws-ssl-profiles@1.1.2: {} + axios@0.25.0: dependencies: follow-redirects: 1.15.11 @@ -2959,6 +3008,10 @@ snapshots: - supports-color optional: true + generate-function@2.3.1: + dependencies: + is-property: 1.0.2 + get-caller-file@2.0.5: optional: true @@ -3124,6 +3177,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.7.0: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: {} image-q@4.0.0: @@ -3183,6 +3240,8 @@ snapshots: is-obj@2.0.0: optional: true + is-property@1.0.2: {} + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -3334,18 +3393,21 @@ snapshots: long@4.0.0: optional: true - long@5.3.2: - optional: true + long@5.3.2: {} lru-cache@6.0.0: dependencies: yallist: 4.0.0 + lru-cache@7.18.3: {} + lru-memoizer@2.3.0: dependencies: lodash.clonedeep: 4.5.0 lru-cache: 6.0.0 + lru.min@1.1.2: {} + luxon@3.7.1: {} make-dir@3.1.0: @@ -3439,6 +3501,18 @@ snapshots: optionalDependencies: msgpackr-extract: 3.0.3 + mysql2@3.15.1: + dependencies: + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.7.0 + long: 5.3.2 + lru.min: 1.1.2 + named-placeholders: 1.1.3 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + mysql@2.18.1: dependencies: bignumber.js: 9.0.0 @@ -3446,12 +3520,18 @@ snapshots: safe-buffer: 5.1.2 sqlstring: 2.3.1 + named-placeholders@1.1.3: + dependencies: + lru-cache: 7.18.3 + nanoid@3.3.11: {} negotiator@0.6.3: {} node-addon-api@5.1.0: {} + node-cron@4.2.1: {} + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 @@ -3782,6 +3862,8 @@ snapshots: transitivePeerDependencies: - supports-color + seq-queue@0.0.5: {} + serve-static@1.14.2: dependencies: encodeurl: 1.0.2 @@ -3840,6 +3922,8 @@ snapshots: sqlstring@2.3.1: {} + sqlstring@2.3.3: {} + stack-trace@0.0.10: {} standard-as-callback@2.1.0: {}