diff --git a/deploy/api.sh b/deploy/api.sh deleted file mode 100755 index b107cd4c..00000000 --- a/deploy/api.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -export ANALYTICS_REPORTS_PATH=reports/api.json -export ANALYTICS_SCRIPT_NAME=api.sh - -$ANALYTICS_ROOT_PATH/bin/analytics-publisher --debug --write-to-database --agenciesFile=$ANALYTICS_ROOT_PATH/deploy/agencies.json diff --git a/deploy/cron.js b/deploy/cron.js deleted file mode 100644 index 36e5b758..00000000 --- a/deploy/cron.js +++ /dev/null @@ -1,120 +0,0 @@ -if (process.env.NODE_ENV !== "production") { - require("dotenv").config(); -} - -if (process.env.NEW_RELIC_APP_NAME) { - require("newrelic"); -} - -const maxListenersExceededWarning = require("max-listeners-exceeded-warning"); -maxListenersExceededWarning(); - -const spawn = require("child_process").spawn; -const logger = require("../src/logger").initialize(); - -logger.info("==================================="); -logger.info("=== STARTING ANALYTICS-REPORTER ==="); -logger.info(" Running /deploy/cron.js"); -logger.info("==================================="); - -const scriptRootPath = `${process.env.ANALYTICS_ROOT_PATH}/deploy`; - -const runScriptWithLogName = (scriptPath, scriptLoggingName) => { - logger.info(`Beginning: ${scriptLoggingName}`); - logger.info(`File path: ${scriptPath}`); - const childProcess = spawn(scriptPath); - - childProcess.stdout.on("data", (data) => { - // Writes logging output from child processes to console. - console.log(data.toString().trim()); - }); - - childProcess.stderr.on("data", (data) => { - // Writes error logging output from child processes to console. - console.log(data.toString().trim()); - }); - - childProcess.on("close", (code, signal) => { - logger.info(`${scriptLoggingName} closed with code: ${code}`); - if (signal) { - logger.info(`${scriptLoggingName} received signal: ${signal}`); - } - }); - - childProcess.on("exit", (code, signal) => { - logger.info(`${scriptLoggingName} exitted with code: ${code}`); - if (signal) { - logger.info(`${scriptLoggingName} received signal: ${signal}`); - } - }); - - childProcess.on("error", (err) => { - logger.info(`${scriptLoggingName} errored: ${err}`); - }); -}; - -const api_run = () => { - runScriptWithLogName(`${scriptRootPath}/api.sh`, "api.sh"); -}; - -const daily_run = () => { - runScriptWithLogName(`${scriptRootPath}/daily.sh`, "daily.sh"); -}; - -/*const hourly_run = () => { - runScriptWithLogName(`${scriptRootPath}/hourly.sh`, "hourly.sh"); -};*/ - -const realtime_run = () => { - runScriptWithLogName(`${scriptRootPath}/realtime.sh`, "realtime.sh"); -}; - -/** - * Daily and API reports run every morning at 10 AM UTC. - * This calculates the offset between now and then for the next scheduled run. - */ -const calculateNextDailyRunTimeOffset = () => { - const currentTime = new Date(); - const nextRunTime = new Date( - currentTime.getFullYear(), - currentTime.getMonth(), - currentTime.getDate() + 1, - 10 - currentTime.getTimezoneOffset() / 60, - ); - return (nextRunTime - currentTime) % (1000 * 60 * 60 * 24); -}; - -/** - * All scripts run immediately upon application start (with a 60 second delay - * between each so that they don't all run at once), then run again at intervals - * going forward. - */ -setTimeout(realtime_run, 1000 * 10); -// setTimeout(hourly_run, 1000 * 70); No hourly reports exist at this time. -setTimeout(daily_run, 1000 * 70); -setTimeout(api_run, 1000 * 130); - -// Daily and API recurring script run setup. -// Runs at 10 AM UTC, then every 24 hours afterwards -setTimeout(() => { - // Offset the daily script run by 30 seconds so that it never runs in parallel - // with the realtime script in order to save memory/CPU. - setTimeout(() => { - daily_run(); - setInterval(daily_run, 1000 * 60 * 60 * 24); - }, 1000 * 30); - - // setTimeout(hourly_run, 1000 * 60); - - // Offset the API script run by 90 seconds so that it never runs in parallel - // with the daily or realtime scripts in order to save memory/CPU. - setTimeout(() => { - api_run(); - setInterval(api_run, 1000 * 60 * 60 * 24); - }, 1000 * 90); -}, calculateNextDailyRunTimeOffset()); -// hourly (no hourly reports exist at this time). -// setInterval(hourly_run, 1000 * 60 * 60); - -// Realtime recurring script run setup. Runs every 15 minutes. -setInterval(realtime_run, 1000 * 60 * 15); diff --git a/deploy/daily.sh b/deploy/daily.sh deleted file mode 100755 index cbe9415a..00000000 --- a/deploy/daily.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -export ANALYTICS_SCRIPT_NAME=daily.sh - -$ANALYTICS_ROOT_PATH/bin/analytics-publisher --publish --frequency=daily --slim --debug --csv --json --agenciesFile=$ANALYTICS_ROOT_PATH/deploy/agencies.json - diff --git a/deploy/hourly.sh b/deploy/hourly.sh deleted file mode 100755 index 407e4d24..00000000 --- a/deploy/hourly.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -export ANALYTICS_SCRIPT_NAME=hourly.sh - -$ANALYTICS_ROOT_PATH/bin/analytics-publisher --publish --frequency=hourly --slim --debug --json --agenciesFile=$ANALYTICS_ROOT_PATH/deploy/agencies.json diff --git a/deploy/publisher.js b/deploy/publisher.js new file mode 100644 index 00000000..9a689eef --- /dev/null +++ b/deploy/publisher.js @@ -0,0 +1,46 @@ +if (process.env.NODE_ENV !== "production") { + require("dotenv").config(); +} + +if (process.env.NEW_RELIC_APP_NAME) { + require("newrelic"); +} + +const logger = require("../src/logger").initialize(); +logger.info("==================================="); +logger.info("=== STARTING ANALYTICS-REPORTER ==="); +logger.info(" Running /deploy/publisher.js"); +logger.info("==================================="); + +// Job Scheduler +const Bree = require("bree"); +const bree = new Bree({ + logger, + jobs: [ + // Runs `../jobs/realtime.js` 1 millisecond after the process starts and + // then every 15 minutes going forward. + { + name: "realtime", + timeout: "1", + interval: "15m", + }, + // Runs `../jobs/daily.js` 1 minute after the process starts and then at + // 10:01 AM every day going forward. + { + name: "daily", + timeout: "1m", + interval: "at 10:01 am", + }, + // Runs `../jobs/api.js` 2 minutes after the process starts and then at + // 10:02 AM every day going forward. + { + name: "api", + timeout: "2m", + interval: "at 10:02 am", + }, + ], +}); + +(async () => { + await bree.start(); +})(); diff --git a/deploy/realtime.sh b/deploy/realtime.sh deleted file mode 100755 index 10ca0f8c..00000000 --- a/deploy/realtime.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -export ANALYTICS_SCRIPT_NAME=realtime.sh - -$ANALYTICS_ROOT_PATH/bin/analytics-publisher --publish --frequency=realtime --slim --debug --csv --json --agenciesFile=$ANALYTICS_ROOT_PATH/deploy/agencies.json diff --git a/jobs/api.js b/jobs/api.js new file mode 100644 index 00000000..ce9b5742 --- /dev/null +++ b/jobs/api.js @@ -0,0 +1,27 @@ +process.env.ANALYTICS_REPORTS_PATH = "reports/api.json"; +process.env.ANALYTICS_SCRIPT_NAME = "api.js"; + +const { runQueuePublish } = require("../index.js"); +const options = { + publish: true, + frequency: "daily", + slim: true, + debug: true, + csv: true, + json: true, + agenciesFile: `${process.env.ANALYTICS_ROOT_PATH}/deploy/agencies.json`, +}; +const logger = require("../src/logger.js").initialize(); + +(async () => { + logger.info(`Beginning job: ${process.env.ANALYTICS_SCRIPT_NAME}`); + + try { + await runQueuePublish(options); + logger.info(`Job completed: ${process.env.ANALYTICS_SCRIPT_NAME}`); + } catch (e) { + logger.error(`Job exited with error: ${process.env.ANALYTICS_SCRIPT_NAME}`); + logger.error(e); + throw e; + } +})(); diff --git a/jobs/daily.js b/jobs/daily.js new file mode 100644 index 00000000..1a7429a0 --- /dev/null +++ b/jobs/daily.js @@ -0,0 +1,27 @@ +process.env.ANALYTICS_REPORTS_PATH = "reports/usa.json"; +process.env.ANALYTICS_SCRIPT_NAME = "daily.js"; + +const { runQueuePublish } = require("../index.js"); +const options = { + publish: true, + frequency: "daily", + slim: true, + debug: true, + csv: true, + json: true, + agenciesFile: `${process.env.ANALYTICS_ROOT_PATH}/deploy/agencies.json`, +}; +const logger = require("../src/logger.js").initialize(); + +(async () => { + logger.info(`Beginning job: ${process.env.ANALYTICS_SCRIPT_NAME}`); + + try { + await runQueuePublish(options); + logger.info(`Job completed: ${process.env.ANALYTICS_SCRIPT_NAME}`); + } catch (e) { + logger.error(`Job exited with error: ${process.env.ANALYTICS_SCRIPT_NAME}`); + logger.error(e); + throw e; + } +})(); diff --git a/jobs/realtime.js b/jobs/realtime.js new file mode 100644 index 00000000..bb0425d8 --- /dev/null +++ b/jobs/realtime.js @@ -0,0 +1,27 @@ +process.env.ANALYTICS_REPORTS_PATH = "reports/usa.json"; +process.env.ANALYTICS_SCRIPT_NAME = "realtime.js"; + +const { runQueuePublish } = require("../index.js"); +const options = { + publish: true, + frequency: "realtime", + slim: true, + debug: true, + csv: true, + json: true, + agenciesFile: `${process.env.ANALYTICS_ROOT_PATH}/deploy/agencies.json`, +}; +const logger = require("../src/logger.js").initialize(); + +(async () => { + logger.info(`Beginning job: ${process.env.ANALYTICS_SCRIPT_NAME}`); + + try { + await runQueuePublish(options); + logger.info(`Job completed: ${process.env.ANALYTICS_SCRIPT_NAME}`); + } catch (e) { + logger.error(`Job exited with error: ${process.env.ANALYTICS_SCRIPT_NAME}`); + logger.error(e); + throw e; + } +})(); diff --git a/manifest.publisher.yml b/manifest.publisher.yml index f916a61a..88ecd9aa 100644 --- a/manifest.publisher.yml +++ b/manifest.publisher.yml @@ -9,7 +9,7 @@ applications: health-check-type: process buildpacks: - nodejs_buildpack - command: node deploy/cron.js + command: node deploy/publisher.js env: ANALYTICS_DEBUG: 'true' ANALYTICS_LOG_LEVEL: ${ANALYTICS_LOG_LEVEL} diff --git a/package-lock.json b/package-lock.json index 67f9c51b..db662bd3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@google-analytics/data": "^4.12.0", "@smithy/node-http-handler": "^3.0.0", "@snyk/protect": "^1.1269.0", + "bree": "^9.2.4", "fast-csv": "^4.3.6", "googleapis": "^140.0.0", "max-listeners-exceeded-warning": "^0.0.1", @@ -1235,6 +1236,18 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.25.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", @@ -1290,6 +1303,15 @@ "node": ">=6.9.0" } }, + "node_modules/@breejs/later": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@breejs/later/-/later-4.2.0.tgz", + "integrity": "sha512-EVMD0SgJtOuFeg0lAVbCwa+qeTKILb87jqvLyUtQswGD9+ce2nB52Y5zbTF1Hc0MDFfbydcMcxb47jSdhikVHA==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -2930,6 +2952,12 @@ "@types/node": "*" } }, + "node_modules/@types/lodash": { + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.14.tgz", + "integrity": "sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==", + "license": "MIT" + }, "node_modules/@types/long": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", @@ -3304,6 +3332,13 @@ "readable-stream": "^3.4.0" } }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT" + }, "node_modules/bowser": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", @@ -3331,6 +3366,33 @@ "node": ">=8" } }, + "node_modules/bree": { + "version": "9.2.4", + "resolved": "https://registry.npmjs.org/bree/-/bree-9.2.4.tgz", + "integrity": "sha512-3GDVYbRYxPIIKgqu00FlIDD//q/0XkMC+zq74sp/qRRQQUWdc39lsFkdHW2g2lTlhaxbqkHd97p8oRMm/YeSJw==", + "license": "MIT", + "dependencies": { + "@breejs/later": "^4.2.0", + "boolean": "^3.2.0", + "combine-errors": "^3.0.3", + "cron-validate": "^1.4.5", + "human-interval": "^2.0.1", + "is-string-and-not-blank": "^0.0.2", + "is-valid-path": "^0.1.1", + "ms": "^2.1.3", + "p-wait-for": "3", + "safe-timers": "^1.1.0" + }, + "engines": { + "node": ">=12.17.0 <13.0.0-0||>=13.2.0" + } + }, + "node_modules/bree/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -3774,6 +3836,15 @@ "text-hex": "1.0.x" } }, + "node_modules/combine-errors": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/combine-errors/-/combine-errors-3.0.3.tgz", + "integrity": "sha512-C8ikRNRMygCwaTx+Ek3Yr+OuZzgZjduCOfSQBjbM8V3MfgcjSTeto/GXP6PAwKvJz/v15b7GHZvx5rOlczFw/Q==", + "dependencies": { + "custom-error-instance": "2.1.1", + "lodash.uniqby": "4.5.0" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -3862,6 +3933,33 @@ "node": ">=12.0.0" } }, + "node_modules/cron-validate": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/cron-validate/-/cron-validate-1.4.5.tgz", + "integrity": "sha512-nKlOJEnYKudMn/aNyNH8xxWczlfpaazfWV32Pcx/2St51r2bxWbGhZD7uwzMcRhunA/ZNL+Htm/i0792Z59UMQ==", + "license": "MIT", + "dependencies": { + "yup": "0.32.9" + } + }, + "node_modules/cron-validate/node_modules/yup": { + "version": "0.32.9", + "resolved": "https://registry.npmjs.org/yup/-/yup-0.32.9.tgz", + "integrity": "sha512-Ci1qN+i2H0XpY7syDQ0k5zKQ/DoxO0LzPg8PAR/X4Mpj6DqaeCoIYEEjDJwhArh3Fa7GWbQQVDZKeXYlSH4JMg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.5", + "@types/lodash": "^4.14.165", + "lodash": "^4.17.20", + "lodash-es": "^4.17.15", + "nanoclone": "^0.2.1", + "property-expr": "^2.0.4", + "toposort": "^2.0.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3877,6 +3975,12 @@ "node": ">= 8" } }, + "node_modules/custom-error-instance": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/custom-error-instance/-/custom-error-instance-2.1.1.tgz", + "integrity": "sha512-p6JFxJc3M4OTD2li2qaHkDCw9SfMw82Ldr6OC9Je1aXiGfhx2W8p3GaoeaGrPJTUN9NirTM/KTxHWMUdR1rsUg==", + "license": "ISC" + }, "node_modules/data-uri-to-buffer": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", @@ -5436,6 +5540,15 @@ "node": ">= 14" } }, + "node_modules/human-interval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/human-interval/-/human-interval-2.0.1.tgz", + "integrity": "sha512-r4Aotzf+OtKIGQCB3odUowy4GfUDTy3aTWTfLd7ZF2gBCy3XW3v/dJLRefZnOFFnjqs5B1TypvS8WarpBkYUNQ==", + "license": "MIT", + "dependencies": { + "numbered": "^1.1.0" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -5728,6 +5841,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-string-and-not-blank": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/is-string-and-not-blank/-/is-string-and-not-blank-0.0.2.tgz", + "integrity": "sha512-FyPGAbNVyZpTeDCTXnzuwbu9/WpNXbCfbHXLpCRpN4GANhS00eEIP5Ef+k5HYSNIzIhdN9zRDoBj6unscECvtQ==", + "license": "MIT", + "dependencies": { + "is-string-blank": "^1.0.1" + }, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/is-string-blank": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-string-blank/-/is-string-blank-1.0.1.tgz", + "integrity": "sha512-9H+ZBCVs3L9OYqv8nuUAzpcT9OTgMD1yAWrG7ihlnibdkbtB850heAmYWxHuXc4CHy4lKeK69tN+ny1K7gBIrw==", + "license": "MIT" + }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -5746,6 +5877,51 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-valid-path": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-valid-path/-/is-valid-path-0.1.1.tgz", + "integrity": "sha512-+kwPrVDu9Ms03L90Qaml+79+6DZHqHyRoANI6IsZJ/g8frhnfchDOBCa0RbQ6/kdHt5CS5OeIEyrYznNuVN+8A==", + "license": "MIT", + "dependencies": { + "is-invalid-path": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-valid-path/node_modules/is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-valid-path/node_modules/is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-valid-path/node_modules/is-invalid-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-invalid-path/-/is-invalid-path-0.1.0.tgz", + "integrity": "sha512-aZMG0T3F34mTg4eTdszcGXx54oiZ4NtHSft3hWNJMGJXUUqdIj3cOZuHcU0nCWWcY3jd7yRe/3AEm3vSNTpBGQ==", + "license": "MIT", + "dependencies": { + "is-glob": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -6209,8 +6385,59 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "optional": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, + "node_modules/lodash._baseiteratee": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash._baseiteratee/-/lodash._baseiteratee-4.7.0.tgz", + "integrity": "sha512-nqB9M+wITz0BX/Q2xg6fQ8mLkyfF7MU7eE+MNBNjTHFKeKaZAPEzEg+E8LWxKWf1DQVflNEn9N49yAuqKh2mWQ==", + "license": "MIT", + "dependencies": { + "lodash._stringtopath": "~4.8.0" + } + }, + "node_modules/lodash._basetostring": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-4.12.0.tgz", + "integrity": "sha512-SwcRIbyxnN6CFEEK4K1y+zuApvWdpQdBHM/swxP962s8HIxPO3alBH5t3m/dl+f4CMUug6sJb7Pww8d13/9WSw==", + "license": "MIT" + }, + "node_modules/lodash._baseuniq": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz", + "integrity": "sha512-Ja1YevpHZctlI5beLA7oc5KNDhGcPixFhcqSiORHNsp/1QTv7amAXzw+gu4YOvErqVlMVyIJGgtzeepCnnur0A==", + "license": "MIT", + "dependencies": { + "lodash._createset": "~4.0.0", + "lodash._root": "~3.0.0" + } + }, + "node_modules/lodash._createset": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz", + "integrity": "sha512-GTkC6YMprrJZCYU3zcqZj+jkXkrXzq3IPBcF/fIPpNEAB4hZEtXU8zp/RwKOvZl43NUmwDbyRk3+ZTbeRdEBXA==", + "license": "MIT" + }, + "node_modules/lodash._root": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ==", + "license": "MIT" + }, + "node_modules/lodash._stringtopath": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/lodash._stringtopath/-/lodash._stringtopath-4.8.0.tgz", + "integrity": "sha512-SXL66C731p0xPDC5LZg4wI5H+dJo/EO4KTqOMwLYCH3+FmmfAKJEZCm6ohGpI+T1xwsDsJCfL4OnhorllvlTPQ==", + "license": "MIT", + "dependencies": { + "lodash._basetostring": "~4.12.0" + } }, "node_modules/lodash.camelcase": { "version": "4.3.0", @@ -6286,6 +6513,16 @@ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" }, + "node_modules/lodash.uniqby": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.5.0.tgz", + "integrity": "sha512-IRt7cfTtHy6f1aRVA5n7kT8rgN3N1nH6MOWLcHfpWG2SH19E3JksLK38MktLxZDhlAjCP9jpIXkOnRXlu6oByQ==", + "license": "MIT", + "dependencies": { + "lodash._baseiteratee": "~4.7.0", + "lodash._baseuniq": "~4.6.0" + } + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -6815,6 +7052,12 @@ "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", "optional": true }, + "node_modules/nanoclone": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz", + "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==", + "license": "MIT" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7060,6 +7303,12 @@ "node": ">=8" } }, + "node_modules/numbered": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/numbered/-/numbered-1.1.0.tgz", + "integrity": "sha512-pv/ue2Odr7IfYOO0byC1KgBI10wo5YDauLhxY6/saNzAdAs0r1SotGCPzzCLNPL0xtrAwWRialLu23AAu9xO1g==", + "license": "MIT" + }, "node_modules/nyc": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", @@ -7341,6 +7590,15 @@ "node": ">= 0.8.0" } }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -7401,6 +7659,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -7410,6 +7680,21 @@ "node": ">=6" } }, + "node_modules/p-wait-for": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-wait-for/-/p-wait-for-3.2.0.tgz", + "integrity": "sha512-wpgERjNkLrBiFmkMEjuZJEWKKDrNfHCKA1OhyN1wg1FrLkULbviEy6py1AyJUgZ72YWFbZ38FIpnqvVqAlDUwA==", + "license": "MIT", + "dependencies": { + "p-timeout": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/pac-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", @@ -7943,8 +8228,7 @@ "node_modules/property-expr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", - "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", - "dev": true + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==" }, "node_modules/proto3-json-serializer": { "version": "2.0.2", @@ -8230,6 +8514,12 @@ "deprecated": "This version has a critical bug in fallback handling. Please upgrade to reflect-metadata@0.2.2 or newer.", "dev": true }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, "node_modules/regexp-match-indices": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz", @@ -8466,6 +8756,12 @@ "node": ">=10" } }, + "node_modules/safe-timers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-timers/-/safe-timers-1.1.0.tgz", + "integrity": "sha512-9aqY+v5eMvmRaluUEtdRThV1EjlSElzO7HuCj0sTW9xvp++8iJ9t/RWGNWV6/WHcUJLHpyT2SNf/apoKTU2EpA==", + "license": "MIT" + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -9446,8 +9742,7 @@ "node_modules/toposort": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", - "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", - "dev": true + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" }, "node_modules/tr46": { "version": "0.0.3", diff --git a/package.json b/package.json index ef0a371b..c99c2b1a 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "@google-analytics/data": "^4.12.0", "@smithy/node-http-handler": "^3.0.0", "@snyk/protect": "^1.1269.0", + "bree": "^9.2.4", "fast-csv": "^4.3.6", "googleapis": "^140.0.0", "max-listeners-exceeded-warning": "^0.0.1",