From 5d047ff8036d283301c22232301fcaea71fef054 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Fri, 29 Sep 2023 10:42:18 -0400 Subject: [PATCH 01/18] feat: additional sync updates --- package-lock.json | 228 +++++++++++++--------- package.json | 3 + src/config/config.js | 3 + src/datalayer/persistance.js | 3 - src/datalayer/syncService.js | 4 +- src/models/projects/projects.model.js | 9 +- src/models/units/units.model.js | 9 +- src/tasks/index.js | 2 - src/tasks/sync-audit-table.js | 268 ++++++++++++++++++++------ 9 files changed, 356 insertions(+), 173 deletions(-) diff --git a/package-lock.json b/package-lock.json index 70284f98..acd1a2c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,9 @@ "version": "1.6.14", "dependencies": { "@babel/eslint-parser": "^7.22.9", + "@chia-carbon/core-registry-config": "^1.0.2", + "@chia-carbon/core-registry-logger": "^1.0.11", + "async-waterfall": "^0.1.5", "body-parser": "^1.20.2", "cli-spinner": "^0.2.10", "cors": "^2.8.5", @@ -125,27 +128,27 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz", - "integrity": "sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", + "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.0.tgz", - "integrity": "sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", + "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.22.13", "@babel/generator": "^7.23.0", "@babel/helper-compilation-targets": "^7.22.15", "@babel/helper-module-transforms": "^7.23.0", - "@babel/helpers": "^7.23.0", + "@babel/helpers": "^7.23.2", "@babel/parser": "^7.23.0", "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.0", + "@babel/traverse": "^7.23.2", "@babel/types": "^7.23.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -314,9 +317,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz", - "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz", + "integrity": "sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==", "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", @@ -529,12 +532,12 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.1.tgz", - "integrity": "sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", "dependencies": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.0", + "@babel/traverse": "^7.23.2", "@babel/types": "^7.23.0" }, "engines": { @@ -860,14 +863,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz", - "integrity": "sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.2.tgz", + "integrity": "sha512-BBYVGxbDVHfoeXbOwcagAkOQAm9NxoTdMGfTqghu1GrvadSaw6iW3Je6IcL5PNOw8VwjxqBECXy50/iCQSY/lQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.9", + "@babel/helper-remap-async-to-generator": "^7.22.20", "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { @@ -1617,12 +1620,12 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.20.tgz", - "integrity": "sha512-11MY04gGC4kSzlPHRfvVkNAZhUxOvm7DCJ37hPDnUENwe06npjIRAfInEMTGSb4LZK5ZgDFkv5hw0lGebHeTyg==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.2.tgz", + "integrity": "sha512-BW3gsuDD+rvHL2VO2SjAUNTBe5YrjsTiDyqamPDWY723na3/yPQ65X5oQkFVJZ0o50/2d+svm1rkPoJeR1KxVQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.22.20", + "@babel/compat-data": "^7.23.2", "@babel/helper-compilation-targets": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-option": "^7.22.15", @@ -1648,15 +1651,15 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.22.5", - "@babel/plugin-transform-async-generator-functions": "^7.22.15", + "@babel/plugin-transform-async-generator-functions": "^7.23.2", "@babel/plugin-transform-async-to-generator": "^7.22.5", "@babel/plugin-transform-block-scoped-functions": "^7.22.5", - "@babel/plugin-transform-block-scoping": "^7.22.15", + "@babel/plugin-transform-block-scoping": "^7.23.0", "@babel/plugin-transform-class-properties": "^7.22.5", "@babel/plugin-transform-class-static-block": "^7.22.11", "@babel/plugin-transform-classes": "^7.22.15", "@babel/plugin-transform-computed-properties": "^7.22.5", - "@babel/plugin-transform-destructuring": "^7.22.15", + "@babel/plugin-transform-destructuring": "^7.23.0", "@babel/plugin-transform-dotall-regex": "^7.22.5", "@babel/plugin-transform-duplicate-keys": "^7.22.5", "@babel/plugin-transform-dynamic-import": "^7.22.11", @@ -1668,9 +1671,9 @@ "@babel/plugin-transform-literals": "^7.22.5", "@babel/plugin-transform-logical-assignment-operators": "^7.22.11", "@babel/plugin-transform-member-expression-literals": "^7.22.5", - "@babel/plugin-transform-modules-amd": "^7.22.5", - "@babel/plugin-transform-modules-commonjs": "^7.22.15", - "@babel/plugin-transform-modules-systemjs": "^7.22.11", + "@babel/plugin-transform-modules-amd": "^7.23.0", + "@babel/plugin-transform-modules-commonjs": "^7.23.0", + "@babel/plugin-transform-modules-systemjs": "^7.23.0", "@babel/plugin-transform-modules-umd": "^7.22.5", "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", "@babel/plugin-transform-new-target": "^7.22.5", @@ -1679,7 +1682,7 @@ "@babel/plugin-transform-object-rest-spread": "^7.22.15", "@babel/plugin-transform-object-super": "^7.22.5", "@babel/plugin-transform-optional-catch-binding": "^7.22.11", - "@babel/plugin-transform-optional-chaining": "^7.22.15", + "@babel/plugin-transform-optional-chaining": "^7.23.0", "@babel/plugin-transform-parameters": "^7.22.15", "@babel/plugin-transform-private-methods": "^7.22.5", "@babel/plugin-transform-private-property-in-object": "^7.22.11", @@ -1696,10 +1699,10 @@ "@babel/plugin-transform-unicode-regex": "^7.22.5", "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", "@babel/preset-modules": "0.1.6-no-external-plugins", - "@babel/types": "^7.22.19", - "babel-plugin-polyfill-corejs2": "^0.4.5", - "babel-plugin-polyfill-corejs3": "^0.8.3", - "babel-plugin-polyfill-regenerator": "^0.5.2", + "@babel/types": "^7.23.0", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", "core-js-compat": "^3.31.0", "semver": "^6.3.1" }, @@ -1759,9 +1762,9 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.23.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.1.tgz", - "integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -1790,9 +1793,9 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz", - "integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dependencies": { "@babel/code-frame": "^7.22.13", "@babel/generator": "^7.23.0", @@ -1822,10 +1825,30 @@ "node": ">=6.9.0" } }, + "node_modules/@chia-carbon/core-registry-config": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@chia-carbon/core-registry-config/-/core-registry-config-1.0.3.tgz", + "integrity": "sha512-7bB+fihP0C/eRzTmDiOmbpLpfKYPjI0dN2074hbwmuIGgVHGMu12J2qt5Mae8pEWtkEIKk4517MJQTtWx8GmPw==", + "dependencies": { + "chia-root-resolver": "^1.0.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21" + } + }, + "node_modules/@chia-carbon/core-registry-logger": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@chia-carbon/core-registry-logger/-/core-registry-logger-1.0.12.tgz", + "integrity": "sha512-emeAXaKdqohjXXFwpDGkJbmeU4nIOSxtoqbVBARveSy1G8z3fgeK7lekm+4qmMtKPxv0Rmvy24UGT86WwaRj+w==", + "dependencies": { + "chia-root-resolver": "^1.0.0", + "winston": "^3.10.0", + "winston-daily-rotate-file": "^4.7.1" + } + }, "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", "engines": { "node": ">=0.1.90" } @@ -2419,9 +2442,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", - "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", + "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -2752,9 +2775,9 @@ "dev": true }, "node_modules/@types/chai": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.6.tgz", - "integrity": "sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==", + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.8.tgz", + "integrity": "sha512-yW/qTM4mRBBcsA9Xw9FbcImYtFPY7sgr+G/O5RDYVmxiy9a+pE5FyoFUi8JYCZY5nicj8atrr1pcfPiYpeNGOA==", "dev": true }, "node_modules/@types/cookie": { @@ -3082,6 +3105,11 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" }, + "node_modules/async-waterfall": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/async-waterfall/-/async-waterfall-0.1.5.tgz", + "integrity": "sha512-aJXVeDPYaXZUw/lfkeEK13OLSxHO4AZWA2so1Q0n4ey3ix26rWzSCzl4hnkJvolA12MvmUF8covY8bZvKjbtmA==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -3144,13 +3172,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz", - "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==", + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz", + "integrity": "sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==", "dev": true, "dependencies": { "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.4.2", + "@babel/helper-define-polyfill-provider": "^0.4.3", "semver": "^6.3.1" }, "peerDependencies": { @@ -3167,12 +3195,12 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.4.tgz", - "integrity": "sha512-9l//BZZsPR+5XjyJMPtZSK4jv0BsTO1zDac2GC6ygx9WLGlcsnRd1Co0B2zT5fF5Ic6BZy+9m3HNZ3QcOeDKfg==", + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.5.tgz", + "integrity": "sha512-Q6CdATeAvbScWPNLB8lzSO7fgUVBkQt6zLgNlfyeCr/EQaEQR+bWiBYYPYAFyE528BMjRhL+1QBMOI4jc/c5TA==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.2", + "@babel/helper-define-polyfill-provider": "^0.4.3", "core-js-compat": "^3.32.2" }, "peerDependencies": { @@ -3180,12 +3208,12 @@ } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz", - "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz", + "integrity": "sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.2" + "@babel/helper-define-polyfill-provider": "^0.4.3" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -3442,9 +3470,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001546", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz", - "integrity": "sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==", + "version": "1.0.30001547", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001547.tgz", + "integrity": "sha512-W7CrtIModMAxobGhz8iXmDfuJiiKg1WADMO/9x7/CLNin5cpSbuBjooyoIUVB5eyCc36QuTVlkVa1iB2S5+/eA==", "funding": [ { "type": "opencollective", @@ -3546,6 +3574,11 @@ "node": "*" } }, + "node_modules/chia-root-resolver": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/chia-root-resolver/-/chia-root-resolver-1.0.0.tgz", + "integrity": "sha512-oZOYbZxzK0688hU9S2EYWZ8ks5NI9zOlABFDsqBtvZwvYZbXEUYaLob+AqMhxLG3p0Dr0Ry+Rm6VPKOl9fQvAA==" + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -4728,9 +4761,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.543", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.543.tgz", - "integrity": "sha512-t2ZP4AcGE0iKCCQCBx/K2426crYdxD3YU6l0uK2EO3FZH0pbC4pFz/sZm2ruZsND6hQBTcDWWlo/MLpiOdif5g==" + "version": "1.4.552", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.552.tgz", + "integrity": "sha512-qMPzA5TEuOAbLFmbpNvO4qkBRe2B5dAxl6H4KxqRNy9cvBeHT2EyzecX0bumBfRhHN8cQJrx6NPd0AAoCCPKQw==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -4772,9 +4805,9 @@ } }, "node_modules/engine.io": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.2.tgz", - "integrity": "sha512-IXsMcGpw/xRfjra46sVZVHiSWo/nJ/3g1337q9KNXtS6YRzbW5yIzTCb9DjhrBe7r3GZQR0I4+nq+4ODk5g/cA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.3.tgz", + "integrity": "sha512-IML/R4eG/pUS5w7OfcDE0jKrljWS9nwnEfsxWCIJF5eO6AHo6+Hlv+lQbdlAYsiJPHzUthLm1RUjnBzWOs45cw==", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -4866,14 +4899,14 @@ } }, "node_modules/eslint": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", - "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", + "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.50.0", + "@eslint/js": "8.51.0", "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -5555,11 +5588,11 @@ } }, "node_modules/flat-cache": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", - "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", "dependencies": { - "flatted": "^3.2.7", + "flatted": "^3.2.9", "keyv": "^4.5.3", "rimraf": "^3.0.2" }, @@ -5671,9 +5704,12 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/gauge": { "version": "3.0.2", @@ -6628,9 +6664,9 @@ "dev": true }, "node_modules/keyv": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", - "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dependencies": { "json-buffer": "3.0.1" } @@ -6925,6 +6961,14 @@ "triple-beam": "^1.3.0" } }, + "node_modules/logform/node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -8736,9 +8780,9 @@ "dev": true }, "node_modules/resolve": { - "version": "1.22.6", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", - "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { "is-core-module": "^2.13.0", @@ -10234,11 +10278,11 @@ } }, "node_modules/winston": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.10.0.tgz", - "integrity": "sha512-nT6SIDaE9B7ZRO0u3UvdrimG0HkB7dSTAgInQnNR2SOPJ4bvq5q79+pXLftKmP52lJGW15+H5MCK0nM9D3KB/g==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", + "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", "dependencies": { - "@colors/colors": "1.5.0", + "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", diff --git a/package.json b/package.json index cfedbb80..babf3acf 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,9 @@ }, "dependencies": { "@babel/eslint-parser": "^7.22.9", + "@chia-carbon/core-registry-config": "^1.0.2", + "@chia-carbon/core-registry-logger": "^1.0.11", + "async-waterfall": "^0.1.5", "body-parser": "^1.20.2", "cli-spinner": "^0.2.10", "cors": "^2.8.5", diff --git a/src/config/config.js b/src/config/config.js index ecba5d72..11d66f21 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -11,6 +11,9 @@ export default { dialect: 'sqlite', storage: `${persistanceFolder}/data.sqlite3`, logging: false, + dialectOptions: { + busyTimeout: 10000, + }, }, simulator: { dialect: 'sqlite', diff --git a/src/datalayer/persistance.js b/src/datalayer/persistance.js index 5e25fcab..321c2003 100644 --- a/src/datalayer/persistance.js +++ b/src/datalayer/persistance.js @@ -583,7 +583,6 @@ const takeOffer = async (offer) => { return data; } - console.log(data); throw new Error(data.error); } catch (error) { logger.error(error); @@ -606,8 +605,6 @@ const verifyOffer = async (offer) => { const data = response.body; - console.log(data); - if (data.success) { return true; } diff --git a/src/datalayer/syncService.js b/src/datalayer/syncService.js index 4a06a08c..3a092c52 100644 --- a/src/datalayer/syncService.js +++ b/src/datalayer/syncService.js @@ -13,8 +13,8 @@ const { USE_SIMULATOR } = getConfig().APP; const POLLING_INTERVAL = 5000; const frames = ['-', '\\', '|', '/']; -logger.info('Start Datalayer Update Polling'); const startDataLayerUpdatePolling = async () => { + logger.info('Start Datalayer Update Polling'); const updateStoreInfo = await dataLayerWasUpdated(); if (updateStoreInfo.length) { await Promise.all( @@ -243,7 +243,7 @@ const getSubscribedStoreData = async (storeId, retry = 0) => { return getSubscribedStoreData(storeId, retry + 1); } else { logger.debug( - `Store Exists and is confirmed, proceededing to get data ${storeId}`, + `Store Exists and is confirmed, proceeding to get data ${storeId}`, ); } } diff --git a/src/models/projects/projects.model.js b/src/models/projects/projects.model.js index 7ec1fcaf..f609106f 100644 --- a/src/models/projects/projects.model.js +++ b/src/models/projects/projects.model.js @@ -135,14 +135,7 @@ class Project extends Model { static async destroy(values, options) { safeMirrorDbHandler(() => ProjectMirror.destroy(values, options)); - - const record = await super.findOne(values.where); - - if (record) { - const { orgUid } = record.dataValues; - Project.changes.next(['projects', orgUid]); - } - + Project.changes.next(['projects']); return super.destroy(values, options); } diff --git a/src/models/units/units.model.js b/src/models/units/units.model.js index 482806e7..ab92b7a7 100644 --- a/src/models/units/units.model.js +++ b/src/models/units/units.model.js @@ -93,14 +93,7 @@ class Unit extends Model { static async destroy(values, options) { safeMirrorDbHandler(() => UnitMirror.destroy(values, options)); - - const record = await super.findOne(values.where); - - if (record) { - const { orgUid } = record.dataValues; - Unit.changes.next(['units', orgUid]); - } - + Unit.changes.next(['units']); return super.destroy(values, options); } diff --git a/src/tasks/index.js b/src/tasks/index.js index 061d4ceb..29e1a530 100644 --- a/src/tasks/index.js +++ b/src/tasks/index.js @@ -1,6 +1,5 @@ import { ToadScheduler } from 'toad-scheduler'; -import syncDataLayer from './sync-datalayer'; import syncDefaultOrganizations from './sync-default-organizations'; import syncPickLists from './sync-picklists'; import syncAudit from './sync-audit-table'; @@ -20,7 +19,6 @@ const start = () => { // add default jobs const defaultJobs = [ syncGovernanceBody, - syncDataLayer, syncDefaultOrganizations, syncPickLists, syncAudit, diff --git a/src/tasks/sync-audit-table.js b/src/tasks/sync-audit-table.js index e996a766..fe9c08d6 100644 --- a/src/tasks/sync-audit-table.js +++ b/src/tasks/sync-audit-table.js @@ -1,68 +1,139 @@ import _ from 'lodash'; import { SimpleIntervalJob, Task } from 'toad-scheduler'; -import { Organization, Audit } from '../models'; +import { Organization, Audit, ModelKeys, Staging } from '../models'; import datalayer from '../datalayer'; import { decodeHex } from '../utils/datalayer-utils'; import dotenv from 'dotenv'; -import { logger } from '../config/logger.cjs'; +import { logger } from '../logger.js'; +import { sequelize, sequelizeMirror } from '../database'; import { assertDataLayerAvailable, assertWalletIsSynced, } from '../utils/data-assertions'; -logger.info('CADT:task:audit'); - dotenv.config(); -import { getConfig } from '../utils/config-loader'; +import { CONFIG } from '../user-config'; -const CONFIG = getConfig().APP; +let taskIsRunning = false; const task = new Task('sync-audit', async () => { try { - await assertDataLayerAvailable(); - await assertWalletIsSynced(); + if (!taskIsRunning) { + taskIsRunning = true; + await processJob(); + } + } catch (error) { + logger.error(`Error during datasync: ${error.message}`); - logger.info('Syncing Audit Information'); - if (!CONFIG.USE_SIMULATOR) { - const organizations = await Organization.findAll({ - where: { subscribed: true }, - raw: true, - }); - await Promise.all( - organizations.map((organization) => - syncOrganizationAudit(organization), - ), + // Log additional information if present in the error object + if (error.response && error.response.body) { + logger.error( + `Additional error details: ${JSON.stringify(error.response.body)}`, ); } - } catch (error) { - logger.error( - `Retrying in ${CONFIG?.TASKS?.AUDIT_SYNC_TASK_INTERVAL || 30} seconds`, - error, - ); + } finally { + taskIsRunning = false; } }); const job = new SimpleIntervalJob( - { - seconds: CONFIG?.TASKS?.AUDIT_SYNC_TASK_INTERVAL || 30, - runImmediately: true, - }, - task, - 'sync-audit', + { + seconds: CONFIG().CADT.TASKS?.AUDIT_SYNC_TASK_INTERVAL || 30, + runImmediately: true, + }, + task, + 'sync-audit', ); +const processJob = async () => { + await assertDataLayerAvailable(); + await assertWalletIsSynced(); + + logger.task('Syncing Audit Information'); + const organizations = await Organization.findAll({ + where: { subscribed: true }, + raw: true, + }); + + for (const organization of organizations) { + await syncOrganizationAudit(organization); + if (!CONFIG().CADT.USE_SIMULATOR) { + await new Promise((resolve) => + setTimeout( + resolve, + (CONFIG().CADT.TASKS?.AUDIT_SYNC_TASK_INTERVAL || 30) * 1000, + ), + ); + } + } + + if (!CONFIG().CADT.USE_SIMULATOR) { + await new Promise((resolve) => setTimeout(resolve, 5000)); + } +}; + +async function createTransaction(callback, afterCommitCallbacks) { + let result = null; + + let transaction; + let mirrorTransaction; + + try { + // Check if the database is locked and wait until it's unlocked + /* while (await isDatabaseLocked()) { + logger.debug('Database is locked. Waiting...'); + await waitFor(retryDelay); + }*/ + + logger.trace('Starting transaction'); + // Start a transaction + transaction = await sequelize.transaction(); + mirrorTransaction = await sequelizeMirror.transaction(); + + // Execute the provided callback with the transaction + result = await callback(transaction, mirrorTransaction); + + // Commit the transaction if the callback completes without errors + await transaction.commit(); + await mirrorTransaction.commit(); + + for (const afterCommitCallback of afterCommitCallbacks) { + await afterCommitCallback(); + } + + logger.trace('Commited transaction'); + + return result; + } catch (error) { + // Roll back the transaction if an error occurs + if (transaction) { + logger.error('Rolling back transaction'); + console.error(error); + await transaction.rollback(); + } + } +} + const syncOrganizationAudit = async (organization) => { try { - logger.info(`Syncing Audit: ${_.get(organization, 'name')}`); + logger.task(`Syncing Audit: ${_.get(organization, 'name')}`); + let afterCommitCallbacks = []; const rootHistory = await datalayer.getRootHistory(organization.registryId); - const lastRootSaved = await Audit.findOne({ - where: { registryId: organization.registryId }, - order: [['createdAt', 'DESC']], - raw: true, - }); + let lastRootSaved; + + if (CONFIG().CADT.USE_SIMULATOR) { + lastRootSaved = rootHistory[0]; + lastRootSaved.rootHash = lastRootSaved.root_hash; + } else { + lastRootSaved = await Audit.findOne({ + where: { registryId: organization.registryId }, + order: [['createdAt', 'DESC']], + raw: true, + }); + } if (!rootHistory.length) { return; @@ -75,11 +146,11 @@ const syncOrganizationAudit = async (organization) => { } const historyIndex = rootHistory.findIndex( - (root) => root.root_hash === rootHash, + (root) => root.root_hash === rootHash, ); if (!lastRootSaved) { - Audit.create({ + await Audit.create({ orgUid: organization.orgUid, registryId: organization.registryId, rootHash: _.get(rootHistory, '[0].root_hash'), @@ -89,6 +160,20 @@ const syncOrganizationAudit = async (organization) => { onchainConfirmationTimeStamp: _.get(rootHistory, '[0].timestamp'), }); + // Destroy existing records for this singleton + // On a fresh db this does nothing, but when the audit table + // is reset this will ensure that this organizations regsitry data is + // cleaned up on both the local db and mirror db and ready to resync + await Promise.all( + Object.keys(ModelKeys).map(async (modelKey) => { + ModelKeys[modelKey].destroy({ + where: { + orgUid: organization.orgUid, + }, + }); + }), + ); + return; } @@ -104,9 +189,9 @@ const syncOrganizationAudit = async (organization) => { } const kvDiff = await datalayer.getRootDiff( - organization.registryId, - root1.root_hash, - root2.root_hash, + organization.registryId, + root1.root_hash, + root2.root_hash, ); if (_.isEmpty(kvDiff)) { @@ -115,24 +200,34 @@ const syncOrganizationAudit = async (organization) => { // 0x636f6d6d656e74 is hex for 'comment' const comment = kvDiff.filter( - (diff) => - (diff.key === '636f6d6d656e74' || diff.key === '0x636f6d6d656e74') && - diff.type === 'INSERT', + (diff) => + (diff.key === '636f6d6d656e74' || diff.key === '0x636f6d6d656e74') && + diff.type === 'INSERT', ); // 0x617574686F72 is hex for 'author' const author = kvDiff.filter( - (diff) => - (diff.key === '617574686f72' || diff.key === '0x617574686F72') && - diff.type === 'INSERT', + (diff) => + (diff.key === '617574686f72' || diff.key === '0x617574686F72') && + diff.type === 'INSERT', ); - await Promise.all( - kvDiff.map(async (diff) => { + // Process any deletes in the kv diff first to ensure correct processing order + kvDiff.sort((a, b) => { + const typeOrder = { DELETE: 0, INSERT: 1 }; + return typeOrder[a.type] - typeOrder[b.type]; + }); + + const homeOrg = await Organization.getHomeOrg(); + // console.log(kvDiff); + + const updateTransaction = async (transaction, mirrorTransaction) => { + for (const diff of kvDiff) { const key = decodeHex(diff.key); const modelKey = key.split('|')[0]; + if (!['comment', 'author'].includes(key)) { - Audit.create({ + const auditData = { orgUid: organization.orgUid, registryId: organization.registryId, rootHash: root2.root_hash, @@ -141,19 +236,76 @@ const syncOrganizationAudit = async (organization) => { change: decodeHex(diff.value), onchainConfirmationTimeStamp: root2.timestamp, comment: _.get( - JSON.parse(decodeHex(_.get(comment, '[0].value', '7b7d'))), - 'comment', - '', + JSON.parse(decodeHex(_.get(comment, '[0].value', '7b7d'))), + 'comment', + '', ), author: _.get( - JSON.parse(decodeHex(_.get(author, '[0].value', '7b7d'))), - 'author', - '', + JSON.parse(decodeHex(_.get(author, '[0].value', '7b7d'))), + 'author', + '', ), - }); + }; + + if (modelKey) { + const record = JSON.parse(decodeHex(diff.value)); + const primaryKeyValue = + record[ModelKeys[modelKey].primaryKeyAttributes[0]]; + + if (diff.type === 'INSERT') { + logger.trace(`INSERTING: ${modelKey} - ${primaryKeyValue}`); + await ModelKeys[modelKey].upsert(record, { + transaction, + mirrorTransaction, + }); + } else if (diff.type === 'DELETE') { + logger.trace(`DELETING: ${modelKey} - ${primaryKeyValue}`); + await ModelKeys[modelKey].destroy({ + where: { + [ModelKeys[modelKey].primaryKeyAttributes[0]]: + primaryKeyValue, + }, + transaction, + mirrorTransaction, + }); + } + + if (organization.orgUid === homeOrg?.orgUid) { + const stagingUuid = [ + 'unit', + 'project', + 'units', + 'projects', + ].includes(modelKey) + ? primaryKeyValue + : undefined; + + if (stagingUuid) { + afterCommitCallbacks.push(async () => { + logger.trace(`DELETING STAGING: ${stagingUuid}`); + await Staging.destroy({ + where: { uuid: stagingUuid }, + }); + }); + } + } + } + + // Create the Audit record + await Audit.create(auditData, { transaction, mirrorTransaction }); + await Organization.update( + { registryHash: root2.root_hash }, + { + where: { orgUid: organization.orgUid }, + transaction, + mirrorTransaction, + }, + ); } - }), - ); + } + }; + + return createTransaction(updateTransaction, afterCommitCallbacks); } catch (error) { logger.error('Error syncing org audit', error); } From 6386a3406bc93555f7a2a5d4512ad7efb9bba80c Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Tue, 3 Oct 2023 09:22:14 -0400 Subject: [PATCH 02/18] chore: remove npm package --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index babf3acf..629ce1f8 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ "@babel/eslint-parser": "^7.22.9", "@chia-carbon/core-registry-config": "^1.0.2", "@chia-carbon/core-registry-logger": "^1.0.11", - "async-waterfall": "^0.1.5", "body-parser": "^1.20.2", "cli-spinner": "^0.2.10", "cors": "^2.8.5", From 5f7ad86836c2e1c8804f852b790dc14777ac27cd Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Mon, 9 Oct 2023 21:01:21 -0400 Subject: [PATCH 03/18] test: all tests pass --- src/database/index.js | 42 +++--- src/datalayer/syncService.js | 19 ++- src/models/audit/audit.model.js | 28 +++- src/models/co-benefits/co-benefits.model.js | 28 +++- src/models/estimations/estimations.model.js | 29 +++- src/models/issuances/issuances.model.js | 28 +++- src/models/labelUnits/labelUnits.model.js | 28 +++- src/models/labels/labels.model.js | 28 +++- src/models/locations/locations.model.js | 28 +++- src/models/projects/projects.model.js | 30 ++++- src/models/ratings/ratings.model.js | 28 +++- .../related-projects.model.js | 28 +++- src/models/simulator/simulator.model.js | 127 +++++++++++++++++- src/models/staging/staging.model.js | 67 +++------ src/models/units/units.model.js | 41 +++++- tests/integration/project.spec.js | 6 +- tests/integration/unit.spec.js | 26 ++-- tests/test-fixtures/common-fixtures.js | 2 +- tests/test-fixtures/staging-fixtures.js | 2 +- tests/test-fixtures/unit-fixtures.js | 3 +- 20 files changed, 477 insertions(+), 141 deletions(-) diff --git a/src/database/index.js b/src/database/index.js index 8a5e5f56..78c68bb4 100644 --- a/src/database/index.js +++ b/src/database/index.js @@ -26,25 +26,29 @@ const logDebounce = _.debounce(() => { }, 120000); export const safeMirrorDbHandler = (callback) => { - try { - sequelizeMirror - .authenticate() - .then(async () => { - try { - await callback(); - } catch (e) { - logger.error(`mirror_error:${e.message}`); - } - }) - .catch(() => { - logDebounce(); - }); - } catch (error) { - logger.error( - 'MirrorDB tried to update before it was initialize, will try again later', - error, - ); - } + return new Promise((resolve) => { + try { + sequelizeMirror + .authenticate() + .then(async () => { + try { + await callback(); + } catch (e) { + logger.error(`mirror_error:${e.message}`); + } + }) + .catch(() => { + logDebounce(); + }); + } catch (error) { + logger.error( + 'MirrorDB tried to update before it was initialize, will try again later', + error, + ); + } finally { + resolve(); + } + }); }; export const sanitizeSqliteFtsQuery = (query) => { diff --git a/src/datalayer/syncService.js b/src/datalayer/syncService.js index 3a092c52..e4a55322 100644 --- a/src/datalayer/syncService.js +++ b/src/datalayer/syncService.js @@ -1,7 +1,7 @@ import _ from 'lodash'; import { decodeHex, decodeDataLayerResponse } from '../utils/datalayer-utils'; -import { Organization, Staging, ModelKeys } from '../models'; +import { Organization, Staging, ModelKeys, Simulator } from '../models'; import { getConfig } from '../utils/config-loader'; import { logger } from '../config/logger.cjs'; @@ -278,11 +278,28 @@ const getSubscribedStoreData = async (storeId, retry = 0) => { const getRootHistory = (storeId) => { if (!USE_SIMULATOR) { return dataLayer.getRootHistory(storeId); + } else { + return [ + { + confirmed: true, + root_hash: + '0xs571e7fcf464b3dc1d31a71894633eb47cb9dbdb824f6b4a535ed74f23f32e50', + timestamp: 1678518050, + }, + { + confirmed: true, + root_hash: + '0xf571e7fcf464b3dc1d31a71894633eb47cb9dbdb824f6b4a535ed74f23f32e50', + timestamp: 1678518053, + }, + ]; } }; const getRootDiff = (storeId, root1, root2) => { if (!USE_SIMULATOR) { + return Simulator.getMockedKvDiffFromStagingTable(); + } else { return dataLayer.getRootDiff(storeId, root1, root2); } }; diff --git a/src/models/audit/audit.model.js b/src/models/audit/audit.model.js index 5c47fd98..4851504a 100644 --- a/src/models/audit/audit.model.js +++ b/src/models/audit/audit.model.js @@ -9,17 +9,35 @@ import findDuplicateIssuancesSql from './sql/find-duplicate-issuances.sql.js'; class Audit extends Model { static async create(values, options) { - safeMirrorDbHandler(() => AuditMirror.create(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await AuditMirror.create(values, mirrorOptions); + }); return super.create(values, options); } - static async destroy(values, options) { - safeMirrorDbHandler(() => AuditMirror.destroy(values, options)); - return super.destroy(values, options); + static async destroy(options) { + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await AuditMirror.destroy(mirrorOptions); + }); + return super.destroy(options); } static async upsert(values, options) { - safeMirrorDbHandler(() => AuditMirror.upsert(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await AuditMirror.upsert(values, mirrorOptions); + }); return super.upsert(values, options); } diff --git a/src/models/co-benefits/co-benefits.model.js b/src/models/co-benefits/co-benefits.model.js index 7f2046f6..f5a3b29d 100644 --- a/src/models/co-benefits/co-benefits.model.js +++ b/src/models/co-benefits/co-benefits.model.js @@ -25,18 +25,36 @@ class CoBenefit extends Model { } static async create(values, options) { - safeMirrorDbHandler(() => CoBenefitMirror.create(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await CoBenefitMirror.create(values, mirrorOptions); + }); return super.create(values, options); } static async upsert(values, options) { - safeMirrorDbHandler(() => CoBenefitMirror.upsert(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await CoBenefitMirror.upsert(values, mirrorOptions); + }); return super.upsert(values, options); } - static async destroy(values, options) { - safeMirrorDbHandler(() => CoBenefitMirror.destroy(values, options)); - return super.destroy(values, options); + static async destroy(options) { + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await CoBenefitMirror.destroy(mirrorOptions); + }); + return super.destroy(options); } } diff --git a/src/models/estimations/estimations.model.js b/src/models/estimations/estimations.model.js index 06e14672..28be7734 100644 --- a/src/models/estimations/estimations.model.js +++ b/src/models/estimations/estimations.model.js @@ -25,18 +25,37 @@ class Estimation extends Model { } static async create(values, options) { - safeMirrorDbHandler(() => EstimationMirror.create(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + + await EstimationMirror.create(values, mirrorOptions); + }); return super.create(values, options); } static async upsert(values, options) { - safeMirrorDbHandler(() => EstimationMirror.upsert(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await EstimationMirror.upsert(values, mirrorOptions); + }); return super.upsert(values, options); } - static async destroy(values, options) { - safeMirrorDbHandler(() => EstimationMirror.destroy(values, options)); - return super.destroy(values, options); + static async destroy(options) { + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await EstimationMirror.destroy(mirrorOptions); + }); + return super.destroy(options); } } diff --git a/src/models/issuances/issuances.model.js b/src/models/issuances/issuances.model.js index 43fce776..bdf1b0b1 100644 --- a/src/models/issuances/issuances.model.js +++ b/src/models/issuances/issuances.model.js @@ -32,17 +32,35 @@ class Issuance extends Model { } static async create(values, options) { - safeMirrorDbHandler(() => IssuanceMirror.create(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await IssuanceMirror.create(values, mirrorOptions); + }); return super.create(values, options); } - static async destroy(values, options) { - safeMirrorDbHandler(() => IssuanceMirror.destroy(values, options)); - return super.destroy(values, options); + static async destroy(options) { + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await IssuanceMirror.destroy(mirrorOptions); + }); + return super.destroy(options); } static async upsert(values, options) { - safeMirrorDbHandler(() => IssuanceMirror.upsert(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await IssuanceMirror.upsert(values, mirrorOptions); + }); return super.upsert(values, options); } } diff --git a/src/models/labelUnits/labelUnits.model.js b/src/models/labelUnits/labelUnits.model.js index e8e072ff..334d72bc 100644 --- a/src/models/labelUnits/labelUnits.model.js +++ b/src/models/labelUnits/labelUnits.model.js @@ -9,17 +9,35 @@ import { LabelUnitMirror } from './labelUnits.model.mirror'; class LabelUnit extends Model { static async create(values, options) { - safeMirrorDbHandler(() => LabelUnitMirror.create(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await LabelUnitMirror.create(values, mirrorOptions); + }); return super.create(values, options); } - static async destroy(values, options) { - safeMirrorDbHandler(() => LabelUnitMirror.destroy(values, options)); - return super.destroy(values, options); + static async destroy(options) { + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await LabelUnitMirror.destroy(mirrorOptions); + }); + return super.destroy(options); } static async upsert(values, options) { - safeMirrorDbHandler(() => LabelUnitMirror.upsert(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await LabelUnitMirror.upsert(values, mirrorOptions); + }); return super.upsert(values, options); } } diff --git a/src/models/labels/labels.model.js b/src/models/labels/labels.model.js index 6048c34a..05fae9d3 100644 --- a/src/models/labels/labels.model.js +++ b/src/models/labels/labels.model.js @@ -38,17 +38,35 @@ class Label extends Model { } static async create(values, options) { - safeMirrorDbHandler(() => LabelMirror.create(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await LabelMirror.create(values, mirrorOptions); + }); return super.create(values, options); } - static async destroy(values, options) { - safeMirrorDbHandler(() => LabelMirror.destroy(values, options)); - return super.destroy(values, options); + static async destroy(options) { + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await LabelMirror.destroy(mirrorOptions); + }); + return super.destroy(options); } static async upsert(values, options) { - safeMirrorDbHandler(() => LabelMirror.upsert(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await LabelMirror.upsert(values, mirrorOptions); + }); return super.upsert(values, options); } } diff --git a/src/models/locations/locations.model.js b/src/models/locations/locations.model.js index be318be0..debc4ff3 100644 --- a/src/models/locations/locations.model.js +++ b/src/models/locations/locations.model.js @@ -34,17 +34,35 @@ class ProjectLocation extends Model { } static async create(values, options) { - safeMirrorDbHandler(() => ProjectLocationMirror.create(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await ProjectLocationMirror.create(values, mirrorOptions); + }); return super.create(values, options); } - static async destroy(values, options) { - safeMirrorDbHandler(() => ProjectLocationMirror.destroy(values, options)); - return super.destroy(values, options); + static async destroy(options) { + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await ProjectLocationMirror.destroy(mirrorOptions); + }); + return super.destroy(options); } static async upsert(values, options) { - safeMirrorDbHandler(() => ProjectLocationMirror.upsert(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await ProjectLocationMirror.upsert(values, mirrorOptions); + }); return super.upsert(values, options); } } diff --git a/src/models/projects/projects.model.js b/src/models/projects/projects.model.js index f609106f..23074ac1 100644 --- a/src/models/projects/projects.model.js +++ b/src/models/projects/projects.model.js @@ -122,7 +122,13 @@ class Project extends Model { } static async create(values, options) { - safeMirrorDbHandler(() => ProjectMirror.create(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await ProjectMirror.create(values, mirrorOptions); + }); const createResult = await super.create(values, options); @@ -133,14 +139,28 @@ class Project extends Model { return createResult; } - static async destroy(values, options) { - safeMirrorDbHandler(() => ProjectMirror.destroy(values, options)); + static async destroy(options) { + await safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + + await ProjectMirror.destroy(mirrorOptions); + }); + Project.changes.next(['projects']); - return super.destroy(values, options); + return super.destroy(options); } static async upsert(values, options) { - safeMirrorDbHandler(() => ProjectMirror.upsert(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await ProjectMirror.upsert(values, mirrorOptions); + }); const upsertResult = await super.upsert(values, options); const { orgUid } = values; diff --git a/src/models/ratings/ratings.model.js b/src/models/ratings/ratings.model.js index 234d5673..e82f3884 100644 --- a/src/models/ratings/ratings.model.js +++ b/src/models/ratings/ratings.model.js @@ -25,17 +25,35 @@ class Rating extends Model { } static async create(values, options) { - safeMirrorDbHandler(() => RatingMirror.create(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await RatingMirror.create(values, mirrorOptions); + }); return super.create(values, options); } - static async destroy(values, options) { - safeMirrorDbHandler(() => RatingMirror.destroy(values, options)); - return super.destroy(values, options); + static async destroy(options) { + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await RatingMirror.destroy(mirrorOptions); + }); + return super.destroy(options); } static async upsert(values, options) { - safeMirrorDbHandler(() => RatingMirror.upsert(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await RatingMirror.upsert(values, mirrorOptions); + }); return super.upsert(values, options); } } diff --git a/src/models/related-projects/related-projects.model.js b/src/models/related-projects/related-projects.model.js index c0894f43..b0342c59 100644 --- a/src/models/related-projects/related-projects.model.js +++ b/src/models/related-projects/related-projects.model.js @@ -26,17 +26,35 @@ class RelatedProject extends Model { } static async create(values, options) { - safeMirrorDbHandler(() => RelatedProjectMirror.create(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await RelatedProjectMirror.create(values, mirrorOptions); + }); return super.create(values, options); } - static async destroy(values, options) { - safeMirrorDbHandler(() => RelatedProjectMirror.destroy(values, options)); - return super.destroy(values, options); + static async destroy(options) { + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await RelatedProjectMirror.destroy(mirrorOptions); + }); + return super.destroy(options); } static async upsert(values, options) { - safeMirrorDbHandler(() => RelatedProjectMirror.upsert(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await RelatedProjectMirror.upsert(values, mirrorOptions); + }); return super.upsert(values, options); } } diff --git a/src/models/simulator/simulator.model.js b/src/models/simulator/simulator.model.js index 808f8813..4b35851d 100644 --- a/src/models/simulator/simulator.model.js +++ b/src/models/simulator/simulator.model.js @@ -1,12 +1,137 @@ 'use strict'; +import _ from 'lodash'; import Sequelize from 'sequelize'; const { Model } = Sequelize; import { sequelize } from '../../database'; +import { encodeHex } from '../../utils/datalayer-utils'; +import { ModelKeys, Staging } from '../index'; import ModelTypes from './simulator.modeltypes.cjs'; +import { uuid as uuidv4 } from 'uuidv4'; -class Simulator extends Model {} +class Simulator extends Model { + /** + * Generate Simulated Key-Value Differences (kvDiffs) from Staging Table. + * + * This function serves to simulate the kvDiffs generated from the data layer. + * It reads all records from the Staging table and produces kvDiffs for each record, + * transforming the Staging table into a form that resembles the data layer output. + * + * The kvDiffs are used to track changes (INSERT, DELETE, UPDATE) to the underlying data model. + * + * For each record in the Staging table: + * + * 1. If the action is 'DELETE' or 'UPDATE', a kvDiff with type 'DELETE' is created for the existing record. + * 2. If the action is 'INSERT' or 'UPDATE', a kvDiff with type 'INSERT' is created for the new record(s). + * + * For 'UPDATE' actions, the function first generates kvDiffs for 'DELETE' using existing records, + * and then kvDiffs for 'INSERT' using the new records. This effectively breaks down an 'UPDATE' + * into a 'DELETE' followed by an 'INSERT'. + * + * @returns {Array} An array of kvDiff objects. + * @throws Will throw an error if the corresponding model for the table doesn't exist or if other database operations fail. + */ + static async getMockedKvDiffFromStagingTable() { + const data = await Staging.findAll(); + const diff = []; + + for (const staging of data) { + const lowerTable = staging.table.toLowerCase(); + const modelKey = ModelKeys[lowerTable]; + const array = []; + + if (staging.action === 'DELETE' || staging.action === 'UPDATE') { + const existingData = await modelKey.findOne({ + where: { [modelKey.primaryKeyAttributes[0]]: staging.uuid }, + raw: true, + }); + if (existingData) { + array.push({ + key: encodeHex(`${lowerTable}|${staging.uuid}`), + value: encodeHex(JSON.stringify(existingData)), + type: 'DELETE', + }); + + const arrayKeys = Object.keys(existingData).filter((key) => + Array.isArray(existingData[key]), + ); + + for (const key of arrayKeys) { + for (const obj of existingData[key]) { + array.push({ + key: encodeHex(`${key}|${staging.uuid}`), + value: encodeHex(JSON.stringify(obj)), + type: 'DELETE', + }); + } + } + } + } + + if (staging.action === 'INSERT' || staging.action === 'UPDATE') { + const parsedDataArray = JSON.parse(staging?.data ?? []); + for (const parsedData of parsedDataArray) { + if (!parsedData) continue; + + const issuanceUuid = uuidv4(); + const issuance = parsedData.issuance + ? _.cloneDeep(parsedData.issuance) + : null; + + if (staging.table.toLowerCase() === 'units' && issuance) { + parsedData.issuanceId = issuanceUuid; + issuance.id = issuanceUuid; + } + + array.push({ + key: encodeHex(`${lowerTable}|${staging.uuid}`), + value: encodeHex(JSON.stringify(parsedData)), + type: 'INSERT', + }); + + const arrayKeys = Object.keys(parsedData).filter((key) => + Array.isArray(parsedData[key]), + ); + + if (staging.table.toLowerCase() === 'units' && Boolean(issuance)) { + arrayKeys.push('issuances'); + } + + for (const key of arrayKeys) { + if (key === 'issuances' && Boolean(issuance)) { + array.push({ + key: encodeHex(`${key}|${staging.uuid}`), + value: encodeHex(JSON.stringify(issuance ?? {})), + type: 'INSERT', + }); + } else { + for (const obj of parsedData[key]) { + array.push({ + key: encodeHex(`${key}|${staging.uuid}`), + value: encodeHex(JSON.stringify(obj)), + type: 'INSERT', + }); + + if (key === 'labels' && obj.label_unit) { + array.push({ + key: encodeHex(`label_unit|${staging.uuid}`), + value: encodeHex(JSON.stringify(obj.label_unit)), + type: 'INSERT', + }); + } + } + } + } + } + } + + diff.push(array); + } + + return _.flatten(diff); + } +} Simulator.init(ModelTypes, { sequelize, diff --git a/src/models/staging/staging.model.js b/src/models/staging/staging.model.js index cf218db8..5b0af3e4 100644 --- a/src/models/staging/staging.model.js +++ b/src/models/staging/staging.model.js @@ -464,55 +464,34 @@ class Staging extends Model { return [insertRecords, updateRecords, deleteChangeList]; }; + /** + * Pushes data to the DataLayer. + * @param {string} tableToPush - The name of the table to push. + * @param {string} comment - The comment to associate with the data. + * @param {string} author - The author of the data. + * @param {Array} [ids=[]] - Optional array of IDs to use in the query. + * @throws {Error} Throws an error if no records are found to send to DataLayer. + */ static async pushToDataLayer(tableToPush, comment, author, ids = []) { - let stagedRecords; + const whereClause = { + commited: false, + ...(tableToPush ? { table: tableToPush } : {}), + ...(ids.length ? { uuid: { [Sequelize.Op.in]: ids } } : {}), + }; - if (tableToPush) { - stagedRecords = await Staging.findAll({ - where: { - commited: false, - table: tableToPush, - ...(ids.length - ? { - uuid: { - [Sequelize.Op.in]: ids, - }, - } - : {}), - }, - raw: true, - }); - } else { - stagedRecords = await Staging.findAll({ - where: { - commited: false, - ...(ids.length - ? { - uuid: { - [Sequelize.Op.in]: ids, - }, - } - : {}), - }, - raw: true, - }); - } + const stagedRecords = await Staging.findAll({ + where: whereClause, + raw: true, + }); if (!stagedRecords.length) { - throw new Error('No records to send to datalayer'); + throw new Error('No records to send to DataLayer'); } - const unitsChangeList = await Unit.generateChangeListFromStagedData( - stagedRecords, - comment, - author, - ); - - const projectsChangeList = await Project.generateChangeListFromStagedData( - stagedRecords, - comment, - author, - ); + const [unitsChangeList, projectsChangeList] = await Promise.all([ + Unit.generateChangeListFromStagedData(stagedRecords, comment, author), + Project.generateChangeListFromStagedData(stagedRecords, comment, author), + ]); const unifiedChangeList = { ...projectsChangeList, @@ -529,7 +508,6 @@ class Staging extends Model { raw: true, }); - // sort so that deletes are first and inserts second const finalChangeList = _.uniqBy( _.sortBy(_.flatten(_.values(unifiedChangeList)), 'action'), (v) => [v.action, v.key].join(), @@ -539,7 +517,6 @@ class Staging extends Model { myOrganization.registryId, finalChangeList, async () => { - // The push failed so revert the commited staging records. await Staging.update( { failedCommit: true }, { where: { commited: true } }, diff --git a/src/models/units/units.model.js b/src/models/units/units.model.js index ab92b7a7..89918625 100644 --- a/src/models/units/units.model.js +++ b/src/models/units/units.model.js @@ -70,7 +70,13 @@ class Unit extends Model { } static async create(values, options) { - safeMirrorDbHandler(() => UnitMirror.create(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await UnitMirror.create(values, mirrorOptions); + }); const createResult = await super.create(values, options); const { orgUid } = createResult; @@ -81,7 +87,14 @@ class Unit extends Model { } static async upsert(values, options) { - safeMirrorDbHandler(() => UnitMirror.upsert(values, options)); + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await UnitMirror.upsert(values, mirrorOptions); + }); + const upsertResult = await super.upsert(values, options); const { orgUid } = values; @@ -91,10 +104,17 @@ class Unit extends Model { return upsertResult; } - static async destroy(values, options) { - safeMirrorDbHandler(() => UnitMirror.destroy(values, options)); + static async destroy(options) { + safeMirrorDbHandler(async () => { + const mirrorOptions = { + ...options, + transaction: options?.mirrorTransaction, + }; + await UnitMirror.destroy(mirrorOptions); + }); + Unit.changes.next(['units']); - return super.destroy(values, options); + return super.destroy(options); } static async fts( @@ -129,7 +149,12 @@ class Unit extends Model { ); } - static async findAllMySQLFts(searchStr, orgUid, pagination, columns = []) { + static async findAllMySQLFts( + userSearchInput, + orgUid, + pagination, + columns = [], + ) { const { offset, limit } = pagination; let fields = '*'; @@ -166,7 +191,9 @@ class Unit extends Model { sql = `${sql} AND orgUid = :orgUid`; } - const replacements = { search: searchStr, orgUid }; + console.log('searchTerm', userSearchInput); + + const replacements = { search: userSearchInput, orgUid }; const count = ( await sequelize.query(sql, { diff --git a/tests/integration/project.spec.js b/tests/integration/project.spec.js index 62d81e34..cc8ff64a 100644 --- a/tests/integration/project.spec.js +++ b/tests/integration/project.spec.js @@ -7,14 +7,14 @@ import * as testFixtures from '../test-fixtures'; import { pullPickListValues } from '../../src/utils/data-loaders'; import { prepareDb } from '../../src/database'; import datalayer from '../../src/datalayer'; -const TEST_WAIT_TIME = datalayer.POLLING_INTERVAL * 2; +const TEST_WAIT_TIME = datalayer.POLLING_INTERVAL * 5; describe('Project Resource Integration Tests', function () { let homeOrgUid; before(async function () { - await pullPickListValues(); await prepareDb(); + await pullPickListValues(); }); beforeEach(async function () { @@ -83,7 +83,7 @@ describe('Project Resource Integration Tests', function () { // process in included in the record we are about to delete // Since some data is derived and not in the creation payload, // we need to test against the subset of the delete record - // We alreay asserted existance of the derived data above + // We already asserted existance of the derived data above testFixtures.objectContainsSubSet( deleteStagingRecord.diff.original, newProjectPayload, diff --git a/tests/integration/unit.spec.js b/tests/integration/unit.spec.js index 2df2fed2..92085191 100644 --- a/tests/integration/unit.spec.js +++ b/tests/integration/unit.spec.js @@ -10,7 +10,8 @@ import { pullPickListValues } from '../../src/utils/data-loaders'; import * as testFixtures from '../test-fixtures'; import { prepareDb } from '../../src/database'; import datalayer from '../../src/datalayer'; -const TEST_WAIT_TIME = datalayer.POLLING_INTERVAL * 2; +import { Staging } from '../../src/models'; +const TEST_WAIT_TIME = datalayer.POLLING_INTERVAL * 5; describe('Unit Resource Integration Tests', function () { let homeOrgUid; @@ -21,11 +22,17 @@ describe('Unit Resource Integration Tests', function () { }); beforeEach(async function () { + await Staging.destroy({ truncate: true }); await testFixtures.resetStagingTable(); await testFixtures.createTestHomeOrg(); homeOrgUid = await testFixtures.getHomeOrgId(); }); + afterEach(async function () { + await testFixtures.resetStagingTable(); + await Staging.destroy({ truncate: true }); + }); + it('deletes a unit end-to-end (with simulator)', async function () { /* Basic Idea for this test is that we are going to create a unit and verify that @@ -153,11 +160,7 @@ describe('Unit Resource Integration Tests', function () { // The node simulator runs on an async process, we are importing // the WAIT_TIME constant from the simulator, padding it and waiting for the // appropriate amount of time for the simulator to finish its operations - await new Promise((resolve) => { - setTimeout(() => { - resolve(); - }, TEST_WAIT_TIME); - }); + await testFixtures.waitForDataLayerSync(); // Get a unit to split const allUnitsResult = await supertest(app).get('/v1/units'); @@ -253,11 +256,7 @@ describe('Unit Resource Integration Tests', function () { // The node simulator runs on an async process, we are importing // the WAIT_TIME constant from the simulator, padding it and waiting for the // appropriate amount of time for the simulator to finish its operations - await new Promise((resolve) => { - setTimeout(() => { - resolve(); - }, TEST_WAIT_TIME); - }); + await testFixtures.waitForDataLayerSync(); const warehouseRes = await supertest(app) .get(`/v1/units`) @@ -346,7 +345,7 @@ describe('Unit Resource Integration Tests', function () { // There should be no staging records left expect(stagingRes3.body.length).to.equal(0); - }).timeout(TEST_WAIT_TIME * 10); + }).timeout(TEST_WAIT_TIME * 20); it('creates a new unit end-to-end (with simulator)', async function () { // 1. Create a new unit @@ -444,6 +443,9 @@ describe('Unit Resource Integration Tests', function () { // Make sure the newly created unit is in the mirrorDb await testFixtures.checkUnitMirrorRecordExists(warehouseUnitId); + + // deleting this is a hack but we dont need to test it here + delete changeRecord.issuance; await testFixtures.updateUnit(warehouseUnitId, changeRecord); // Get the staging record we just created diff --git a/tests/test-fixtures/common-fixtures.js b/tests/test-fixtures/common-fixtures.js index 9dd4f6ea..3f93b4db 100644 --- a/tests/test-fixtures/common-fixtures.js +++ b/tests/test-fixtures/common-fixtures.js @@ -21,7 +21,7 @@ export const waitForDataLayerSync = () => { return new Promise((resolve) => { setTimeout(() => { resolve(); - }, TEST_WAIT_TIME * 2); + }, TEST_WAIT_TIME * 5); }); }; diff --git a/tests/test-fixtures/staging-fixtures.js b/tests/test-fixtures/staging-fixtures.js index e115e7d1..0d9f2ebd 100644 --- a/tests/test-fixtures/staging-fixtures.js +++ b/tests/test-fixtures/staging-fixtures.js @@ -7,7 +7,7 @@ import supertest from 'supertest'; import app from '../../src/server'; export const resetStagingTable = async () => { - await supertest(app).get(`/v1/staging/clean`); + await supertest(app).delete(`/v1/staging/clean`); const result = await supertest(app).get('/v1/staging'); expect(result.body).to.deep.equal([]); }; diff --git a/tests/test-fixtures/unit-fixtures.js b/tests/test-fixtures/unit-fixtures.js index e3948ca5..822b15dc 100644 --- a/tests/test-fixtures/unit-fixtures.js +++ b/tests/test-fixtures/unit-fixtures.js @@ -42,7 +42,7 @@ export const updateUnit = async (warehouseUnitId, originalRecord) => { } if (typeof updateUnitJson[key] === 'object') { - updateUnitJson[key].id = originalRecord[key].id; + updateUnitJson[key].id = originalRecord[key]?.id; } }); @@ -69,6 +69,7 @@ export const getUnit = async (warehouseUnitId) => { export const checkUnitRecordExists = async (warehouseUnitId) => { const record = await Unit.findByPk(warehouseUnitId); expect(record).to.be.ok; + return record; }; export const checkUnitRecordDoesNotExist = async (warehouseUnitId) => { From 6f5d407ab7b8638c9882befd25572eb96cfa74e7 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Fri, 13 Oct 2023 12:04:34 -0400 Subject: [PATCH 04/18] fix: various tweaks for sync to work in this repo --- package-lock.json | 8 +- package.json | 3 - src/datalayer/syncService.js | 2 +- src/tasks/sync-audit-table.js | 126 +++++++++++++++--------------- src/utils/config-loader.js | 1 + tests/integration/project.spec.js | 1 + 6 files changed, 65 insertions(+), 76 deletions(-) diff --git a/package-lock.json b/package-lock.json index acd1a2c3..b54ba5cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,7 @@ "dependencies": { "@babel/eslint-parser": "^7.22.9", "@chia-carbon/core-registry-config": "^1.0.2", - "@chia-carbon/core-registry-logger": "^1.0.11", - "async-waterfall": "^0.1.5", + "@chia-carbon/core-registry-logger": "^1.0.12", "body-parser": "^1.20.2", "cli-spinner": "^0.2.10", "cors": "^2.8.5", @@ -3105,11 +3104,6 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" }, - "node_modules/async-waterfall": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/async-waterfall/-/async-waterfall-0.1.5.tgz", - "integrity": "sha512-aJXVeDPYaXZUw/lfkeEK13OLSxHO4AZWA2so1Q0n4ey3ix26rWzSCzl4hnkJvolA12MvmUF8covY8bZvKjbtmA==" - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", diff --git a/package.json b/package.json index 629ce1f8..6e2b9b0e 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,6 @@ }, "dependencies": { "@babel/eslint-parser": "^7.22.9", - "@chia-carbon/core-registry-config": "^1.0.2", - "@chia-carbon/core-registry-logger": "^1.0.11", "body-parser": "^1.20.2", "cli-spinner": "^0.2.10", "cors": "^2.8.5", @@ -74,7 +72,6 @@ "eslint-plugin-es": "^4.1.0", "eslint-plugin-mocha": "^10.2.0", "husky": "^8.0.3", - "mocha": "^10.2.0", "semver": "^7.5.4", "sinon": "^16.1.0", diff --git a/src/datalayer/syncService.js b/src/datalayer/syncService.js index e4a55322..1a02e187 100644 --- a/src/datalayer/syncService.js +++ b/src/datalayer/syncService.js @@ -297,7 +297,7 @@ const getRootHistory = (storeId) => { }; const getRootDiff = (storeId, root1, root2) => { - if (!USE_SIMULATOR) { + if (USE_SIMULATOR) { return Simulator.getMockedKvDiffFromStagingTable(); } else { return dataLayer.getRootDiff(storeId, root1, root2); diff --git a/src/tasks/sync-audit-table.js b/src/tasks/sync-audit-table.js index fe9c08d6..9576cedc 100644 --- a/src/tasks/sync-audit-table.js +++ b/src/tasks/sync-audit-table.js @@ -5,16 +5,17 @@ import { Organization, Audit, ModelKeys, Staging } from '../models'; import datalayer from '../datalayer'; import { decodeHex } from '../utils/datalayer-utils'; import dotenv from 'dotenv'; -import { logger } from '../logger.js'; +import { logger } from '../config/logger.cjs'; import { sequelize, sequelizeMirror } from '../database'; - +import { getConfig } from '../utils/config-loader'; import { assertDataLayerAvailable, assertWalletIsSynced, } from '../utils/data-assertions'; dotenv.config(); -import { CONFIG } from '../user-config'; + +const CONFIG = getConfig().APP; let taskIsRunning = false; @@ -30,7 +31,7 @@ const task = new Task('sync-audit', async () => { // Log additional information if present in the error object if (error.response && error.response.body) { logger.error( - `Additional error details: ${JSON.stringify(error.response.body)}`, + `Additional error details: ${JSON.stringify(error.response.body)}`, ); } } finally { @@ -39,37 +40,38 @@ const task = new Task('sync-audit', async () => { }); const job = new SimpleIntervalJob( - { - seconds: CONFIG().CADT.TASKS?.AUDIT_SYNC_TASK_INTERVAL || 30, - runImmediately: true, - }, - task, - 'sync-audit', + { + seconds: CONFIG?.TASKS?.AUDIT_SYNC_TASK_INTERVAL || 30, + runImmediately: true, + }, + task, + 'sync-audit', ); const processJob = async () => { await assertDataLayerAvailable(); await assertWalletIsSynced(); - logger.task('Syncing Audit Information'); + logger.info('Syncing Audit Information'); const organizations = await Organization.findAll({ where: { subscribed: true }, raw: true, }); for (const organization of organizations) { + console.log(`Syncing ${organization.name}`); await syncOrganizationAudit(organization); - if (!CONFIG().CADT.USE_SIMULATOR) { + if (!CONFIG.USE_SIMULATOR) { await new Promise((resolve) => - setTimeout( - resolve, - (CONFIG().CADT.TASKS?.AUDIT_SYNC_TASK_INTERVAL || 30) * 1000, - ), + setTimeout( + resolve, + (CONFIG.TASKS?.AUDIT_SYNC_TASK_INTERVAL || 30) * 1000, + ), ); } } - if (!CONFIG().CADT.USE_SIMULATOR) { + if (!CONFIG.USE_SIMULATOR) { await new Promise((resolve) => setTimeout(resolve, 5000)); } }; @@ -81,13 +83,7 @@ async function createTransaction(callback, afterCommitCallbacks) { let mirrorTransaction; try { - // Check if the database is locked and wait until it's unlocked - /* while (await isDatabaseLocked()) { - logger.debug('Database is locked. Waiting...'); - await waitFor(retryDelay); - }*/ - - logger.trace('Starting transaction'); + logger.info('Starting transaction'); // Start a transaction transaction = await sequelize.transaction(); mirrorTransaction = await sequelizeMirror.transaction(); @@ -103,7 +99,7 @@ async function createTransaction(callback, afterCommitCallbacks) { await afterCommitCallback(); } - logger.trace('Commited transaction'); + logger.info('Commited transaction'); return result; } catch (error) { @@ -118,13 +114,14 @@ async function createTransaction(callback, afterCommitCallbacks) { const syncOrganizationAudit = async (organization) => { try { - logger.task(`Syncing Audit: ${_.get(organization, 'name')}`); + logger.info(`Syncing Audit: ${_.get(organization, 'name')}`); let afterCommitCallbacks = []; const rootHistory = await datalayer.getRootHistory(organization.registryId); let lastRootSaved; - if (CONFIG().CADT.USE_SIMULATOR) { + if (CONFIG.USE_SIMULATOR) { + console.log('USING MOCK ROOT HISTORY'); lastRootSaved = rootHistory[0]; lastRootSaved.rootHash = lastRootSaved.root_hash; } else { @@ -146,7 +143,7 @@ const syncOrganizationAudit = async (organization) => { } const historyIndex = rootHistory.findIndex( - (root) => root.root_hash === rootHash, + (root) => root.root_hash === rootHash, ); if (!lastRootSaved) { @@ -165,13 +162,13 @@ const syncOrganizationAudit = async (organization) => { // is reset this will ensure that this organizations regsitry data is // cleaned up on both the local db and mirror db and ready to resync await Promise.all( - Object.keys(ModelKeys).map(async (modelKey) => { - ModelKeys[modelKey].destroy({ - where: { - orgUid: organization.orgUid, - }, - }); - }), + Object.keys(ModelKeys).map(async (modelKey) => { + ModelKeys[modelKey].destroy({ + where: { + orgUid: organization.orgUid, + }, + }); + }), ); return; @@ -189,9 +186,9 @@ const syncOrganizationAudit = async (organization) => { } const kvDiff = await datalayer.getRootDiff( - organization.registryId, - root1.root_hash, - root2.root_hash, + organization.registryId, + root1.root_hash, + root2.root_hash, ); if (_.isEmpty(kvDiff)) { @@ -200,16 +197,16 @@ const syncOrganizationAudit = async (organization) => { // 0x636f6d6d656e74 is hex for 'comment' const comment = kvDiff.filter( - (diff) => - (diff.key === '636f6d6d656e74' || diff.key === '0x636f6d6d656e74') && - diff.type === 'INSERT', + (diff) => + (diff.key === '636f6d6d656e74' || diff.key === '0x636f6d6d656e74') && + diff.type === 'INSERT', ); // 0x617574686F72 is hex for 'author' const author = kvDiff.filter( - (diff) => - (diff.key === '617574686f72' || diff.key === '0x617574686F72') && - diff.type === 'INSERT', + (diff) => + (diff.key === '617574686f72' || diff.key === '0x617574686F72') && + diff.type === 'INSERT', ); // Process any deletes in the kv diff first to ensure correct processing order @@ -219,7 +216,6 @@ const syncOrganizationAudit = async (organization) => { }); const homeOrg = await Organization.getHomeOrg(); - // console.log(kvDiff); const updateTransaction = async (transaction, mirrorTransaction) => { for (const diff of kvDiff) { @@ -236,34 +232,34 @@ const syncOrganizationAudit = async (organization) => { change: decodeHex(diff.value), onchainConfirmationTimeStamp: root2.timestamp, comment: _.get( - JSON.parse(decodeHex(_.get(comment, '[0].value', '7b7d'))), - 'comment', - '', + JSON.parse(decodeHex(_.get(comment, '[0].value', '7b7d'))), + 'comment', + '', ), author: _.get( - JSON.parse(decodeHex(_.get(author, '[0].value', '7b7d'))), - 'author', - '', + JSON.parse(decodeHex(_.get(author, '[0].value', '7b7d'))), + 'author', + '', ), }; if (modelKey) { const record = JSON.parse(decodeHex(diff.value)); const primaryKeyValue = - record[ModelKeys[modelKey].primaryKeyAttributes[0]]; + record[ModelKeys[modelKey].primaryKeyAttributes[0]]; if (diff.type === 'INSERT') { - logger.trace(`INSERTING: ${modelKey} - ${primaryKeyValue}`); + logger.info(`INSERTING: ${modelKey} - ${primaryKeyValue}`); await ModelKeys[modelKey].upsert(record, { transaction, mirrorTransaction, }); } else if (diff.type === 'DELETE') { - logger.trace(`DELETING: ${modelKey} - ${primaryKeyValue}`); + logger.info(`DELETING: ${modelKey} - ${primaryKeyValue}`); await ModelKeys[modelKey].destroy({ where: { [ModelKeys[modelKey].primaryKeyAttributes[0]]: - primaryKeyValue, + primaryKeyValue, }, transaction, mirrorTransaction, @@ -277,12 +273,12 @@ const syncOrganizationAudit = async (organization) => { 'units', 'projects', ].includes(modelKey) - ? primaryKeyValue - : undefined; + ? primaryKeyValue + : undefined; if (stagingUuid) { afterCommitCallbacks.push(async () => { - logger.trace(`DELETING STAGING: ${stagingUuid}`); + logger.info(`DELETING STAGING: ${stagingUuid}`); await Staging.destroy({ where: { uuid: stagingUuid }, }); @@ -294,18 +290,18 @@ const syncOrganizationAudit = async (organization) => { // Create the Audit record await Audit.create(auditData, { transaction, mirrorTransaction }); await Organization.update( - { registryHash: root2.root_hash }, - { - where: { orgUid: organization.orgUid }, - transaction, - mirrorTransaction, - }, + { registryHash: root2.root_hash }, + { + where: { orgUid: organization.orgUid }, + transaction, + mirrorTransaction, + }, ); } } }; - return createTransaction(updateTransaction, afterCommitCallbacks); + return await createTransaction(updateTransaction, afterCommitCallbacks); } catch (error) { logger.error('Error syncing org audit', error); } diff --git a/src/utils/config-loader.js b/src/utils/config-loader.js index 94fcf63c..ed4f031c 100644 --- a/src/utils/config-loader.js +++ b/src/utils/config-loader.js @@ -29,6 +29,7 @@ export const getConfig = _.memoize(() => { if (process.env.USE_SIMULATOR) { defaultConfig.APP.USE_SIMULATOR = true; defaultConfig.APP.CHIA_NETWORK = 'testnet'; + defaultConfig.APP.TASKS.AUDIT_SYNC_TASK_INTERVAL = 30; logger.info(`ENV FILE OVERRIDE: RUNNING IN SIMULATOR MODE`); } diff --git a/tests/integration/project.spec.js b/tests/integration/project.spec.js index cc8ff64a..02bd5d50 100644 --- a/tests/integration/project.spec.js +++ b/tests/integration/project.spec.js @@ -57,6 +57,7 @@ describe('Project Resource Integration Tests', function () { // Now push the staging table live await testFixtures.commitStagingRecords(); await testFixtures.waitForDataLayerSync(); + await testFixtures.waitForDataLayerSync(); // The staging table should be empty after committing expect(await testFixtures.getLastCreatedStagingRecord()).to.equal( From 1bca49e2556700ddee218a4a90462fc402309a49 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Mon, 16 Oct 2023 09:53:10 -0400 Subject: [PATCH 05/18] feat: automatic migration to new sync method --- .jshintrc | 3 ++ src/database/index.js | 19 ++++++++++++ src/models/units/units.model.js | 2 -- src/tasks/sync-audit-table.js | 51 +++++++++++++++++++++++++++++---- 4 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 .jshintrc diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 00000000..711f4c4f --- /dev/null +++ b/.jshintrc @@ -0,0 +1,3 @@ +{ + "esversion": 11 +} diff --git a/src/database/index.js b/src/database/index.js index 78c68bb4..d12ab53a 100644 --- a/src/database/index.js +++ b/src/database/index.js @@ -25,7 +25,26 @@ const logDebounce = _.debounce(() => { logger.info('Mirror DB not connected'); }, 120000); +export const mirrorDBEnabled = () => { + const CONFIG = getConfig(); + if ( + mirrorConfig === 'mirror' && + (!CONFIG?.MIRROR_DB?.DB_HOST || + !CONFIG?.MIRROR_DB?.DB_NAME || + !CONFIG?.MIRROR_DB?.DB_USERNAME || + !CONFIG?.MIRROR_DB?.DB_PASSWORD) + ) { + return false; + } + + return true; +}; + export const safeMirrorDbHandler = (callback) => { + if (!mirrorDBEnabled()) { + return Promise.resolve(); + } + return new Promise((resolve) => { try { sequelizeMirror diff --git a/src/models/units/units.model.js b/src/models/units/units.model.js index 89918625..07c94324 100644 --- a/src/models/units/units.model.js +++ b/src/models/units/units.model.js @@ -191,8 +191,6 @@ class Unit extends Model { sql = `${sql} AND orgUid = :orgUid`; } - console.log('searchTerm', userSearchInput); - const replacements = { search: userSearchInput, orgUid }; const count = ( diff --git a/src/tasks/sync-audit-table.js b/src/tasks/sync-audit-table.js index 9576cedc..f865bd1b 100644 --- a/src/tasks/sync-audit-table.js +++ b/src/tasks/sync-audit-table.js @@ -1,7 +1,7 @@ import _ from 'lodash'; import { SimpleIntervalJob, Task } from 'toad-scheduler'; -import { Organization, Audit, ModelKeys, Staging } from '../models'; +import { Organization, Audit, ModelKeys, Staging, Meta } from '../models'; import datalayer from '../datalayer'; import { decodeHex } from '../utils/datalayer-utils'; import dotenv from 'dotenv'; @@ -12,6 +12,7 @@ import { assertDataLayerAvailable, assertWalletIsSynced, } from '../utils/data-assertions'; +import { mirrorDBEnabled } from '../database'; dotenv.config(); @@ -23,7 +24,39 @@ const task = new Task('sync-audit', async () => { try { if (!taskIsRunning) { taskIsRunning = true; - await processJob(); + + const hasMigratedToNewSyncMethod = await Meta.findOne({ + where: { metaKey: 'migratedToNewSync' }, + }); + + if (hasMigratedToNewSyncMethod || CONFIG.USE_SIMULATOR) { + await processJob(); + } else { + logger.info( + 'Initiating migration to the new synchronization method. This will require a complete resynchronization of all data and may take some time.', + ); + + for (const modelKey of Object.keys(ModelKeys)) { + logger.info(`Resetting ${modelKey}`); + await ModelKeys[modelKey].destroy({ + where: {}, + truncate: true, + }); + } + + logger.info(`Resetting Audit Table`); + await Audit.destroy({ + where: {}, + truncate: true, + }); + + logger.info(`Completing Migration`); + await Meta.upsert({ + metaKey: 'migratedToNewSync', + metaValue: 'true', + }); + logger.info(`Migration Complete`); + } } } catch (error) { logger.error(`Error during datasync: ${error.message}`); @@ -52,7 +85,7 @@ const processJob = async () => { await assertDataLayerAvailable(); await assertWalletIsSynced(); - logger.info('Syncing Audit Information'); + logger.info('Syncing Registry Data'); const organizations = await Organization.findAll({ where: { subscribed: true }, raw: true, @@ -86,14 +119,20 @@ async function createTransaction(callback, afterCommitCallbacks) { logger.info('Starting transaction'); // Start a transaction transaction = await sequelize.transaction(); - mirrorTransaction = await sequelizeMirror.transaction(); + + if (mirrorDBEnabled()) { + mirrorTransaction = await sequelizeMirror.transaction(); + } // Execute the provided callback with the transaction result = await callback(transaction, mirrorTransaction); // Commit the transaction if the callback completes without errors await transaction.commit(); - await mirrorTransaction.commit(); + + if (mirrorDBEnabled()) { + await mirrorTransaction.commit(); + } for (const afterCommitCallback of afterCommitCallbacks) { await afterCommitCallback(); @@ -114,7 +153,7 @@ async function createTransaction(callback, afterCommitCallbacks) { const syncOrganizationAudit = async (organization) => { try { - logger.info(`Syncing Audit: ${_.get(organization, 'name')}`); + logger.info(`Syncing Registry: ${_.get(organization, 'name')}`); let afterCommitCallbacks = []; const rootHistory = await datalayer.getRootHistory(organization.registryId); From 4e0e5ac1835311b15e023ba94a037abab14b45b6 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Fri, 20 Oct 2023 16:51:05 -0400 Subject: [PATCH 06/18] feat: syncing status for all organizations --- .../20231020201652-OrgSyncStatus.js | 23 +++++++++++ src/database/migrations/index.js | 5 +++ src/middleware.js | 34 +++++++++++++-- .../organizations/organizations.model.js | 41 ++++++++++--------- .../organizations.modeltypes.cjs | 5 +++ src/tasks/sync-audit-table.js | 21 ++++++++-- 6 files changed, 101 insertions(+), 28 deletions(-) create mode 100644 src/database/migrations/20231020201652-OrgSyncStatus.js diff --git a/src/database/migrations/20231020201652-OrgSyncStatus.js b/src/database/migrations/20231020201652-OrgSyncStatus.js new file mode 100644 index 00000000..cc62e3fa --- /dev/null +++ b/src/database/migrations/20231020201652-OrgSyncStatus.js @@ -0,0 +1,23 @@ +'use strict'; + +export default { + async up(queryInterface, Sequelize) { + await Promise.all( + ['organizations'].map((table) => { + queryInterface.addColumn(table, 'synced', { + type: Sequelize.BOOLEAN, + allowNull: true, + defaultValue: false, + }); + }), + ); + }, + + async down(queryInterface) { + await Promise.all( + ['organizations'].map((table) => { + queryInterface.removeColumn(table, 'synced'); + }), + ); + }, +}; diff --git a/src/database/migrations/index.js b/src/database/migrations/index.js index 38371f65..9c289a41 100644 --- a/src/database/migrations/index.js +++ b/src/database/migrations/index.js @@ -30,6 +30,7 @@ import PopulateUnitsFTS from './20220808192709-populate-units-fts'; import ResetDBForNewSingletons from './20220816155101-reset-db-for-new-singletons'; import AddIsTransferColumn from './20220825124702-add-isTransfer-column'; import AddOrgMetadata from './20220831023546-add-org-metadata'; +import OrgSyncStatus from './20231020201652-OrgSyncStatus'; export const migrations = [ { @@ -164,4 +165,8 @@ export const migrations = [ migration: AddOrgMetadata, name: '20220831023546-add-org-metadata', }, + { + migration: OrgSyncStatus, + name: '20231020201652-OrgSyncStatus', + }, ]; diff --git a/src/middleware.js b/src/middleware.js index b9192891..159dd213 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -6,7 +6,6 @@ import bodyParser from 'body-parser'; import cors from 'cors'; import { V1Router } from './routes/v1'; import { getConfig } from './utils/config-loader'; -import { logger } from './config/logger.cjs'; import { assertChiaNetworkMatchInConfiguration, assertDataLayerAvailable, @@ -14,6 +13,7 @@ import { } from './utils/data-assertions'; import packageJson from '../package.json' assert { type: 'json' }; import datalayer from './datalayer'; +import { Organization } from './models'; const { CADT_API_KEY, READ_ONLY, IS_GOVERNANCE_BODY, USE_SIMULATOR } = getConfig().APP; @@ -24,6 +24,8 @@ const headerKeys = Object.freeze({ DATA_MODEL_VERION_HEADER_KEY: 'x-datamodel-version', GOVERNANCE_BODY_HEADER_KEY: 'x-governance-body', WALLET_SYNCED: 'x-wallet-synced', + HOME_ORGANIZATION_SYNCED: 'x-home-org-synced', + ALL_DATA_SYNCED: 'x-data-synced', }); const app = express(); @@ -88,9 +90,6 @@ app.use(function (req, res, next) { }); app.use(function (req, res, next) { - logger.info( - `Setting header x-api-verion to package.json version: ${packageJson.version}`, - ); const version = packageJson.version; res.setHeader(headerKeys.API_VERSION_HEADER_KEY, version); @@ -100,6 +99,33 @@ app.use(function (req, res, next) { next(); }); +app.use(async function (req, res, next) { + // If the home organization is syncing, then we treat all requests as read-only + const homeOrg = await Organization.getHomeOrg(); + + if (req.method !== 'GET' && !homeOrg.synced) { + res.status(400).json({ + message: + 'Your organization data is still resyncing, please try again after it completes', + success: false, + }); + } else if (homeOrg.synced) { + res.setHeader(headerKeys.HOME_ORGANIZATION_SYNCED, true); + } else { + res.setHeader(headerKeys.HOME_ORGANIZATION_SYNCED, false); + } + + next(); +}); + +app.use(async function (req, res, next) { + const orgMap = await Organization.getOrgsMap(); + const notSynced = Object.keys(orgMap).find((key) => !orgMap[key].synced); + + res.setHeader(headerKeys.ALL_DATA_SYNCED, !notSynced); + next(); +}); + app.use(async function (req, res, next) { if (USE_SIMULATOR) { res.setHeader(headerKeys.WALLET_SYNCED, true); diff --git a/src/models/organizations/organizations.model.js b/src/models/organizations/organizations.model.js index 79b0a3f7..11a9a7a2 100644 --- a/src/models/organizations/organizations.model.js +++ b/src/models/organizations/organizations.model.js @@ -33,6 +33,7 @@ class Organization extends Model { 'registryId', 'fileStoreId', 'metadata', + 'synced', ], where: { isHome: true }, raw: true, @@ -52,13 +53,15 @@ class Organization extends Model { delete myOrganization.metadata; } + myOrganization.synced = myOrganization.synced === 1; + if (myOrganization && includeAddress) { myOrganization.xchAddress = await datalayer.getPublicAddress(); myOrganization.fileStoreSubscribed = true; return myOrganization; } - return undefined; + return myOrganization; } static async getOrgsMap() { @@ -69,6 +72,7 @@ class Organization extends Model { 'icon', 'isHome', 'subscribed', + 'synced', 'fileStoreSubscribed', ], }); @@ -256,8 +260,7 @@ class Organization extends Model { }); } - // eslint-disable-next-line - static importOrganization = async (orgUid) => { + static async importOrganization(orgUid) { try { console.log('Importing organization ' + orgUid); const orgData = await datalayer.getSubscribedStoreData(orgUid); @@ -310,10 +313,9 @@ class Organization extends Model { } catch (error) { logger.info(error.message); } - }; + } - // eslint-disable-next-line - static subscribeToOrganization = async (orgUid) => { + static async subscribeToOrganization(orgUid) { const exists = await Organization.findOne({ where: { orgUid } }); if (exists) { await Organization.update({ subscribed: true }, { where: { orgUid } }); @@ -322,14 +324,13 @@ class Organization extends Model { 'Can not subscribe, please import this organization first', ); } - }; + } - // eslint-disable-next-line - static unsubscribeToOrganization = async (orgUid) => { + static async unsubscribeToOrganization(orgUid) { await Organization.update({ subscribed: false }, { orgUid }); - }; + } - static syncOrganizationMeta = async () => { + static async syncOrganizationMeta() { try { const allSubscribedOrganizations = await Organization.findAll({ subscribed: true, @@ -389,9 +390,9 @@ class Organization extends Model { } catch (error) { logger.info(error.message); } - }; + } - static subscribeToDefaultOrganizations = async () => { + static async subscribeToDefaultOrganizations() { try { const defaultOrgs = await getDefaultOrganizationList(); if (!Array.isArray(defaultOrgs)) { @@ -414,9 +415,9 @@ class Organization extends Model { } catch (error) { logger.info(error); } - }; + } - static editOrgMeta = async ({ name, icon }) => { + static async editOrgMeta({ name, icon }) { const myOrganization = await Organization.getHomeOrg(); const payload = {}; @@ -430,20 +431,20 @@ class Organization extends Model { } await datalayer.upsertDataLayer(myOrganization.orgUid, payload); - }; + } - static addMetadata = async (payload) => { + static async addMetadata(payload) { const myOrganization = await Organization.getHomeOrg(); // Prefix keys with "meta_" const metadata = _.mapKeys(payload, (_value, key) => `meta_${key}`); await datalayer.upsertDataLayer(myOrganization.orgUid, metadata); - }; + } - static removeMirror = async (storeId, coinId) => { + static async removeMirror(storeId, coinId) { datalayer.removeMirror(storeId, coinId); - }; + } } Organization.init(ModelTypes, { diff --git a/src/models/organizations/organizations.modeltypes.cjs b/src/models/organizations/organizations.modeltypes.cjs index ffe2d704..77a7df85 100644 --- a/src/models/organizations/organizations.modeltypes.cjs +++ b/src/models/organizations/organizations.modeltypes.cjs @@ -33,6 +33,11 @@ module.exports = { allowNull: true, defaultValue: '{}', }, + synced: { + type: Sequelize.BOOLEAN, + allowNull: true, + defaultValue: false, + }, createdAt: Sequelize.DATE, updatedAt: Sequelize.DATE, }; diff --git a/src/tasks/sync-audit-table.js b/src/tasks/sync-audit-table.js index f865bd1b..9007b5f2 100644 --- a/src/tasks/sync-audit-table.js +++ b/src/tasks/sync-audit-table.js @@ -55,6 +55,11 @@ const task = new Task('sync-audit', async () => { metaKey: 'migratedToNewSync', metaValue: 'true', }); + + await Organization.upsert({ + synced: false, + }); + logger.info(`Migration Complete`); } } @@ -155,6 +160,8 @@ const syncOrganizationAudit = async (organization) => { try { logger.info(`Syncing Registry: ${_.get(organization, 'name')}`); let afterCommitCallbacks = []; + + const homeOrg = await Organization.getHomeOrg(); const rootHistory = await datalayer.getRootHistory(organization.registryId); let lastRootSaved; @@ -198,7 +205,7 @@ const syncOrganizationAudit = async (organization) => { // Destroy existing records for this singleton // On a fresh db this does nothing, but when the audit table - // is reset this will ensure that this organizations regsitry data is + // is reset this will ensure that this organizations registry data is // cleaned up on both the local db and mirror db and ready to resync await Promise.all( Object.keys(ModelKeys).map(async (modelKey) => { @@ -213,7 +220,15 @@ const syncOrganizationAudit = async (organization) => { return; } - if (historyIndex === rootHistory.length) { + const isSynced = rootHistory[rootHistory.length - 1].root_hash === rootHash; + + await Organization.update( + { synced: isSynced }, + { where: { orgUid: organization.orgUid } }, + ); + + if (isSynced) { + logger.info(`No new data to sync for ${organization.name}`); return; } @@ -254,8 +269,6 @@ const syncOrganizationAudit = async (organization) => { return typeOrder[a.type] - typeOrder[b.type]; }); - const homeOrg = await Organization.getHomeOrg(); - const updateTransaction = async (transaction, mirrorTransaction) => { for (const diff of kvDiff) { const key = decodeHex(diff.key); From d82fb12660d27220a53571d39342a45b6825672f Mon Sep 17 00:00:00 2001 From: Chia Automation Date: Fri, 20 Oct 2023 21:27:18 +0000 Subject: [PATCH 07/18] chore: Updating npm dev dependencies --- package-lock.json | 2220 ++++++++++++++++++++++++++++++--------------- package.json | 12 +- 2 files changed, 1519 insertions(+), 713 deletions(-) diff --git a/package-lock.json b/package-lock.json index 70284f98..ee9445ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cadt", - "version": "1.6.14", + "version": "1.6.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cadt", - "version": "1.6.14", + "version": "1.6.15", "dependencies": { "@babel/eslint-parser": "^7.22.9", "body-parser": "^1.20.2", @@ -39,22 +39,22 @@ }, "devDependencies": { "@babel/cli": "^7.23.0", - "@babel/core": "^7.23.0", + "@babel/core": "^7.23.2", "@babel/plugin-syntax-import-attributes": "^7.22.5", - "@babel/preset-env": "^7.22.20", + "@babel/preset-env": "^7.23.2", "@babel/register": "^7.22.15", - "@commitlint/cli": "^17.7.2", - "@commitlint/config-conventional": "^17.7.0", + "@commitlint/cli": "^18.0.0", + "@commitlint/config-conventional": "^18.0.0", "babel-plugin-module-resolver": "^5.0.0", "chai": "^4.3.10", "chai-http": "^4.4.0", - "eslint": "^8.50.0", + "eslint": "^8.52.0", "eslint-plugin-es": "^4.1.0", "eslint-plugin-mocha": "^10.2.0", "husky": "^8.0.3", "mocha": "^10.2.0", "semver": "^7.5.4", - "sinon": "^16.1.0", + "sinon": "^17.0.0", "socket.io-client": "^4.7.2", "standard-version": "^9.5.0", "supertest": "^6.3.3" @@ -125,27 +125,27 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz", - "integrity": "sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", + "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.0.tgz", - "integrity": "sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", + "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.22.13", "@babel/generator": "^7.23.0", "@babel/helper-compilation-targets": "^7.22.15", "@babel/helper-module-transforms": "^7.23.0", - "@babel/helpers": "^7.23.0", + "@babel/helpers": "^7.23.2", "@babel/parser": "^7.23.0", "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.0", + "@babel/traverse": "^7.23.2", "@babel/types": "^7.23.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -314,9 +314,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz", - "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz", + "integrity": "sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==", "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", @@ -529,12 +529,12 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.1.tgz", - "integrity": "sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", "dependencies": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.0", + "@babel/traverse": "^7.23.2", "@babel/types": "^7.23.0" }, "engines": { @@ -860,14 +860,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz", - "integrity": "sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.2.tgz", + "integrity": "sha512-BBYVGxbDVHfoeXbOwcagAkOQAm9NxoTdMGfTqghu1GrvadSaw6iW3Je6IcL5PNOw8VwjxqBECXy50/iCQSY/lQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.9", + "@babel/helper-remap-async-to-generator": "^7.22.20", "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { @@ -1617,12 +1617,12 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.20.tgz", - "integrity": "sha512-11MY04gGC4kSzlPHRfvVkNAZhUxOvm7DCJ37hPDnUENwe06npjIRAfInEMTGSb4LZK5ZgDFkv5hw0lGebHeTyg==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.2.tgz", + "integrity": "sha512-BW3gsuDD+rvHL2VO2SjAUNTBe5YrjsTiDyqamPDWY723na3/yPQ65X5oQkFVJZ0o50/2d+svm1rkPoJeR1KxVQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.22.20", + "@babel/compat-data": "^7.23.2", "@babel/helper-compilation-targets": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-option": "^7.22.15", @@ -1648,15 +1648,15 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.22.5", - "@babel/plugin-transform-async-generator-functions": "^7.22.15", + "@babel/plugin-transform-async-generator-functions": "^7.23.2", "@babel/plugin-transform-async-to-generator": "^7.22.5", "@babel/plugin-transform-block-scoped-functions": "^7.22.5", - "@babel/plugin-transform-block-scoping": "^7.22.15", + "@babel/plugin-transform-block-scoping": "^7.23.0", "@babel/plugin-transform-class-properties": "^7.22.5", "@babel/plugin-transform-class-static-block": "^7.22.11", "@babel/plugin-transform-classes": "^7.22.15", "@babel/plugin-transform-computed-properties": "^7.22.5", - "@babel/plugin-transform-destructuring": "^7.22.15", + "@babel/plugin-transform-destructuring": "^7.23.0", "@babel/plugin-transform-dotall-regex": "^7.22.5", "@babel/plugin-transform-duplicate-keys": "^7.22.5", "@babel/plugin-transform-dynamic-import": "^7.22.11", @@ -1668,9 +1668,9 @@ "@babel/plugin-transform-literals": "^7.22.5", "@babel/plugin-transform-logical-assignment-operators": "^7.22.11", "@babel/plugin-transform-member-expression-literals": "^7.22.5", - "@babel/plugin-transform-modules-amd": "^7.22.5", - "@babel/plugin-transform-modules-commonjs": "^7.22.15", - "@babel/plugin-transform-modules-systemjs": "^7.22.11", + "@babel/plugin-transform-modules-amd": "^7.23.0", + "@babel/plugin-transform-modules-commonjs": "^7.23.0", + "@babel/plugin-transform-modules-systemjs": "^7.23.0", "@babel/plugin-transform-modules-umd": "^7.22.5", "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", "@babel/plugin-transform-new-target": "^7.22.5", @@ -1679,7 +1679,7 @@ "@babel/plugin-transform-object-rest-spread": "^7.22.15", "@babel/plugin-transform-object-super": "^7.22.5", "@babel/plugin-transform-optional-catch-binding": "^7.22.11", - "@babel/plugin-transform-optional-chaining": "^7.22.15", + "@babel/plugin-transform-optional-chaining": "^7.23.0", "@babel/plugin-transform-parameters": "^7.22.15", "@babel/plugin-transform-private-methods": "^7.22.5", "@babel/plugin-transform-private-property-in-object": "^7.22.11", @@ -1696,10 +1696,10 @@ "@babel/plugin-transform-unicode-regex": "^7.22.5", "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", "@babel/preset-modules": "0.1.6-no-external-plugins", - "@babel/types": "^7.22.19", - "babel-plugin-polyfill-corejs2": "^0.4.5", - "babel-plugin-polyfill-corejs3": "^0.8.3", - "babel-plugin-polyfill-regenerator": "^0.5.2", + "@babel/types": "^7.23.0", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", "core-js-compat": "^3.31.0", "semver": "^6.3.1" }, @@ -1759,9 +1759,9 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.23.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.1.tgz", - "integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -1790,9 +1790,9 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz", - "integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dependencies": { "@babel/code-frame": "^7.22.13", "@babel/generator": "^7.23.0", @@ -1823,24 +1823,24 @@ } }, "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", "engines": { "node": ">=0.1.90" } }, "node_modules/@commitlint/cli": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-17.7.2.tgz", - "integrity": "sha512-t3N7TZq7lOeqTOyEgfGcaltHqEJf7YDlPg75MldeVPPyz14jZq/+mbGF9tueDLFX8R6RwdymrN6D+U5XwZ8Iwg==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-18.0.0.tgz", + "integrity": "sha512-0HuJB7VfxSqia0r+mZ9VLgTc5gPaRDiQtloLfwCBp63PvpFn2sZsidiZBbym3jDC6+P47HSuIdRRg3/JsCcBwA==", "dev": true, "dependencies": { - "@commitlint/format": "^17.4.4", - "@commitlint/lint": "^17.7.0", - "@commitlint/load": "^17.7.2", - "@commitlint/read": "^17.5.1", - "@commitlint/types": "^17.4.4", + "@commitlint/format": "^18.0.0", + "@commitlint/lint": "^18.0.0", + "@commitlint/load": "^18.0.0", + "@commitlint/read": "^18.0.0", + "@commitlint/types": "^18.0.0", "execa": "^5.0.0", "lodash.isfunction": "^3.0.9", "resolve-from": "5.0.0", @@ -1851,41 +1851,41 @@ "commitlint": "cli.js" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/config-conventional": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-17.7.0.tgz", - "integrity": "sha512-iicqh2o6et+9kWaqsQiEYZzfLbtoWv9uZl8kbI8EGfnc0HeGafQBF7AJ0ylN9D/2kj6txltsdyQs8+2fTMwWEw==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-18.0.0.tgz", + "integrity": "sha512-XZW3MDwhMWwr7pf+jO5F18ohBwrJ8mt+1OPhkVyO8bYrY0dKPE5tPpdXlDt+JCFurl4VnUDPmu6xZ4/cKCH7cA==", "dev": true, "dependencies": { - "conventional-changelog-conventionalcommits": "^6.1.0" + "conventional-changelog-conventionalcommits": "^7.0.2" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/config-validator": { - "version": "17.6.7", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-17.6.7.tgz", - "integrity": "sha512-vJSncmnzwMvpr3lIcm0I8YVVDJTzyjy7NZAeXbTXy+MPUdAr9pKyyg7Tx/ebOQ9kqzE6O9WT6jg2164br5UdsQ==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-18.0.0.tgz", + "integrity": "sha512-PlXy5QZzQeMgQM7jb0odIhxsI6GWcbGgfy+Hkz5ap31KES/oJgtEvgD8pjg0Z9Ri296bT6zK3ts6brS0MAcMgg==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", + "@commitlint/types": "^18.0.0", "ajv": "^8.11.0" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/ensure": { - "version": "17.6.7", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-17.6.7.tgz", - "integrity": "sha512-mfDJOd1/O/eIb/h4qwXzUxkmskXDL9vNPnZ4AKYKiZALz4vHzwMxBSYtyL2mUIDeU9DRSpEUins8SeKtFkYHSw==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-18.0.0.tgz", + "integrity": "sha512-AhzK4ybWGVmO7lwC33dGujS0k2IZDNFiew80M1H2R5Ou7Qkqq7sbuMZoof+yjOQcqltYP4IHLd0YECZoGermvQ==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", + "@commitlint/types": "^18.0.0", "lodash.camelcase": "^4.3.0", "lodash.kebabcase": "^4.1.1", "lodash.snakecase": "^4.1.1", @@ -1893,29 +1893,29 @@ "lodash.upperfirst": "^4.3.1" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/execute-rule": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-17.4.0.tgz", - "integrity": "sha512-LIgYXuCSO5Gvtc0t9bebAMSwd68ewzmqLypqI2Kke1rqOqqDbMpYcYfoPfFlv9eyLIh4jocHWwCK5FS7z9icUA==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-18.0.0.tgz", + "integrity": "sha512-eNUSaHajb+g3sgZeIrfc6cXNnKIkYN2SXtDVXuiE+hOa055T0bLdZK29gSd945JCztxPVwdOkPLDeLg3NfDubg==", "dev": true, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/format": { - "version": "17.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-17.4.4.tgz", - "integrity": "sha512-+IS7vpC4Gd/x+uyQPTAt3hXs5NxnkqAZ3aqrHd5Bx/R9skyCAWusNlNbw3InDbAK6j166D9asQM8fnmYIa+CXQ==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-18.0.0.tgz", + "integrity": "sha512-etvUmOufihecdNm0r5+rCetrO2Yj7fSkJ4f0k8xOzqrrNdID9G/6iK14i/ufISBLSSy0XzsiiV+Rn9TX/cg46Q==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", + "@commitlint/types": "^18.0.0", "chalk": "^4.1.0" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/format/node_modules/ansi-styles": { @@ -1989,44 +1989,44 @@ } }, "node_modules/@commitlint/is-ignored": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-17.7.0.tgz", - "integrity": "sha512-043rA7m45tyEfW7Zv2vZHF++176MLHH9h70fnPoYlB1slKBeKl8BwNIlnPg4xBdRBVNPaCqvXxWswx2GR4c9Hw==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-18.0.0.tgz", + "integrity": "sha512-fAUOF4GlKTmreE5hxhLlVUcXd1aIexxn+edocbMSwOa4dcm8OoHbsLcDB/rhwXIK+jzK4DybCMCx1VaTeRC4SQ==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", + "@commitlint/types": "^18.0.0", "semver": "7.5.4" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/lint": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-17.7.0.tgz", - "integrity": "sha512-TCQihm7/uszA5z1Ux1vw+Nf3yHTgicus/+9HiUQk+kRSQawByxZNESeQoX9ujfVd3r4Sa+3fn0JQAguG4xvvbA==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-18.0.0.tgz", + "integrity": "sha512-Vqg6sIPm7nELu/U4lEzKMdLYaELgwSySGZzKc2YjJxdJWyiQo0b1hfCpxXsWGdNBOt0+CM4eBAGoX/Kjq5AYNA==", "dev": true, "dependencies": { - "@commitlint/is-ignored": "^17.7.0", - "@commitlint/parse": "^17.7.0", - "@commitlint/rules": "^17.7.0", - "@commitlint/types": "^17.4.4" + "@commitlint/is-ignored": "^18.0.0", + "@commitlint/parse": "^18.0.0", + "@commitlint/rules": "^18.0.0", + "@commitlint/types": "^18.0.0" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/load": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-17.7.2.tgz", - "integrity": "sha512-XA7WTnsjHZ4YH6ZYsrnxgLdXzriwMMq+utZUET6spbOEEIPBCDLdOQXS26P+v3TTO4hUHOEhzUquaBv3jbBixw==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-18.0.0.tgz", + "integrity": "sha512-ocvMSkzNZCJ4yV673xjd4Y7sFVG/mg7S6yvL5ioM0OIG2XTbcCdzpmq+BeJcIwsRYU9g/b688yh7RDzGlbai6w==", "dev": true, "dependencies": { - "@commitlint/config-validator": "^17.6.7", - "@commitlint/execute-rule": "^17.4.0", - "@commitlint/resolve-extends": "^17.6.7", - "@commitlint/types": "^17.4.4", - "@types/node": "20.5.1", + "@commitlint/config-validator": "^18.0.0", + "@commitlint/execute-rule": "^18.0.0", + "@commitlint/resolve-extends": "^18.0.0", + "@commitlint/types": "^18.0.0", + "@types/node": "^18.11.9", "chalk": "^4.1.0", "cosmiconfig": "^8.0.0", "cosmiconfig-typescript-loader": "^4.0.0", @@ -2035,10 +2035,10 @@ "lodash.uniq": "^4.5.0", "resolve-from": "^5.0.0", "ts-node": "^10.8.1", - "typescript": "^4.6.4 || ^5.0.0" + "typescript": "^5.2.2" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/load/node_modules/ansi-styles": { @@ -2112,108 +2112,108 @@ } }, "node_modules/@commitlint/message": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-17.4.2.tgz", - "integrity": "sha512-3XMNbzB+3bhKA1hSAWPCQA3lNxR4zaeQAQcHj0Hx5sVdO6ryXtgUBGGv+1ZCLMgAPRixuc6en+iNAzZ4NzAa8Q==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-18.0.0.tgz", + "integrity": "sha512-FJmEBn81RMEZrG1E1BxmjNoe/Rz918IeIGJRe5YXxM7IXboFhKS69rHPttNjKwSS038t6GUsRUJrAWqZnA6nCw==", "dev": true, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/parse": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-17.7.0.tgz", - "integrity": "sha512-dIvFNUMCUHqq5Abv80mIEjLVfw8QNuA4DS7OWip4pcK/3h5wggmjVnlwGCDvDChkw2TjK1K6O+tAEV78oxjxag==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-18.0.0.tgz", + "integrity": "sha512-qbZYOCpIZzfFzV35s5ei3JkBG/8KUOyGYluAeaYIcYC9z0uKXEVK6O2F2P/KLvbTkgZ4Q9OOLDrrtoWzPb2pjg==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", + "@commitlint/types": "^18.0.0", "conventional-changelog-angular": "^6.0.0", - "conventional-commits-parser": "^4.0.0" + "conventional-commits-parser": "^5.0.0" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/read": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-17.5.1.tgz", - "integrity": "sha512-7IhfvEvB//p9aYW09YVclHbdf1u7g7QhxeYW9ZHSO8Huzp8Rz7m05aCO1mFG7G8M+7yfFnXB5xOmG18brqQIBg==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-18.0.0.tgz", + "integrity": "sha512-VclRvG+ZvHOjYP4rmKPfNwS7eSI5m68D/CPtT2do/D4EBljmLBwqCYVL1I/3y2E6Fbub1GfYoXiRHThd1cVlag==", "dev": true, "dependencies": { - "@commitlint/top-level": "^17.4.0", - "@commitlint/types": "^17.4.4", + "@commitlint/top-level": "^18.0.0", + "@commitlint/types": "^18.0.0", "fs-extra": "^11.0.0", "git-raw-commits": "^2.0.11", "minimist": "^1.2.6" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/resolve-extends": { - "version": "17.6.7", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-17.6.7.tgz", - "integrity": "sha512-PfeoAwLHtbOaC9bGn/FADN156CqkFz6ZKiVDMjuC2N5N0740Ke56rKU7Wxdwya8R8xzLK9vZzHgNbuGhaOVKIg==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-18.0.0.tgz", + "integrity": "sha512-MD9+6GSiWvqgdJtfos+1gqz+zmy2vV7TbUVz2ETZzpfECgmUZSZSYzyivivBAQK6feS71KxmMLL8+YFF9+FFRQ==", "dev": true, "dependencies": { - "@commitlint/config-validator": "^17.6.7", - "@commitlint/types": "^17.4.4", + "@commitlint/config-validator": "^18.0.0", + "@commitlint/types": "^18.0.0", "import-fresh": "^3.0.0", "lodash.mergewith": "^4.6.2", "resolve-from": "^5.0.0", "resolve-global": "^1.0.0" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/rules": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-17.7.0.tgz", - "integrity": "sha512-J3qTh0+ilUE5folSaoK91ByOb8XeQjiGcdIdiB/8UT1/Rd1itKo0ju/eQVGyFzgTMYt8HrDJnGTmNWwcMR1rmA==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-18.0.0.tgz", + "integrity": "sha512-J7xjMKC4H1hfZR8fmPPuV35wS8Vgy3YX9xIpfPJhsDnRk2BL/dyZjNEXPdvlbpvkNgkfIWi0A0IDtW1dDoViag==", "dev": true, "dependencies": { - "@commitlint/ensure": "^17.6.7", - "@commitlint/message": "^17.4.2", - "@commitlint/to-lines": "^17.4.0", - "@commitlint/types": "^17.4.4", + "@commitlint/ensure": "^18.0.0", + "@commitlint/message": "^18.0.0", + "@commitlint/to-lines": "^18.0.0", + "@commitlint/types": "^18.0.0", "execa": "^5.0.0" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/to-lines": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-17.4.0.tgz", - "integrity": "sha512-LcIy/6ZZolsfwDUWfN1mJ+co09soSuNASfKEU5sCmgFCvX5iHwRYLiIuoqXzOVDYOy7E7IcHilr/KS0e5T+0Hg==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-18.0.0.tgz", + "integrity": "sha512-HwwBvzXX+3x7XYvBrEKy69S9w/clUEL0gMwkXTtg5awUpvEvzmTz1FBE/5WIiUICyOGdH1NhV1WgKb7UwOnI4A==", "dev": true, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/top-level": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-17.4.0.tgz", - "integrity": "sha512-/1loE/g+dTTQgHnjoCy0AexKAEFyHsR2zRB4NWrZ6lZSMIxAhBJnmCqwao7b4H8888PsfoTBCLBYIw8vGnej8g==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-18.0.0.tgz", + "integrity": "sha512-6+jjZhe9pF7ioD9IR2HChteTh95KPXa7GUUV52e0YhEsFArkCnyhzSL72ko1c2Xad0sWNBL0e76mifi20wD/Bg==", "dev": true, "dependencies": { "find-up": "^5.0.0" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/types": { - "version": "17.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-17.4.4.tgz", - "integrity": "sha512-amRN8tRLYOsxRr6mTnGGGvB5EmW/4DDjLMgiwK3CCVEmN6Sr/6xePGEpWaspKkckILuUORCwe6VfDBw6uj4axQ==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-18.0.0.tgz", + "integrity": "sha512-FDzAdSm7kIir0NW0bZLENdrEgf/9Ihs1AAqE9DK9R+dRFby4ookkxPMaz7elZmG+e5rBl7hGrWJzJINqG9cDDg==", "dev": true, "dependencies": { "chalk": "^4.1.0" }, "engines": { - "node": ">=v14" + "node": ">=v18" } }, "node_modules/@commitlint/types/node_modules/ansi-styles": { @@ -2419,9 +2419,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", - "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", + "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -2446,11 +2446,11 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", - "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, @@ -2471,9 +2471,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==" }, "node_modules/@hutson/parse-repository-url": { "version": "3.0.2", @@ -2519,9 +2519,9 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -2679,9 +2679,9 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", + "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.0" @@ -2752,9 +2752,9 @@ "dev": true }, "node_modules/@types/chai": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.6.tgz", - "integrity": "sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==", + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.9.tgz", + "integrity": "sha512-69TtiDzu0bcmKQv3yg1Zx409/Kd7r0b5F1PfpYJfSHzLGtB53547V4u+9iqKYsTu/O2ai6KTb0TInNpvuQ3qmg==", "dev": true }, "node_modules/@types/cookie": { @@ -2763,47 +2763,47 @@ "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" }, "node_modules/@types/cookiejar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", - "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.3.tgz", + "integrity": "sha512-LZ8SD3LpNmLMDLkG2oCBjZg+ETnx6XdCjydUE0HwojDmnDfDUnhMKKbtth1TZh+hzcqb03azrYWoXLS8sMXdqg==", "dev": true }, "node_modules/@types/cors": { - "version": "2.8.14", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.14.tgz", - "integrity": "sha512-RXHUvNWYICtbP6s18PnOCaqToK8y14DnLd75c6HfyKf228dxy7pHNOQkxPtvXKp/hINFMDjbYzsj63nnpPMSRQ==", + "version": "2.8.15", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.15.tgz", + "integrity": "sha512-n91JxbNLD8eQIuXDIChAN1tCKNWCEgpceU9b7ZMbFA+P+Q4yIeh80jizFLEvolRPc1ES0VdwFlGv+kJTSirogw==", "dependencies": { "@types/node": "*" } }, "node_modules/@types/debug": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.9.tgz", - "integrity": "sha512-8Hz50m2eoS56ldRlepxSBa6PWEVCtzUo/92HgLc2qTMnotJNIm7xP+UZhyWoYsyOdd5dxZ+NZLb24rsKyFs2ow==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.10.tgz", + "integrity": "sha512-tOSCru6s732pofZ+sMv9o4o3Zc+Sa8l3bxd/tweTQudFn06vAzb13ZX46Zi6m6EJ+RUbRTHvgQJ1gBtSgkaUYA==", "dependencies": { "@types/ms": "*" } }, "node_modules/@types/minimist": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.3.tgz", - "integrity": "sha512-ZYFzrvyWUNhaPomn80dsMNgMeXxNWZBdkuG/hWlUvXvbdUH8ZERNBGXnU87McuGcWDsyzX2aChCv/SVN348k3A==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.4.tgz", + "integrity": "sha512-Kfe/D3hxHTusnPNRbycJE1N77WHDsdS4AjUYIzlDzhDrS47NrwuL3YW4VITxwR7KCVpzwgy4Rbj829KSSQmwXQ==", "dev": true }, "node_modules/@types/ms": { - "version": "0.7.32", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.32.tgz", - "integrity": "sha512-xPSg0jm4mqgEkNhowKgZFBNtwoEwF6gJ4Dhww+GFpm3IgtNseHQZ5IqdNwnquZEoANxyDAKDRAdVo4Z72VvD/g==" + "version": "0.7.33", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.33.tgz", + "integrity": "sha512-AuHIyzR5Hea7ij0P9q7vx7xu4z0C28ucwjAZC0ja7JhINyCnOw8/DnvAPQQ9TfOlCtZAmCERKQX9+o1mgQhuOQ==" }, "node_modules/@types/node": { - "version": "20.5.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz", - "integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==" + "version": "18.18.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.6.tgz", + "integrity": "sha512-wf3Vz+jCmOQ2HV1YUJuCWdL64adYxumkrxtc+H1VUQlnQI04+5HtH+qZCOE21lBE7gIrt+CwX2Wv8Acrw5Ak6w==" }, "node_modules/@types/normalize-package-data": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.2.tgz", - "integrity": "sha512-lqa4UEhhv/2sjjIQgjX8B+RBjj47eo0mzGasklVJ78UKGQY1r0VpB9XHDaZZO9qzEFDdy4MrXLuEaSmPrPSe/A==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.3.tgz", + "integrity": "sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg==", "dev": true }, "node_modules/@types/superagent": { @@ -2817,9 +2817,9 @@ } }, "node_modules/@types/triple-beam": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.3.tgz", - "integrity": "sha512-6tOUG+nVHn0cJbVp25JFayS5UE6+xlbcNF9Lo9mU7U0zk3zeUShZied4YEQZjy1JBF043FSkdXw8YkUJuVtB5g==" + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.4.tgz", + "integrity": "sha512-HlJjF3wxV4R2VQkFpKe0YqJLilYNgtRtsqqZtby7RkVsSs+i+vbyzjtUwpFEdUCKcrGzCiEJE7F/0mKjh0sunA==" }, "node_modules/@types/uuid": { "version": "8.3.4", @@ -2827,9 +2827,14 @@ "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" }, "node_modules/@types/validator": { - "version": "13.11.2", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.2.tgz", - "integrity": "sha512-nIKVVQKT6kGKysnNt+xLobr+pFJNssJRi2s034wgWeFBUx01fI8BeHTW2TcRp7VcFu9QCYG8IlChTuovcm0oKQ==" + "version": "13.11.5", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.5.tgz", + "integrity": "sha512-xW4qsT4UIYILu+7ZrBnfQdBYniZrMLYYK3wN9M/NdeIHgBN5pZI2/8Q7UfdWIcr5RLJv/OGENsx91JIpUUoC7Q==" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, "node_modules/abbrev": { "version": "1.1.1", @@ -3144,13 +3149,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz", - "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==", + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz", + "integrity": "sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==", "dev": true, "dependencies": { "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.4.2", + "@babel/helper-define-polyfill-provider": "^0.4.3", "semver": "^6.3.1" }, "peerDependencies": { @@ -3167,12 +3172,12 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.4.tgz", - "integrity": "sha512-9l//BZZsPR+5XjyJMPtZSK4jv0BsTO1zDac2GC6ygx9WLGlcsnRd1Co0B2zT5fF5Ic6BZy+9m3HNZ3QcOeDKfg==", + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.5.tgz", + "integrity": "sha512-Q6CdATeAvbScWPNLB8lzSO7fgUVBkQt6zLgNlfyeCr/EQaEQR+bWiBYYPYAFyE528BMjRhL+1QBMOI4jc/c5TA==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.2", + "@babel/helper-define-polyfill-provider": "^0.4.3", "core-js-compat": "^3.32.2" }, "peerDependencies": { @@ -3180,12 +3185,12 @@ } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz", - "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz", + "integrity": "sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.2" + "@babel/helper-define-polyfill-provider": "^0.4.3" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -3396,12 +3401,13 @@ "optional": true }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3416,12 +3422,15 @@ } }, "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/camelcase-keys": { @@ -3441,10 +3450,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/caniuse-lite": { - "version": "1.0.30001546", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz", - "integrity": "sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==", + "version": "1.0.30001551", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001551.tgz", + "integrity": "sha512-vtBAez47BoGMMzlbYhfXrMV1kvRF2WP/lqiMuDu1Sb4EE4LKEgjopFDSRtZfdVnslNRpOqV/woE+Xgrwj6VQlg==", "funding": [ { "type": "opencollective", @@ -3884,15 +3902,15 @@ "dev": true }, "node_modules/conventional-changelog-conventionalcommits": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-6.1.0.tgz", - "integrity": "sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", + "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", "dev": true, "dependencies": { "compare-func": "^2.0.0" }, "engines": { - "node": ">=14" + "node": ">=16" } }, "node_modules/conventional-changelog-core": { @@ -3941,15 +3959,16 @@ } }, "node_modules/conventional-changelog-core/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "dependencies": { - "locate-path": "^2.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/conventional-changelog-core/node_modules/hosted-git-info": { @@ -3958,110 +3977,156 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, - "node_modules/conventional-changelog-core/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "node_modules/conventional-changelog-core/node_modules/is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", "dev": true, "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "text-extensions": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/conventional-changelog-core/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "node_modules/conventional-changelog-core/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "dependencies": { - "p-try": "^1.0.0" + "p-locate": "^4.1.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/conventional-changelog-core/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "node_modules/conventional-changelog-core/node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", "dev": true, "dependencies": { - "p-limit": "^1.1.0" + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/conventional-changelog-core/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "node_modules/conventional-changelog-core/node_modules/meow/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/conventional-changelog-core/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "node_modules/conventional-changelog-core/node_modules/meow/node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, "dependencies": { - "pify": "^3.0.0" + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/conventional-changelog-core/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "node_modules/conventional-changelog-core/node_modules/meow/node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/conventional-changelog-core/node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "node_modules/conventional-changelog-core/node_modules/meow/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/conventional-changelog-core/node_modules/meow/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/conventional-changelog-core/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/conventional-changelog-core/node_modules/read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", + "node_modules/conventional-changelog-core/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" + "p-limit": "^2.2.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/conventional-changelog-core/node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "node_modules/conventional-changelog-core/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/conventional-changelog-core/node_modules/semver": { @@ -4073,6 +4138,36 @@ "semver": "bin/semver" } }, + "node_modules/conventional-changelog-core/node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/conventional-changelog-core/node_modules/text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/conventional-changelog-core/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/conventional-changelog-ember": { "version": "2.0.9", "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz", @@ -4166,18 +4261,184 @@ "node": ">=10" } }, - "node_modules/conventional-changelog-writer/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/conventional-changelog-writer/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/conventional-changelog/node_modules/conventional-changelog-angular": { - "version": "5.0.13", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", + "node_modules/conventional-changelog-writer/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/conventional-changelog-writer/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/conventional-changelog-writer/node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog-writer/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog-writer/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/conventional-changelog-writer/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/conventional-changelog-writer/node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog-writer/node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/conventional-changelog-writer/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/conventional-changelog-writer/node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/conventional-changelog-writer/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/conventional-changelog-writer/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/conventional-changelog-writer/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-changelog/node_modules/conventional-changelog-angular": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==", "dev": true, "dependencies": { @@ -4216,21 +4477,21 @@ } }, "node_modules/conventional-commits-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz", - "integrity": "sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", "dev": true, "dependencies": { - "is-text-path": "^1.0.1", + "is-text-path": "^2.0.0", "JSONStream": "^1.3.5", - "meow": "^8.1.2", - "split2": "^3.2.2" + "meow": "^12.0.1", + "split2": "^4.0.0" }, "bin": { - "conventional-commits-parser": "cli.js" + "conventional-commits-parser": "cli.mjs" }, "engines": { - "node": ">=14" + "node": ">=16" } }, "node_modules/conventional-recommended-bump": { @@ -4290,93 +4551,289 @@ "node": ">=10" } }, - "node_modules/conventional-recommended-bump/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/conventional-recommended-bump/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">= 6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "node_modules/cookiejar": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", - "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==" + "node_modules/conventional-recommended-bump/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true }, - "node_modules/core-js-compat": { - "version": "3.33.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.0.tgz", - "integrity": "sha512-0w4LcLXsVEuNkIqwjjf9rjCoPhK8uqA4tMRh4Ge26vfLtUutshn+aRJU21I9LCJlh2QQHfisNToLjw1XEJLTWw==", + "node_modules/conventional-recommended-bump/node_modules/is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", "dev": true, "dependencies": { - "browserslist": "^4.22.1" + "text-extensions": "^1.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "node_modules/conventional-recommended-bump/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, "dependencies": { - "object-assign": "^4", - "vary": "^1" + "p-locate": "^4.1.0" }, "engines": { - "node": ">= 0.10" + "node": ">=8" } }, - "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "node_modules/conventional-recommended-bump/node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", "dev": true, "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" }, "engines": { - "node": ">=14" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-recommended-bump/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-recommended-bump/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/conventional-recommended-bump/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/conventional-recommended-bump/node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/conventional-recommended-bump/node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/conventional-recommended-bump/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/conventional-recommended-bump/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/conventional-recommended-bump/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/conventional-recommended-bump/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/conventional-recommended-bump/node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/conventional-recommended-bump/node_modules/text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/conventional-recommended-bump/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==" + }, + "node_modules/core-js-compat": { + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.1.tgz", + "integrity": "sha512-6pYKNOgD/j/bkC5xS5IIg6bncid3rfrI42oBH1SQJbsmYPKF7rhzcFzYCcxYMmNQQ0rCEB8WqpW7QHndOggaeQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -4468,12 +4925,15 @@ } }, "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/decamelize-keys": { @@ -4492,6 +4952,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/decamelize-keys/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/decamelize-keys/node_modules/map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", @@ -4518,6 +4987,19 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -4699,15 +5181,6 @@ "node": ">=6" } }, - "node_modules/dotgitignore/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/dotgitignore/node_modules/path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -4728,9 +5201,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.543", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.543.tgz", - "integrity": "sha512-t2ZP4AcGE0iKCCQCBx/K2426crYdxD3YU6l0uK2EO3FZH0pbC4pFz/sZm2ruZsND6hQBTcDWWlo/MLpiOdif5g==" + "version": "1.4.562", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.562.tgz", + "integrity": "sha512-kMGVZLP65O2/oH7zzaoIA5hcr4/xPYO6Sa83FrIpWcd7YPPtSlxqwxTd8lJIwKxaiXM6FGsYK4ukyJ40XkW7jg==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -4772,9 +5245,9 @@ } }, "node_modules/engine.io": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.2.tgz", - "integrity": "sha512-IXsMcGpw/xRfjra46sVZVHiSWo/nJ/3g1337q9KNXtS6YRzbW5yIzTCb9DjhrBe7r3GZQR0I4+nq+4ODk5g/cA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.3.tgz", + "integrity": "sha512-IML/R4eG/pUS5w7OfcDE0jKrljWS9nwnEfsxWCIJF5eO6AHo6+Hlv+lQbdlAYsiJPHzUthLm1RUjnBzWOs45cw==", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", @@ -4866,17 +5339,18 @@ } }, "node_modules/eslint": { - "version": "8.50.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", - "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", + "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.50.0", - "@humanwhocodes/config-array": "^0.11.11", + "@eslint/js": "8.52.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -5555,11 +6029,11 @@ } }, "node_modules/flat-cache": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", - "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", "dependencies": { - "flatted": "^3.2.7", + "flatted": "^3.2.9", "keyv": "^4.5.3", "rimraf": "^3.0.2" }, @@ -5671,9 +6145,12 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/gauge": { "version": "3.0.2", @@ -5786,136 +6263,479 @@ "wrap-ansi": "^7.0.0" } }, - "node_modules/get-pkg-repo/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/get-pkg-repo/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/get-pkg-repo/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/get-pkg-repo/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/get-pkg-repo/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/get-pkg-repo/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-raw-commits": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", + "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", + "dev": true, + "dependencies": { + "dargs": "^7.0.0", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/git-raw-commits/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/git-raw-commits/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/git-raw-commits/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/git-raw-commits/node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-raw-commits/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-raw-commits/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/git-raw-commits/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/git-raw-commits/node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-raw-commits/node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/git-raw-commits/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/git-raw-commits/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/git-raw-commits/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/git-raw-commits/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/git-raw-commits/node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/git-raw-commits/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-remote-origin-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", + "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==", + "dev": true, + "dependencies": { + "gitconfiglocal": "^1.0.0", + "pify": "^2.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/git-remote-origin-url/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/git-semver-tags": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz", + "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==", + "dev": true, + "dependencies": { + "meow": "^8.0.0", + "semver": "^6.0.0" + }, + "bin": { + "git-semver-tags": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/git-semver-tags/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=8" } }, - "node_modules/get-pkg-repo/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/git-semver-tags/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, - "node_modules/get-pkg-repo/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "node_modules/git-semver-tags/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/get-pkg-repo/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/git-semver-tags/node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-pkg-repo/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "node_modules/git-semver-tags/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "p-try": "^2.0.0" }, "engines": { - "node": ">=10" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/git-raw-commits": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", - "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", + "node_modules/git-semver-tags/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "dependencies": { - "dargs": "^7.0.0", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" + "p-limit": "^2.2.0" }, - "bin": { - "git-raw-commits": "cli.js" + "engines": { + "node": ">=8" + } + }, + "node_modules/git-semver-tags/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/git-remote-origin-url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", - "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==", + "node_modules/git-semver-tags/node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, "dependencies": { - "gitconfiglocal": "^1.0.0", - "pify": "^2.3.0" + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/git-remote-origin-url/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "node_modules/git-semver-tags/node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/git-semver-tags": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz", - "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==", + "node_modules/git-semver-tags/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "dependencies": { - "meow": "^8.0.0", - "semver": "^6.0.0" - }, + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/git-semver-tags/node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, "bin": { - "git-semver-tags": "cli.js" - }, + "semver": "bin/semver" + } + }, + "node_modules/git-semver-tags/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, "engines": { - "node": ">=10" + "node": ">=8" } }, "node_modules/git-semver-tags/node_modules/semver": { @@ -5927,6 +6747,18 @@ "semver": "bin/semver.js" } }, + "node_modules/git-semver-tags/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gitconfiglocal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", @@ -5987,6 +6819,17 @@ "node": ">=4" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -6044,6 +6887,17 @@ "node": ">=4" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", @@ -6416,12 +7270,12 @@ } }, "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/is-plain-object": { @@ -6453,15 +7307,15 @@ } }, "node_modules/is-text-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", + "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", "dev": true, "dependencies": { - "text-extensions": "^1.0.0" + "text-extensions": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/is-unicode-supported": { @@ -6628,9 +7482,9 @@ "dev": true }, "node_modules/keyv": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", - "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dependencies": { "json-buffer": "3.0.1" } @@ -6913,16 +7767,19 @@ } }, "node_modules/logform": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz", - "integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", + "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", "dependencies": { - "@colors/colors": "1.5.0", + "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" } }, "node_modules/long": { @@ -6931,12 +7788,12 @@ "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, "node_modules/loupe": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", - "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, "dependencies": { - "get-func-name": "^2.0.0" + "get-func-name": "^2.0.1" } }, "node_modules/lru-cache": { @@ -7032,46 +7889,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/meow": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", - "dev": true, - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=16.10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7176,6 +8008,15 @@ "node": ">= 6" } }, + "node_modules/minimist-options/node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/minipass": { "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", @@ -7499,15 +8340,6 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -7654,9 +8486,9 @@ "dev": true }, "node_modules/nise": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz", - "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz", + "integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==", "dev": true, "dependencies": { "@sinonjs/commons": "^2.0.0", @@ -7675,6 +8507,24 @@ "type-detect": "4.0.8" } }, + "node_modules/nise/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/nise/node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, "node_modules/nise/node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -7896,9 +8746,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8004,12 +8854,12 @@ } }, "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/parent-module": { @@ -8206,15 +9056,6 @@ "node": ">=6" } }, - "node_modules/pkg-dir/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/pkg-dir/node_modules/path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -8288,15 +9129,6 @@ "node": ">=6" } }, - "node_modules/pkg-up/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/pkg-up/node_modules/path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -8448,105 +9280,97 @@ } }, "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", "dev": true, "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", "dev": true, "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, "node_modules/read-pkg-up/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", "dev": true, "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "locate-path": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", "dev": true, "dependencies": { - "p-locate": "^4.1.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "dependencies": { - "p-try": "^2.0.0" + "p-try": "^1.0.0" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", "dev": true, "dependencies": { - "p-limit": "^2.2.0" + "p-limit": "^1.1.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/read-pkg-up/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", "dev": true, "engines": { - "node": ">=6" + "node": ">=4" } }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "dev": true, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/read-pkg/node_modules/hosted-git-info": { @@ -8567,6 +9391,27 @@ "validate-npm-package-license": "^3.0.1" } }, + "node_modules/read-pkg/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/read-pkg/node_modules/semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", @@ -8576,15 +9421,6 @@ "semver": "bin/semver" } }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -8736,9 +9572,9 @@ "dev": true }, "node_modules/resolve": { - "version": "1.22.6", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", - "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { "is-core-module": "^2.13.0", @@ -9057,6 +9893,20 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -9125,16 +9975,16 @@ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, "node_modules/sinon": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-16.1.0.tgz", - "integrity": "sha512-ZSgzF0vwmoa8pq0GEynqfdnpEDyP1PkYmEChnkjW0Vyh8IDlyFEJ+fkMhCP0il6d5cJjPl2PUsnUSAuP5sttOQ==", + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.0.tgz", + "integrity": "sha512-p4lJiYKBoOEVUxxVIC9H1MM2znG1/c8gud++I2BauJA5hsz7hHsst35eurNWXTusBsIq66FzOQbZ/uMdpvbPIQ==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^10.3.0", + "@sinonjs/fake-timers": "^11.2.2", "@sinonjs/samsam": "^8.0.0", "diff": "^5.1.0", - "nise": "^5.1.4", + "nise": "^5.1.5", "supports-color": "^7.2.0" }, "funding": { @@ -9381,26 +10231,12 @@ } }, "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dev": true, - "dependencies": { - "readable-stream": "^3.0.0" - } - }, - "node_modules/split2/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, "engines": { - "node": ">= 6" + "node": ">= 10.x" } }, "node_modules/sqlite3": { @@ -9785,12 +10621,15 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/text-extensions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", + "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", "dev": true, "engines": { - "node": ">=0.10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/text-hex": { @@ -10234,11 +11073,11 @@ } }, "node_modules/winston": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.10.0.tgz", - "integrity": "sha512-nT6SIDaE9B7ZRO0u3UvdrimG0HkB7dSTAgInQnNR2SOPJ4bvq5q79+pXLftKmP52lJGW15+H5MCK0nM9D3KB/g==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", + "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", "dependencies": { - "@colors/colors": "1.5.0", + "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", @@ -10272,16 +11111,16 @@ } }, "node_modules/winston-transport": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", - "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", + "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", "dependencies": { "logform": "^2.3.2", "readable-stream": "^3.6.0", "triple-beam": "^1.3.0" }, "engines": { - "node": ">= 6.4.0" + "node": ">= 12.0.0" } }, "node_modules/winston-transport/node_modules/readable-stream": { @@ -10460,9 +11299,9 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", "dev": true, "engines": { "node": ">=10" @@ -10483,39 +11322,6 @@ "node": ">=10" } }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs-unparser/node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/yargs/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", diff --git a/package.json b/package.json index 4b9ef371..a2646f0e 100644 --- a/package.json +++ b/package.json @@ -59,23 +59,23 @@ }, "devDependencies": { "@babel/cli": "^7.23.0", - "@babel/core": "^7.23.0", + "@babel/core": "^7.23.2", "@babel/plugin-syntax-import-attributes": "^7.22.5", - "@babel/preset-env": "^7.22.20", + "@babel/preset-env": "^7.23.2", "@babel/register": "^7.22.15", - "@commitlint/cli": "^17.7.2", - "@commitlint/config-conventional": "^17.7.0", + "@commitlint/cli": "^18.0.0", + "@commitlint/config-conventional": "^18.0.0", "babel-plugin-module-resolver": "^5.0.0", "chai": "^4.3.10", "chai-http": "^4.4.0", - "eslint": "^8.50.0", + "eslint": "^8.52.0", "eslint-plugin-es": "^4.1.0", "eslint-plugin-mocha": "^10.2.0", "husky": "^8.0.3", "mocha": "^10.2.0", "semver": "^7.5.4", - "sinon": "^16.1.0", + "sinon": "^17.0.0", "socket.io-client": "^4.7.2", "standard-version": "^9.5.0", "supertest": "^6.3.3" From bea5410d69b39ecc6cd8396fe55d65b774f50392 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Fri, 20 Oct 2023 18:05:45 -0400 Subject: [PATCH 08/18] feat: sync remaining count for organizations --- src/controllers/governance.controller.js | 7 ++ src/controllers/offer.controller.js | 2 + src/controllers/organization.controller.js | 21 +++- src/controllers/project.controller.js | 5 + src/controllers/staging.controller.js | 17 ++- src/controllers/units.controller.js | 6 + src/database/index.js | 2 - .../20231020201652-OrgSyncStatus.js | 2 +- .../20231020214357-OrgSyncRemainingCount.js | 23 ++++ src/database/migrations/index.js | 5 + src/datalayer/persistance.js | 1 - src/datalayer/syncService.js | 6 +- src/datalayer/writeService.js | 2 - src/middleware.js | 7 ++ src/models/governance/governance.model.js | 6 +- .../organizations/organizations.model.js | 5 +- .../organizations.modeltypes.cjs | 5 +- src/server.js | 2 - src/tasks/sync-audit-table.js | 109 +++++++++++------- src/tasks/sync-datalayer.js | 2 - src/tasks/sync-default-organizations.js | 2 - src/tasks/sync-governance-body.js | 2 - src/tasks/sync-organization-meta.js | 3 - src/tasks/sync-picklists.js | 2 - src/utils/defaultConfig.js | 4 +- 25 files changed, 173 insertions(+), 75 deletions(-) create mode 100644 src/database/migrations/20231020214357-OrgSyncRemainingCount.js diff --git a/src/controllers/governance.controller.js b/src/controllers/governance.controller.js index 0f6c9a97..1f5b201f 100644 --- a/src/controllers/governance.controller.js +++ b/src/controllers/governance.controller.js @@ -37,10 +37,12 @@ export const isCreated = async (req, res) => { if (results) { return res.json({ created: true, + success: true, }); } else { return res.json({ created: false, + success: true, }); } } catch (error) { @@ -116,6 +118,7 @@ export const createGoveranceBody = async (req, res) => { return res.json({ message: 'Setting up new Governance Body on this node, this can take a few mins', + success: true, }); } catch (error) { res.status(400).json({ @@ -141,6 +144,7 @@ export const setDefaultOrgList = async (req, res) => { return res.json({ message: 'Committed this new organization list to the datalayer', + success: true, }); } catch (error) { console.trace(error); @@ -167,6 +171,7 @@ export const setPickList = async (req, res) => { return res.json({ message: 'Committed this pick list to the datalayer', + success: true, }); } catch (error) { res.status(400).json({ @@ -191,6 +196,7 @@ export const setGlossary = async (req, res) => { return res.json({ message: 'Committed glossary to the datalayer', + success: true, }); } catch (error) { res.status(400).json({ @@ -206,6 +212,7 @@ export const sync = async (req, res) => { Governance.sync(); return res.json({ message: 'Syncing Governance Body', + success: true, }); } catch (error) { res.status(400).json({ diff --git a/src/controllers/offer.controller.js b/src/controllers/offer.controller.js index de2acbaa..ab18b9a2 100644 --- a/src/controllers/offer.controller.js +++ b/src/controllers/offer.controller.js @@ -102,6 +102,7 @@ export const importOfferFile = async (req, res) => { res.json({ message: 'Offer has been imported for review.', + success: true, }); } catch (error) { console.trace(error); @@ -132,6 +133,7 @@ export const commitImportedOfferFile = async (req, res) => { res.json({ message: 'Offer Accepted.', tradeId: response.trade_id, + success: true, }); await Meta.destroy({ diff --git a/src/controllers/organization.controller.js b/src/controllers/organization.controller.js index 7ec3823f..21220d8a 100644 --- a/src/controllers/organization.controller.js +++ b/src/controllers/organization.controller.js @@ -1,3 +1,4 @@ +import { Sequelize } from 'sequelize'; import { sequelize } from '../database'; import { Organization } from '../models/organizations'; @@ -62,6 +63,7 @@ export const createV2 = async (req, res) => { return res.json({ message: 'Your organization already exists.', orgId: myOrganization.orgUid, + success: false, }); } else { const { name } = req.body; @@ -81,6 +83,7 @@ export const createV2 = async (req, res) => { return res.json({ message: 'New organization is currently being created. It can take up to 30 mins. Please do not interrupt this process.', + success: true, }); } } catch (error) { @@ -104,6 +107,7 @@ export const create = async (req, res) => { return res.json({ message: 'Your organization already exists.', orgId: myOrganization.orgUid, + success: false, }); } else { const { name, icon } = req.body; @@ -111,6 +115,7 @@ export const create = async (req, res) => { return res.json({ message: 'New organization created successfully.', + success: true, orgId: await Organization.createHomeOrganization( name, icon, @@ -135,13 +140,18 @@ export const resetHomeOrg = async (req, res) => { await Promise.all([ Organization.destroy({ where: { isHome: true } }), Staging.destroy({ - where: {}, + where: { + id: { + [Sequelize.Op.ne]: null, + }, + }, truncate: true, }), ]); res.json({ message: 'Your home organization was reset, please create a new one.', + success: true, }); } catch (error) { res.status(400).json({ @@ -162,6 +172,7 @@ export const importOrg = async (req, res) => { res.json({ message: 'Importing and subscribing organization this can take a few mins.', + success: true, }); return Organization.importOrganization(orgUid); @@ -186,6 +197,7 @@ export const importHomeOrg = async (req, res) => { res.json({ message: 'Importing home organization.', + success: true, }); } catch (error) { console.trace(error); @@ -207,6 +219,7 @@ export const subscribeToOrganization = async (req, res) => { return res.json({ message: 'Subscribed to organization', + success: true, }); } catch (error) { res.status(400).json({ @@ -242,6 +255,7 @@ export const deleteImportedOrg = async (req, res) => { return res.json({ message: 'UnSubscribed to organization, you will no longer receive updates.', + success: true, }); } catch (error) { res.status(400).json({ @@ -282,6 +296,7 @@ export const unsubscribeToOrganization = async (req, res) => { return res.json({ message: 'UnSubscribed to organization, you will no longer receive updates.', + success: true, }); } catch (error) { res.status(400).json({ @@ -322,6 +337,7 @@ export const resyncOrganization = async (req, res) => { return res.json({ message: 'Resyncing organization completed', + success: true, }); } catch (error) { res.status(400).json({ @@ -367,6 +383,7 @@ export const addMirror = async (req, res) => { await Organization.addMirror(req.body.storeId, req.body.url); return res.json({ message: `Mirror added for ${req.body.storeId}.`, + success: true, }); } catch (error) { res.status(400).json({ @@ -404,6 +421,7 @@ export const removeMirror = async (req, res) => { await Organization.removeMirror(req.body.storeId, req.body.coinId); return res.json({ message: `Mirror removed for ${req.body.storeId}.`, + success: true, }); } catch (error) { res.status(400).json({ @@ -418,6 +436,7 @@ export const sync = async (req, res) => { Organization.syncOrganizationMeta(); return res.json({ message: 'Syncing All Organizations Metadata', + success: true, }); } catch (error) { res.status(400).json({ diff --git a/src/controllers/project.controller.js b/src/controllers/project.controller.js index f376de81..1fea824f 100644 --- a/src/controllers/project.controller.js +++ b/src/controllers/project.controller.js @@ -104,6 +104,7 @@ export const create = async (req, res) => { res.json({ message: 'Project staged successfully', uuid, + success: true, }); } catch (err) { res.status(400).json({ @@ -304,6 +305,7 @@ export const updateFromXLS = async (req, res) => { res.json({ message: 'Updates from xlsx added to staging', + success: true, }); } catch (error) { console.trace(error); @@ -418,6 +420,7 @@ const update = async (req, res, isTransfer = false) => { res.json({ message: 'Project update added to staging', + success: true, }); } catch (err) { res.status(400).json({ @@ -452,6 +455,7 @@ export const destroy = async (req, res) => { res.json({ message: 'Project deleted successfully', + success: true, }); } catch (err) { res.status(400).json({ @@ -474,6 +478,7 @@ export const batchUpload = async (req, res) => { res.json({ message: 'CSV processing complete, your records have been added to the staging table.', + success: true, }); } catch (error) { logger.error('Batch Upload Failed.', error); diff --git a/src/controllers/staging.controller.js b/src/controllers/staging.controller.js index 51bee162..c40b21f7 100644 --- a/src/controllers/staging.controller.js +++ b/src/controllers/staging.controller.js @@ -1,5 +1,6 @@ import _ from 'lodash'; +import { Sequelize } from 'sequelize'; import { Staging } from '../models'; import { @@ -22,11 +23,13 @@ export const hasPendingTransactions = async (req, res) => { res.json({ confirmed: true, message: 'There are no pending transactions', + success: true, }); } catch (error) { res.json({ confirmed: false, message: 'There are currently pending transactions', + success: true, }); } }; @@ -102,7 +105,10 @@ export const commit = async (req, res) => { _.get(req, 'body.ids', []), ); - res.json({ message: 'Staging Table committed to full node' }); + res.json({ + message: 'Staging Table committed to full node', + success: true, + }); } catch (error) { console.trace(error); res.status(400).json({ @@ -125,6 +131,7 @@ export const destroy = async (req, res) => { }); res.json({ message: 'Deleted from stage', + success: true, }); } catch (error) { res.status(400).json({ @@ -140,11 +147,16 @@ export const clean = async (req, res) => { await assertIfReadOnlyMode(); await assertHomeOrgExists(); await Staging.destroy({ - where: {}, + where: { + id: { + [Sequelize.Op.ne]: null, + }, + }, truncate: true, }); res.json({ message: 'Staging Data Cleaned', + success: true, }); } catch (error) { res.status(400).json({ @@ -193,6 +205,7 @@ export const retryRecrod = async (req, res) => { ); res.json({ message: 'Staging record re-staged.', + success: true, }); } catch (error) { res.status(400).json({ diff --git a/src/controllers/units.controller.js b/src/controllers/units.controller.js index f6468172..2ebbd94a 100644 --- a/src/controllers/units.controller.js +++ b/src/controllers/units.controller.js @@ -108,6 +108,7 @@ export const create = async (req, res) => { res.json({ message: 'Unit staged successfully', uuid, + success: true, }); } catch (error) { res.status(400).json({ @@ -318,6 +319,7 @@ export const updateFromXLS = async (req, res) => { res.json({ message: 'Updates from xlsx added to staging', + success: true, }); } catch (error) { logger.error('Batch Upload Failed.', error); @@ -406,6 +408,7 @@ export const update = async (req, res) => { res.json({ message: 'Unit update added to staging', + success: true, }); } catch (err) { res.status(400).json({ @@ -437,6 +440,7 @@ export const destroy = async (req, res) => { await Staging.upsert(stagedData); res.json({ message: 'Unit deleted successfully', + success: true, }); } catch (err) { res.status(400).json({ @@ -524,6 +528,7 @@ export const split = async (req, res) => { res.json({ message: 'Unit split successful', + success: true, }); } catch (error) { res.status(400).json({ @@ -546,6 +551,7 @@ export const batchUpload = async (req, res) => { res.json({ message: 'CSV processing complete, your records have been added to the staging table.', + success: true, }); } catch (error) { logger.error('Batch Upload Failed.', error); diff --git a/src/database/index.js b/src/database/index.js index d12ab53a..102c1409 100644 --- a/src/database/index.js +++ b/src/database/index.js @@ -18,8 +18,6 @@ const mirrorConfig = (process.env.NODE_ENV || 'local') === 'local' ? 'mirror' : 'mirrorTest'; export const sequelizeMirror = new Sequelize(config[mirrorConfig]); -logger.info('CADT:mirror-database'); - const logDebounce = _.debounce(() => { console.log('Mirror DB not connected'); logger.info('Mirror DB not connected'); diff --git a/src/database/migrations/20231020201652-OrgSyncStatus.js b/src/database/migrations/20231020201652-OrgSyncStatus.js index cc62e3fa..3dc295f1 100644 --- a/src/database/migrations/20231020201652-OrgSyncStatus.js +++ b/src/database/migrations/20231020201652-OrgSyncStatus.js @@ -6,7 +6,7 @@ export default { ['organizations'].map((table) => { queryInterface.addColumn(table, 'synced', { type: Sequelize.BOOLEAN, - allowNull: true, + allowNull: false, defaultValue: false, }); }), diff --git a/src/database/migrations/20231020214357-OrgSyncRemainingCount.js b/src/database/migrations/20231020214357-OrgSyncRemainingCount.js new file mode 100644 index 00000000..8b686daa --- /dev/null +++ b/src/database/migrations/20231020214357-OrgSyncRemainingCount.js @@ -0,0 +1,23 @@ +'use strict'; + +export default { + async up(queryInterface, Sequelize) { + await Promise.all( + ['organizations'].map((table) => { + queryInterface.addColumn(table, 'sync_remaining', { + type: Sequelize.INTEGER, + allowNull: true, + defaultValue: false, + }); + }), + ); + }, + + async down(queryInterface) { + await Promise.all( + ['organizations'].map((table) => { + queryInterface.removeColumn(table, 'sync_remaining'); + }), + ); + }, +}; diff --git a/src/database/migrations/index.js b/src/database/migrations/index.js index 9c289a41..1ff83fb2 100644 --- a/src/database/migrations/index.js +++ b/src/database/migrations/index.js @@ -31,6 +31,7 @@ import ResetDBForNewSingletons from './20220816155101-reset-db-for-new-singleton import AddIsTransferColumn from './20220825124702-add-isTransfer-column'; import AddOrgMetadata from './20220831023546-add-org-metadata'; import OrgSyncStatus from './20231020201652-OrgSyncStatus'; +import OrgSyncRemaining from './20231020214357-OrgSyncRemainingCount'; export const migrations = [ { @@ -169,4 +170,8 @@ export const migrations = [ migration: OrgSyncStatus, name: '20231020201652-OrgSyncStatus', }, + { + migration: OrgSyncRemaining, + name: '20231020214357-OrgSyncRemainingCount', + }, ]; diff --git a/src/datalayer/persistance.js b/src/datalayer/persistance.js index 321c2003..fd2b5319 100644 --- a/src/datalayer/persistance.js +++ b/src/datalayer/persistance.js @@ -10,7 +10,6 @@ import { Organization } from '../models'; import { logger } from '../config/logger.cjs'; import { getChiaRoot } from '../utils/chia-root.js'; -logger.info('CADT:datalayer:persistance'); process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0; const CONFIG = getConfig().APP; diff --git a/src/datalayer/syncService.js b/src/datalayer/syncService.js index 1a02e187..e9f3dc6a 100644 --- a/src/datalayer/syncService.js +++ b/src/datalayer/syncService.js @@ -230,7 +230,7 @@ const getSubscribedStoreData = async (storeId, retry = 0) => { if (!USE_SIMULATOR) { logger.info(`Getting confirmation for ${storeId}.`); const storeExistAndIsConfirmed = await dataLayer.getRoot(storeId, true); - logger.info(`Store exists and is found ${storeId}.`); + logger.info(`Store found in DataLayer: ${storeId}.`); if (!storeExistAndIsConfirmed) { logger.info( `Retrying subscribe to ${storeId}, store not yet confirmed.`, @@ -242,9 +242,7 @@ const getSubscribedStoreData = async (storeId, retry = 0) => { ); return getSubscribedStoreData(storeId, retry + 1); } else { - logger.debug( - `Store Exists and is confirmed, proceeding to get data ${storeId}`, - ); + logger.debug(`Store is confirmed, proceeding to get data ${storeId}`); } } diff --git a/src/datalayer/writeService.js b/src/datalayer/writeService.js index c60b0618..9f825a90 100644 --- a/src/datalayer/writeService.js +++ b/src/datalayer/writeService.js @@ -10,8 +10,6 @@ import { logger } from '../config/logger.cjs'; import { Organization } from '../models'; import { publicIpv4 } from '../utils/ip-tools'; -logger.info('CADT:datalayer:writeService'); - const { USE_SIMULATOR, DATALAYER_FILE_SERVER_URL } = getConfig().APP; const createDataLayerStore = async () => { diff --git a/src/middleware.js b/src/middleware.js index 159dd213..4dbdd3ec 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -26,6 +26,7 @@ const headerKeys = Object.freeze({ WALLET_SYNCED: 'x-wallet-synced', HOME_ORGANIZATION_SYNCED: 'x-home-org-synced', ALL_DATA_SYNCED: 'x-data-synced', + SYNC_REMAINING: 'x-sync-remaining', }); const app = express(); @@ -123,6 +124,12 @@ app.use(async function (req, res, next) { const notSynced = Object.keys(orgMap).find((key) => !orgMap[key].synced); res.setHeader(headerKeys.ALL_DATA_SYNCED, !notSynced); + + const syncRemaining = Object.keys(orgMap).reduce((agg, key) => { + return agg + orgMap[key].sync_remaining; + }, 0); + + res.setHeader(headerKeys.SYNC_REMAINING, syncRemaining); next(); }); diff --git a/src/models/governance/governance.model.js b/src/models/governance/governance.model.js index ef8974d0..afc2a592 100644 --- a/src/models/governance/governance.model.js +++ b/src/models/governance/governance.model.js @@ -194,7 +194,11 @@ class Governance extends Model { const rollbackChangesIfFailed = async () => { logger.info('Reverting Goverance Records'); await Governance.destroy({ - where: {}, + where: { + id: { + [Sequelize.Op.ne]: null, + }, + }, truncate: true, }); diff --git a/src/models/organizations/organizations.model.js b/src/models/organizations/organizations.model.js index 11a9a7a2..ade30bd7 100644 --- a/src/models/organizations/organizations.model.js +++ b/src/models/organizations/organizations.model.js @@ -18,8 +18,6 @@ import { getDataModelVersion } from '../../utils/helpers'; import { getConfig } from '../../utils/config-loader'; const { USE_SIMULATOR, AUTO_SUBSCRIBE_FILESTORE } = getConfig().APP; -logger.info('CADT:organizations'); - import ModelTypes from './organizations.modeltypes.cjs'; class Organization extends Model { @@ -74,6 +72,7 @@ class Organization extends Model { 'subscribed', 'synced', 'fileStoreSubscribed', + 'sync_remaining', ], }); @@ -333,7 +332,7 @@ class Organization extends Model { static async syncOrganizationMeta() { try { const allSubscribedOrganizations = await Organization.findAll({ - subscribed: true, + where: { subscribed: true }, }); await Promise.all( diff --git a/src/models/organizations/organizations.modeltypes.cjs b/src/models/organizations/organizations.modeltypes.cjs index 77a7df85..3a66be11 100644 --- a/src/models/organizations/organizations.modeltypes.cjs +++ b/src/models/organizations/organizations.modeltypes.cjs @@ -35,9 +35,12 @@ module.exports = { }, synced: { type: Sequelize.BOOLEAN, - allowNull: true, defaultValue: false, }, + sync_remaining: { + type: Sequelize.INTEGER, + defaultValue: 0, + }, createdAt: Sequelize.DATE, updatedAt: Sequelize.DATE, }; diff --git a/src/server.js b/src/server.js index 4276aa7d..de1b58d5 100644 --- a/src/server.js +++ b/src/server.js @@ -12,8 +12,6 @@ import dotenv from 'dotenv'; dotenv.config(); -logger.info('CADT:server'); - const port = getConfig().APP.CW_PORT || 3030; const bindAddress = getConfig().APP.BIND_ADDRESS || 'localhost'; const server = http.createServer(rootRouter); diff --git a/src/tasks/sync-audit-table.js b/src/tasks/sync-audit-table.js index 9007b5f2..76b4cb77 100644 --- a/src/tasks/sync-audit-table.js +++ b/src/tasks/sync-audit-table.js @@ -1,5 +1,6 @@ import _ from 'lodash'; +import { Sequelize } from 'sequelize'; import { SimpleIntervalJob, Task } from 'toad-scheduler'; import { Organization, Audit, ModelKeys, Staging, Meta } from '../models'; import datalayer from '../datalayer'; @@ -39,26 +40,43 @@ const task = new Task('sync-audit', async () => { for (const modelKey of Object.keys(ModelKeys)) { logger.info(`Resetting ${modelKey}`); await ModelKeys[modelKey].destroy({ - where: {}, + where: { + id: { + [Sequelize.Op.ne]: null, + }, + }, truncate: true, }); } logger.info(`Resetting Audit Table`); await Audit.destroy({ - where: {}, + where: { + id: { + [Sequelize.Op.ne]: null, + }, + }, truncate: true, }); - logger.info(`Completing Migration`); await Meta.upsert({ metaKey: 'migratedToNewSync', metaValue: 'true', }); - await Organization.upsert({ - synced: false, - }); + await Organization.update( + { + synced: false, + sync_remaining: 0, + }, + { + where: { + id: { + [Sequelize.Op.ne]: null, + }, + }, + }, + ); logger.info(`Migration Complete`); } @@ -79,7 +97,7 @@ const task = new Task('sync-audit', async () => { const job = new SimpleIntervalJob( { - seconds: CONFIG?.TASKS?.AUDIT_SYNC_TASK_INTERVAL || 30, + seconds: 30, runImmediately: true, }, task, @@ -90,27 +108,13 @@ const processJob = async () => { await assertDataLayerAvailable(); await assertWalletIsSynced(); - logger.info('Syncing Registry Data'); const organizations = await Organization.findAll({ where: { subscribed: true }, raw: true, }); for (const organization of organizations) { - console.log(`Syncing ${organization.name}`); await syncOrganizationAudit(organization); - if (!CONFIG.USE_SIMULATOR) { - await new Promise((resolve) => - setTimeout( - resolve, - (CONFIG.TASKS?.AUDIT_SYNC_TASK_INTERVAL || 30) * 1000, - ), - ); - } - } - - if (!CONFIG.USE_SIMULATOR) { - await new Promise((resolve) => setTimeout(resolve, 5000)); } }; @@ -158,11 +162,17 @@ async function createTransaction(callback, afterCommitCallbacks) { const syncOrganizationAudit = async (organization) => { try { - logger.info(`Syncing Registry: ${_.get(organization, 'name')}`); let afterCommitCallbacks = []; const homeOrg = await Organization.getHomeOrg(); - const rootHistory = await datalayer.getRootHistory(organization.registryId); + const rootHistory = ( + await datalayer.getRootHistory(organization.registryId) + ).sort((a, b) => a.timestamp - b.timestamp); + + if (!rootHistory.length) { + logger.info(`No root history found for ${organization.name}`); + return; + } let lastRootSaved; @@ -173,30 +183,19 @@ const syncOrganizationAudit = async (organization) => { } else { lastRootSaved = await Audit.findOne({ where: { registryId: organization.registryId }, - order: [['createdAt', 'DESC']], + order: [['onchainConfirmationTimeStamp', 'DESC']], raw: true, }); } - if (!rootHistory.length) { - return; - } - let rootHash = _.get(rootHistory, '[0].root_hash'); - if (lastRootSaved) { - rootHash = lastRootSaved.rootHash; - } - - const historyIndex = rootHistory.findIndex( - (root) => root.root_hash === rootHash, - ); - if (!lastRootSaved) { + logger.info(`Syncing new registry ${organization.name}`); await Audit.create({ orgUid: organization.orgUid, registryId: organization.registryId, - rootHash: _.get(rootHistory, '[0].root_hash'), + rootHash, type: 'CREATE REGISTRY', change: null, table: null, @@ -218,24 +217,43 @@ const syncOrganizationAudit = async (organization) => { ); return; + } else { + rootHash = lastRootSaved.rootHash; } const isSynced = rootHistory[rootHistory.length - 1].root_hash === rootHash; + const historyIndex = rootHistory.findIndex( + (root) => root.root_hash === rootHash, + ); + await Organization.update( - { synced: isSynced }, + { + synced: isSynced, + sync_remaining: rootHistory.length - historyIndex - 1, + }, { where: { orgUid: organization.orgUid } }, ); if (isSynced) { - logger.info(`No new data to sync for ${organization.name}`); return; } + // Organization not synced, sync it + logger.info(' '); + logger.info(`Syncing Registry: ${_.get(organization, 'name')}`); + + if (!CONFIG.USE_SIMULATOR) { + await new Promise((resolve) => setTimeout(resolve, 30000)); + } + const root1 = _.get(rootHistory, `[${historyIndex}]`); const root2 = _.get(rootHistory, `[${historyIndex + 1}]`); if (!_.get(root2, 'confirmed')) { + logger.info( + `Waiting for the latest root for ${organization.name} to confirm`, + ); return; } @@ -246,6 +264,15 @@ const syncOrganizationAudit = async (organization) => { ); if (_.isEmpty(kvDiff)) { + const errorMsg = [ + `No data found for ${organization.name} in the current generation.`, + `Missing data for root hash: ${root2.root_hash}.`, + "Check your internet connection, otherwise the organization's file propagation server may be offline.", + 'Syncing for this organization will be halted until resolved.', + 'If the issue persists, contact the organization.', + ].join(' '); + + logger.error(errorMsg); return; } @@ -256,7 +283,7 @@ const syncOrganizationAudit = async (organization) => { diff.type === 'INSERT', ); - // 0x617574686F72 is hex for 'author' + // 0x617574686F72 is hex for 'author'T const author = kvDiff.filter( (diff) => (diff.key === '617574686f72' || diff.key === '0x617574686F72') && @@ -353,7 +380,7 @@ const syncOrganizationAudit = async (organization) => { } }; - return await createTransaction(updateTransaction, afterCommitCallbacks); + await createTransaction(updateTransaction, afterCommitCallbacks); } catch (error) { logger.error('Error syncing org audit', error); } diff --git a/src/tasks/sync-datalayer.js b/src/tasks/sync-datalayer.js index e202ed0e..4e8090a5 100644 --- a/src/tasks/sync-datalayer.js +++ b/src/tasks/sync-datalayer.js @@ -13,8 +13,6 @@ dotenv.config(); import { getConfig } from '../utils/config-loader'; const CONFIG = getConfig().APP; -logger.info('CADT:task:sync-datalayer'); - const spinner = new Spinner('Waiting for Updates %s'); spinner.setSpinnerString('|/-\\'); spinner.setSpinnerDelay(500); diff --git a/src/tasks/sync-default-organizations.js b/src/tasks/sync-default-organizations.js index bea96375..9ba85823 100644 --- a/src/tasks/sync-default-organizations.js +++ b/src/tasks/sync-default-organizations.js @@ -11,8 +11,6 @@ const CONFIG = getConfig().APP; import dotenv from 'dotenv'; dotenv.config(); -logger.info('CADT:task:sync-default-organizations'); - const task = new Task('sync-default-organizations', async () => { try { await assertDataLayerAvailable(); diff --git a/src/tasks/sync-governance-body.js b/src/tasks/sync-governance-body.js index 0c3b9085..de9b245e 100644 --- a/src/tasks/sync-governance-body.js +++ b/src/tasks/sync-governance-body.js @@ -14,8 +14,6 @@ const CONFIG = getConfig(); import dotenv from 'dotenv'; dotenv.config(); -logger.info('CADT:task:sync-governance'); - const task = new Task('sync-governance-meta', async () => { try { await assertDataLayerAvailable(); diff --git a/src/tasks/sync-organization-meta.js b/src/tasks/sync-organization-meta.js index fbe03827..652ccb23 100644 --- a/src/tasks/sync-organization-meta.js +++ b/src/tasks/sync-organization-meta.js @@ -12,13 +12,10 @@ const CONFIG = getConfig().APP; import dotenv from 'dotenv'; dotenv.config(); -logger.info('CADT:task:sync-organizations'); - const task = new Task('sync-organization-meta', async () => { try { await assertDataLayerAvailable(); await assertWalletIsSynced(); - logger.info('Syncing subscribed organizations'); if (!CONFIG.USE_SIMULATOR) { Organization.syncOrganizationMeta(); } diff --git a/src/tasks/sync-picklists.js b/src/tasks/sync-picklists.js index be9b8abd..0f762370 100644 --- a/src/tasks/sync-picklists.js +++ b/src/tasks/sync-picklists.js @@ -9,8 +9,6 @@ import { getConfig } from '../utils/config-loader'; const CONFIG = getConfig().APP; -logger.info('CADT:task:sync-picklists'); - const task = new Task('sync-picklist', async () => { try { await assertDataLayerAvailable(); diff --git a/src/utils/defaultConfig.js b/src/utils/defaultConfig.js index 594d5bb0..ca93057e 100644 --- a/src/utils/defaultConfig.js +++ b/src/utils/defaultConfig.js @@ -22,10 +22,8 @@ export const defaultConfig = { DATALAYER_FILE_SERVER_URL: null, AUTO_SUBSCRIBE_FILESTORE: false, TASKS: { - AUDIT_SYNC_TASK_INTERVAL: 30, - DATAMODEL_SYNC_TASK_INTERVAL: 60, GOVERNANCE_SYNC_TASK_INTERVAL: 86400, - ORGANIZATION_META_SYNC_TASK_INTERVAL: 86400, + ORGANIZATION_META_SYNC_TASK_INTERVAL: 300, PICKLIST_SYNC_TASK_INTERVAL: 30, }, }, From ef7cf1799b6e5b0db131fa6af2fb354d135ec960 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Fri, 20 Oct 2023 18:05:45 -0400 Subject: [PATCH 09/18] feat: sync remaining count for organizations --- src/controllers/governance.controller.js | 7 ++ src/controllers/offer.controller.js | 2 + src/controllers/organization.controller.js | 21 +++- src/controllers/project.controller.js | 5 + src/controllers/staging.controller.js | 17 ++- src/controllers/units.controller.js | 6 + src/database/index.js | 2 - .../20231020201652-OrgSyncStatus.js | 2 +- .../20231020214357-OrgSyncRemainingCount.js | 23 ++++ src/database/migrations/index.js | 5 + src/datalayer/persistance.js | 1 - src/datalayer/syncService.js | 6 +- src/datalayer/writeService.js | 2 - src/middleware.js | 7 ++ src/models/governance/governance.model.js | 6 +- .../organizations/organizations.model.js | 7 +- .../organizations.modeltypes.cjs | 5 +- src/server.js | 2 - src/tasks/sync-audit-table.js | 109 +++++++++++------- src/tasks/sync-datalayer.js | 2 - src/tasks/sync-default-organizations.js | 2 - src/tasks/sync-governance-body.js | 2 - src/tasks/sync-organization-meta.js | 3 - src/tasks/sync-picklists.js | 2 - src/utils/defaultConfig.js | 4 +- 25 files changed, 174 insertions(+), 76 deletions(-) create mode 100644 src/database/migrations/20231020214357-OrgSyncRemainingCount.js diff --git a/src/controllers/governance.controller.js b/src/controllers/governance.controller.js index 0f6c9a97..1f5b201f 100644 --- a/src/controllers/governance.controller.js +++ b/src/controllers/governance.controller.js @@ -37,10 +37,12 @@ export const isCreated = async (req, res) => { if (results) { return res.json({ created: true, + success: true, }); } else { return res.json({ created: false, + success: true, }); } } catch (error) { @@ -116,6 +118,7 @@ export const createGoveranceBody = async (req, res) => { return res.json({ message: 'Setting up new Governance Body on this node, this can take a few mins', + success: true, }); } catch (error) { res.status(400).json({ @@ -141,6 +144,7 @@ export const setDefaultOrgList = async (req, res) => { return res.json({ message: 'Committed this new organization list to the datalayer', + success: true, }); } catch (error) { console.trace(error); @@ -167,6 +171,7 @@ export const setPickList = async (req, res) => { return res.json({ message: 'Committed this pick list to the datalayer', + success: true, }); } catch (error) { res.status(400).json({ @@ -191,6 +196,7 @@ export const setGlossary = async (req, res) => { return res.json({ message: 'Committed glossary to the datalayer', + success: true, }); } catch (error) { res.status(400).json({ @@ -206,6 +212,7 @@ export const sync = async (req, res) => { Governance.sync(); return res.json({ message: 'Syncing Governance Body', + success: true, }); } catch (error) { res.status(400).json({ diff --git a/src/controllers/offer.controller.js b/src/controllers/offer.controller.js index de2acbaa..ab18b9a2 100644 --- a/src/controllers/offer.controller.js +++ b/src/controllers/offer.controller.js @@ -102,6 +102,7 @@ export const importOfferFile = async (req, res) => { res.json({ message: 'Offer has been imported for review.', + success: true, }); } catch (error) { console.trace(error); @@ -132,6 +133,7 @@ export const commitImportedOfferFile = async (req, res) => { res.json({ message: 'Offer Accepted.', tradeId: response.trade_id, + success: true, }); await Meta.destroy({ diff --git a/src/controllers/organization.controller.js b/src/controllers/organization.controller.js index 7ec3823f..21220d8a 100644 --- a/src/controllers/organization.controller.js +++ b/src/controllers/organization.controller.js @@ -1,3 +1,4 @@ +import { Sequelize } from 'sequelize'; import { sequelize } from '../database'; import { Organization } from '../models/organizations'; @@ -62,6 +63,7 @@ export const createV2 = async (req, res) => { return res.json({ message: 'Your organization already exists.', orgId: myOrganization.orgUid, + success: false, }); } else { const { name } = req.body; @@ -81,6 +83,7 @@ export const createV2 = async (req, res) => { return res.json({ message: 'New organization is currently being created. It can take up to 30 mins. Please do not interrupt this process.', + success: true, }); } } catch (error) { @@ -104,6 +107,7 @@ export const create = async (req, res) => { return res.json({ message: 'Your organization already exists.', orgId: myOrganization.orgUid, + success: false, }); } else { const { name, icon } = req.body; @@ -111,6 +115,7 @@ export const create = async (req, res) => { return res.json({ message: 'New organization created successfully.', + success: true, orgId: await Organization.createHomeOrganization( name, icon, @@ -135,13 +140,18 @@ export const resetHomeOrg = async (req, res) => { await Promise.all([ Organization.destroy({ where: { isHome: true } }), Staging.destroy({ - where: {}, + where: { + id: { + [Sequelize.Op.ne]: null, + }, + }, truncate: true, }), ]); res.json({ message: 'Your home organization was reset, please create a new one.', + success: true, }); } catch (error) { res.status(400).json({ @@ -162,6 +172,7 @@ export const importOrg = async (req, res) => { res.json({ message: 'Importing and subscribing organization this can take a few mins.', + success: true, }); return Organization.importOrganization(orgUid); @@ -186,6 +197,7 @@ export const importHomeOrg = async (req, res) => { res.json({ message: 'Importing home organization.', + success: true, }); } catch (error) { console.trace(error); @@ -207,6 +219,7 @@ export const subscribeToOrganization = async (req, res) => { return res.json({ message: 'Subscribed to organization', + success: true, }); } catch (error) { res.status(400).json({ @@ -242,6 +255,7 @@ export const deleteImportedOrg = async (req, res) => { return res.json({ message: 'UnSubscribed to organization, you will no longer receive updates.', + success: true, }); } catch (error) { res.status(400).json({ @@ -282,6 +296,7 @@ export const unsubscribeToOrganization = async (req, res) => { return res.json({ message: 'UnSubscribed to organization, you will no longer receive updates.', + success: true, }); } catch (error) { res.status(400).json({ @@ -322,6 +337,7 @@ export const resyncOrganization = async (req, res) => { return res.json({ message: 'Resyncing organization completed', + success: true, }); } catch (error) { res.status(400).json({ @@ -367,6 +383,7 @@ export const addMirror = async (req, res) => { await Organization.addMirror(req.body.storeId, req.body.url); return res.json({ message: `Mirror added for ${req.body.storeId}.`, + success: true, }); } catch (error) { res.status(400).json({ @@ -404,6 +421,7 @@ export const removeMirror = async (req, res) => { await Organization.removeMirror(req.body.storeId, req.body.coinId); return res.json({ message: `Mirror removed for ${req.body.storeId}.`, + success: true, }); } catch (error) { res.status(400).json({ @@ -418,6 +436,7 @@ export const sync = async (req, res) => { Organization.syncOrganizationMeta(); return res.json({ message: 'Syncing All Organizations Metadata', + success: true, }); } catch (error) { res.status(400).json({ diff --git a/src/controllers/project.controller.js b/src/controllers/project.controller.js index f376de81..1fea824f 100644 --- a/src/controllers/project.controller.js +++ b/src/controllers/project.controller.js @@ -104,6 +104,7 @@ export const create = async (req, res) => { res.json({ message: 'Project staged successfully', uuid, + success: true, }); } catch (err) { res.status(400).json({ @@ -304,6 +305,7 @@ export const updateFromXLS = async (req, res) => { res.json({ message: 'Updates from xlsx added to staging', + success: true, }); } catch (error) { console.trace(error); @@ -418,6 +420,7 @@ const update = async (req, res, isTransfer = false) => { res.json({ message: 'Project update added to staging', + success: true, }); } catch (err) { res.status(400).json({ @@ -452,6 +455,7 @@ export const destroy = async (req, res) => { res.json({ message: 'Project deleted successfully', + success: true, }); } catch (err) { res.status(400).json({ @@ -474,6 +478,7 @@ export const batchUpload = async (req, res) => { res.json({ message: 'CSV processing complete, your records have been added to the staging table.', + success: true, }); } catch (error) { logger.error('Batch Upload Failed.', error); diff --git a/src/controllers/staging.controller.js b/src/controllers/staging.controller.js index 51bee162..c40b21f7 100644 --- a/src/controllers/staging.controller.js +++ b/src/controllers/staging.controller.js @@ -1,5 +1,6 @@ import _ from 'lodash'; +import { Sequelize } from 'sequelize'; import { Staging } from '../models'; import { @@ -22,11 +23,13 @@ export const hasPendingTransactions = async (req, res) => { res.json({ confirmed: true, message: 'There are no pending transactions', + success: true, }); } catch (error) { res.json({ confirmed: false, message: 'There are currently pending transactions', + success: true, }); } }; @@ -102,7 +105,10 @@ export const commit = async (req, res) => { _.get(req, 'body.ids', []), ); - res.json({ message: 'Staging Table committed to full node' }); + res.json({ + message: 'Staging Table committed to full node', + success: true, + }); } catch (error) { console.trace(error); res.status(400).json({ @@ -125,6 +131,7 @@ export const destroy = async (req, res) => { }); res.json({ message: 'Deleted from stage', + success: true, }); } catch (error) { res.status(400).json({ @@ -140,11 +147,16 @@ export const clean = async (req, res) => { await assertIfReadOnlyMode(); await assertHomeOrgExists(); await Staging.destroy({ - where: {}, + where: { + id: { + [Sequelize.Op.ne]: null, + }, + }, truncate: true, }); res.json({ message: 'Staging Data Cleaned', + success: true, }); } catch (error) { res.status(400).json({ @@ -193,6 +205,7 @@ export const retryRecrod = async (req, res) => { ); res.json({ message: 'Staging record re-staged.', + success: true, }); } catch (error) { res.status(400).json({ diff --git a/src/controllers/units.controller.js b/src/controllers/units.controller.js index f6468172..2ebbd94a 100644 --- a/src/controllers/units.controller.js +++ b/src/controllers/units.controller.js @@ -108,6 +108,7 @@ export const create = async (req, res) => { res.json({ message: 'Unit staged successfully', uuid, + success: true, }); } catch (error) { res.status(400).json({ @@ -318,6 +319,7 @@ export const updateFromXLS = async (req, res) => { res.json({ message: 'Updates from xlsx added to staging', + success: true, }); } catch (error) { logger.error('Batch Upload Failed.', error); @@ -406,6 +408,7 @@ export const update = async (req, res) => { res.json({ message: 'Unit update added to staging', + success: true, }); } catch (err) { res.status(400).json({ @@ -437,6 +440,7 @@ export const destroy = async (req, res) => { await Staging.upsert(stagedData); res.json({ message: 'Unit deleted successfully', + success: true, }); } catch (err) { res.status(400).json({ @@ -524,6 +528,7 @@ export const split = async (req, res) => { res.json({ message: 'Unit split successful', + success: true, }); } catch (error) { res.status(400).json({ @@ -546,6 +551,7 @@ export const batchUpload = async (req, res) => { res.json({ message: 'CSV processing complete, your records have been added to the staging table.', + success: true, }); } catch (error) { logger.error('Batch Upload Failed.', error); diff --git a/src/database/index.js b/src/database/index.js index d12ab53a..102c1409 100644 --- a/src/database/index.js +++ b/src/database/index.js @@ -18,8 +18,6 @@ const mirrorConfig = (process.env.NODE_ENV || 'local') === 'local' ? 'mirror' : 'mirrorTest'; export const sequelizeMirror = new Sequelize(config[mirrorConfig]); -logger.info('CADT:mirror-database'); - const logDebounce = _.debounce(() => { console.log('Mirror DB not connected'); logger.info('Mirror DB not connected'); diff --git a/src/database/migrations/20231020201652-OrgSyncStatus.js b/src/database/migrations/20231020201652-OrgSyncStatus.js index cc62e3fa..3dc295f1 100644 --- a/src/database/migrations/20231020201652-OrgSyncStatus.js +++ b/src/database/migrations/20231020201652-OrgSyncStatus.js @@ -6,7 +6,7 @@ export default { ['organizations'].map((table) => { queryInterface.addColumn(table, 'synced', { type: Sequelize.BOOLEAN, - allowNull: true, + allowNull: false, defaultValue: false, }); }), diff --git a/src/database/migrations/20231020214357-OrgSyncRemainingCount.js b/src/database/migrations/20231020214357-OrgSyncRemainingCount.js new file mode 100644 index 00000000..8b686daa --- /dev/null +++ b/src/database/migrations/20231020214357-OrgSyncRemainingCount.js @@ -0,0 +1,23 @@ +'use strict'; + +export default { + async up(queryInterface, Sequelize) { + await Promise.all( + ['organizations'].map((table) => { + queryInterface.addColumn(table, 'sync_remaining', { + type: Sequelize.INTEGER, + allowNull: true, + defaultValue: false, + }); + }), + ); + }, + + async down(queryInterface) { + await Promise.all( + ['organizations'].map((table) => { + queryInterface.removeColumn(table, 'sync_remaining'); + }), + ); + }, +}; diff --git a/src/database/migrations/index.js b/src/database/migrations/index.js index 9c289a41..1ff83fb2 100644 --- a/src/database/migrations/index.js +++ b/src/database/migrations/index.js @@ -31,6 +31,7 @@ import ResetDBForNewSingletons from './20220816155101-reset-db-for-new-singleton import AddIsTransferColumn from './20220825124702-add-isTransfer-column'; import AddOrgMetadata from './20220831023546-add-org-metadata'; import OrgSyncStatus from './20231020201652-OrgSyncStatus'; +import OrgSyncRemaining from './20231020214357-OrgSyncRemainingCount'; export const migrations = [ { @@ -169,4 +170,8 @@ export const migrations = [ migration: OrgSyncStatus, name: '20231020201652-OrgSyncStatus', }, + { + migration: OrgSyncRemaining, + name: '20231020214357-OrgSyncRemainingCount', + }, ]; diff --git a/src/datalayer/persistance.js b/src/datalayer/persistance.js index 321c2003..fd2b5319 100644 --- a/src/datalayer/persistance.js +++ b/src/datalayer/persistance.js @@ -10,7 +10,6 @@ import { Organization } from '../models'; import { logger } from '../config/logger.cjs'; import { getChiaRoot } from '../utils/chia-root.js'; -logger.info('CADT:datalayer:persistance'); process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0; const CONFIG = getConfig().APP; diff --git a/src/datalayer/syncService.js b/src/datalayer/syncService.js index 1a02e187..e9f3dc6a 100644 --- a/src/datalayer/syncService.js +++ b/src/datalayer/syncService.js @@ -230,7 +230,7 @@ const getSubscribedStoreData = async (storeId, retry = 0) => { if (!USE_SIMULATOR) { logger.info(`Getting confirmation for ${storeId}.`); const storeExistAndIsConfirmed = await dataLayer.getRoot(storeId, true); - logger.info(`Store exists and is found ${storeId}.`); + logger.info(`Store found in DataLayer: ${storeId}.`); if (!storeExistAndIsConfirmed) { logger.info( `Retrying subscribe to ${storeId}, store not yet confirmed.`, @@ -242,9 +242,7 @@ const getSubscribedStoreData = async (storeId, retry = 0) => { ); return getSubscribedStoreData(storeId, retry + 1); } else { - logger.debug( - `Store Exists and is confirmed, proceeding to get data ${storeId}`, - ); + logger.debug(`Store is confirmed, proceeding to get data ${storeId}`); } } diff --git a/src/datalayer/writeService.js b/src/datalayer/writeService.js index c60b0618..9f825a90 100644 --- a/src/datalayer/writeService.js +++ b/src/datalayer/writeService.js @@ -10,8 +10,6 @@ import { logger } from '../config/logger.cjs'; import { Organization } from '../models'; import { publicIpv4 } from '../utils/ip-tools'; -logger.info('CADT:datalayer:writeService'); - const { USE_SIMULATOR, DATALAYER_FILE_SERVER_URL } = getConfig().APP; const createDataLayerStore = async () => { diff --git a/src/middleware.js b/src/middleware.js index 159dd213..4dbdd3ec 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -26,6 +26,7 @@ const headerKeys = Object.freeze({ WALLET_SYNCED: 'x-wallet-synced', HOME_ORGANIZATION_SYNCED: 'x-home-org-synced', ALL_DATA_SYNCED: 'x-data-synced', + SYNC_REMAINING: 'x-sync-remaining', }); const app = express(); @@ -123,6 +124,12 @@ app.use(async function (req, res, next) { const notSynced = Object.keys(orgMap).find((key) => !orgMap[key].synced); res.setHeader(headerKeys.ALL_DATA_SYNCED, !notSynced); + + const syncRemaining = Object.keys(orgMap).reduce((agg, key) => { + return agg + orgMap[key].sync_remaining; + }, 0); + + res.setHeader(headerKeys.SYNC_REMAINING, syncRemaining); next(); }); diff --git a/src/models/governance/governance.model.js b/src/models/governance/governance.model.js index ef8974d0..afc2a592 100644 --- a/src/models/governance/governance.model.js +++ b/src/models/governance/governance.model.js @@ -194,7 +194,11 @@ class Governance extends Model { const rollbackChangesIfFailed = async () => { logger.info('Reverting Goverance Records'); await Governance.destroy({ - where: {}, + where: { + id: { + [Sequelize.Op.ne]: null, + }, + }, truncate: true, }); diff --git a/src/models/organizations/organizations.model.js b/src/models/organizations/organizations.model.js index 11a9a7a2..64d11199 100644 --- a/src/models/organizations/organizations.model.js +++ b/src/models/organizations/organizations.model.js @@ -18,8 +18,6 @@ import { getDataModelVersion } from '../../utils/helpers'; import { getConfig } from '../../utils/config-loader'; const { USE_SIMULATOR, AUTO_SUBSCRIBE_FILESTORE } = getConfig().APP; -logger.info('CADT:organizations'); - import ModelTypes from './organizations.modeltypes.cjs'; class Organization extends Model { @@ -53,7 +51,7 @@ class Organization extends Model { delete myOrganization.metadata; } - myOrganization.synced = myOrganization.synced === 1; + myOrganization.synced = myOrganization?.synced === 1; if (myOrganization && includeAddress) { myOrganization.xchAddress = await datalayer.getPublicAddress(); @@ -74,6 +72,7 @@ class Organization extends Model { 'subscribed', 'synced', 'fileStoreSubscribed', + 'sync_remaining', ], }); @@ -333,7 +332,7 @@ class Organization extends Model { static async syncOrganizationMeta() { try { const allSubscribedOrganizations = await Organization.findAll({ - subscribed: true, + where: { subscribed: true }, }); await Promise.all( diff --git a/src/models/organizations/organizations.modeltypes.cjs b/src/models/organizations/organizations.modeltypes.cjs index 77a7df85..3a66be11 100644 --- a/src/models/organizations/organizations.modeltypes.cjs +++ b/src/models/organizations/organizations.modeltypes.cjs @@ -35,9 +35,12 @@ module.exports = { }, synced: { type: Sequelize.BOOLEAN, - allowNull: true, defaultValue: false, }, + sync_remaining: { + type: Sequelize.INTEGER, + defaultValue: 0, + }, createdAt: Sequelize.DATE, updatedAt: Sequelize.DATE, }; diff --git a/src/server.js b/src/server.js index 4276aa7d..de1b58d5 100644 --- a/src/server.js +++ b/src/server.js @@ -12,8 +12,6 @@ import dotenv from 'dotenv'; dotenv.config(); -logger.info('CADT:server'); - const port = getConfig().APP.CW_PORT || 3030; const bindAddress = getConfig().APP.BIND_ADDRESS || 'localhost'; const server = http.createServer(rootRouter); diff --git a/src/tasks/sync-audit-table.js b/src/tasks/sync-audit-table.js index 9007b5f2..76b4cb77 100644 --- a/src/tasks/sync-audit-table.js +++ b/src/tasks/sync-audit-table.js @@ -1,5 +1,6 @@ import _ from 'lodash'; +import { Sequelize } from 'sequelize'; import { SimpleIntervalJob, Task } from 'toad-scheduler'; import { Organization, Audit, ModelKeys, Staging, Meta } from '../models'; import datalayer from '../datalayer'; @@ -39,26 +40,43 @@ const task = new Task('sync-audit', async () => { for (const modelKey of Object.keys(ModelKeys)) { logger.info(`Resetting ${modelKey}`); await ModelKeys[modelKey].destroy({ - where: {}, + where: { + id: { + [Sequelize.Op.ne]: null, + }, + }, truncate: true, }); } logger.info(`Resetting Audit Table`); await Audit.destroy({ - where: {}, + where: { + id: { + [Sequelize.Op.ne]: null, + }, + }, truncate: true, }); - logger.info(`Completing Migration`); await Meta.upsert({ metaKey: 'migratedToNewSync', metaValue: 'true', }); - await Organization.upsert({ - synced: false, - }); + await Organization.update( + { + synced: false, + sync_remaining: 0, + }, + { + where: { + id: { + [Sequelize.Op.ne]: null, + }, + }, + }, + ); logger.info(`Migration Complete`); } @@ -79,7 +97,7 @@ const task = new Task('sync-audit', async () => { const job = new SimpleIntervalJob( { - seconds: CONFIG?.TASKS?.AUDIT_SYNC_TASK_INTERVAL || 30, + seconds: 30, runImmediately: true, }, task, @@ -90,27 +108,13 @@ const processJob = async () => { await assertDataLayerAvailable(); await assertWalletIsSynced(); - logger.info('Syncing Registry Data'); const organizations = await Organization.findAll({ where: { subscribed: true }, raw: true, }); for (const organization of organizations) { - console.log(`Syncing ${organization.name}`); await syncOrganizationAudit(organization); - if (!CONFIG.USE_SIMULATOR) { - await new Promise((resolve) => - setTimeout( - resolve, - (CONFIG.TASKS?.AUDIT_SYNC_TASK_INTERVAL || 30) * 1000, - ), - ); - } - } - - if (!CONFIG.USE_SIMULATOR) { - await new Promise((resolve) => setTimeout(resolve, 5000)); } }; @@ -158,11 +162,17 @@ async function createTransaction(callback, afterCommitCallbacks) { const syncOrganizationAudit = async (organization) => { try { - logger.info(`Syncing Registry: ${_.get(organization, 'name')}`); let afterCommitCallbacks = []; const homeOrg = await Organization.getHomeOrg(); - const rootHistory = await datalayer.getRootHistory(organization.registryId); + const rootHistory = ( + await datalayer.getRootHistory(organization.registryId) + ).sort((a, b) => a.timestamp - b.timestamp); + + if (!rootHistory.length) { + logger.info(`No root history found for ${organization.name}`); + return; + } let lastRootSaved; @@ -173,30 +183,19 @@ const syncOrganizationAudit = async (organization) => { } else { lastRootSaved = await Audit.findOne({ where: { registryId: organization.registryId }, - order: [['createdAt', 'DESC']], + order: [['onchainConfirmationTimeStamp', 'DESC']], raw: true, }); } - if (!rootHistory.length) { - return; - } - let rootHash = _.get(rootHistory, '[0].root_hash'); - if (lastRootSaved) { - rootHash = lastRootSaved.rootHash; - } - - const historyIndex = rootHistory.findIndex( - (root) => root.root_hash === rootHash, - ); - if (!lastRootSaved) { + logger.info(`Syncing new registry ${organization.name}`); await Audit.create({ orgUid: organization.orgUid, registryId: organization.registryId, - rootHash: _.get(rootHistory, '[0].root_hash'), + rootHash, type: 'CREATE REGISTRY', change: null, table: null, @@ -218,24 +217,43 @@ const syncOrganizationAudit = async (organization) => { ); return; + } else { + rootHash = lastRootSaved.rootHash; } const isSynced = rootHistory[rootHistory.length - 1].root_hash === rootHash; + const historyIndex = rootHistory.findIndex( + (root) => root.root_hash === rootHash, + ); + await Organization.update( - { synced: isSynced }, + { + synced: isSynced, + sync_remaining: rootHistory.length - historyIndex - 1, + }, { where: { orgUid: organization.orgUid } }, ); if (isSynced) { - logger.info(`No new data to sync for ${organization.name}`); return; } + // Organization not synced, sync it + logger.info(' '); + logger.info(`Syncing Registry: ${_.get(organization, 'name')}`); + + if (!CONFIG.USE_SIMULATOR) { + await new Promise((resolve) => setTimeout(resolve, 30000)); + } + const root1 = _.get(rootHistory, `[${historyIndex}]`); const root2 = _.get(rootHistory, `[${historyIndex + 1}]`); if (!_.get(root2, 'confirmed')) { + logger.info( + `Waiting for the latest root for ${organization.name} to confirm`, + ); return; } @@ -246,6 +264,15 @@ const syncOrganizationAudit = async (organization) => { ); if (_.isEmpty(kvDiff)) { + const errorMsg = [ + `No data found for ${organization.name} in the current generation.`, + `Missing data for root hash: ${root2.root_hash}.`, + "Check your internet connection, otherwise the organization's file propagation server may be offline.", + 'Syncing for this organization will be halted until resolved.', + 'If the issue persists, contact the organization.', + ].join(' '); + + logger.error(errorMsg); return; } @@ -256,7 +283,7 @@ const syncOrganizationAudit = async (organization) => { diff.type === 'INSERT', ); - // 0x617574686F72 is hex for 'author' + // 0x617574686F72 is hex for 'author'T const author = kvDiff.filter( (diff) => (diff.key === '617574686f72' || diff.key === '0x617574686F72') && @@ -353,7 +380,7 @@ const syncOrganizationAudit = async (organization) => { } }; - return await createTransaction(updateTransaction, afterCommitCallbacks); + await createTransaction(updateTransaction, afterCommitCallbacks); } catch (error) { logger.error('Error syncing org audit', error); } diff --git a/src/tasks/sync-datalayer.js b/src/tasks/sync-datalayer.js index e202ed0e..4e8090a5 100644 --- a/src/tasks/sync-datalayer.js +++ b/src/tasks/sync-datalayer.js @@ -13,8 +13,6 @@ dotenv.config(); import { getConfig } from '../utils/config-loader'; const CONFIG = getConfig().APP; -logger.info('CADT:task:sync-datalayer'); - const spinner = new Spinner('Waiting for Updates %s'); spinner.setSpinnerString('|/-\\'); spinner.setSpinnerDelay(500); diff --git a/src/tasks/sync-default-organizations.js b/src/tasks/sync-default-organizations.js index bea96375..9ba85823 100644 --- a/src/tasks/sync-default-organizations.js +++ b/src/tasks/sync-default-organizations.js @@ -11,8 +11,6 @@ const CONFIG = getConfig().APP; import dotenv from 'dotenv'; dotenv.config(); -logger.info('CADT:task:sync-default-organizations'); - const task = new Task('sync-default-organizations', async () => { try { await assertDataLayerAvailable(); diff --git a/src/tasks/sync-governance-body.js b/src/tasks/sync-governance-body.js index 0c3b9085..de9b245e 100644 --- a/src/tasks/sync-governance-body.js +++ b/src/tasks/sync-governance-body.js @@ -14,8 +14,6 @@ const CONFIG = getConfig(); import dotenv from 'dotenv'; dotenv.config(); -logger.info('CADT:task:sync-governance'); - const task = new Task('sync-governance-meta', async () => { try { await assertDataLayerAvailable(); diff --git a/src/tasks/sync-organization-meta.js b/src/tasks/sync-organization-meta.js index fbe03827..652ccb23 100644 --- a/src/tasks/sync-organization-meta.js +++ b/src/tasks/sync-organization-meta.js @@ -12,13 +12,10 @@ const CONFIG = getConfig().APP; import dotenv from 'dotenv'; dotenv.config(); -logger.info('CADT:task:sync-organizations'); - const task = new Task('sync-organization-meta', async () => { try { await assertDataLayerAvailable(); await assertWalletIsSynced(); - logger.info('Syncing subscribed organizations'); if (!CONFIG.USE_SIMULATOR) { Organization.syncOrganizationMeta(); } diff --git a/src/tasks/sync-picklists.js b/src/tasks/sync-picklists.js index be9b8abd..0f762370 100644 --- a/src/tasks/sync-picklists.js +++ b/src/tasks/sync-picklists.js @@ -9,8 +9,6 @@ import { getConfig } from '../utils/config-loader'; const CONFIG = getConfig().APP; -logger.info('CADT:task:sync-picklists'); - const task = new Task('sync-picklist', async () => { try { await assertDataLayerAvailable(); diff --git a/src/utils/defaultConfig.js b/src/utils/defaultConfig.js index 594d5bb0..ca93057e 100644 --- a/src/utils/defaultConfig.js +++ b/src/utils/defaultConfig.js @@ -22,10 +22,8 @@ export const defaultConfig = { DATALAYER_FILE_SERVER_URL: null, AUTO_SUBSCRIBE_FILESTORE: false, TASKS: { - AUDIT_SYNC_TASK_INTERVAL: 30, - DATAMODEL_SYNC_TASK_INTERVAL: 60, GOVERNANCE_SYNC_TASK_INTERVAL: 86400, - ORGANIZATION_META_SYNC_TASK_INTERVAL: 86400, + ORGANIZATION_META_SYNC_TASK_INTERVAL: 300, PICKLIST_SYNC_TASK_INTERVAL: 30, }, }, From b5f79c1020807de288c9e890660cfe4e18ddeb9c Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Mon, 23 Oct 2023 13:21:33 -0400 Subject: [PATCH 10/18] fix: dont mutate homeorg info if no homeorg --- package-lock.json | 141 ++++++++---------- package.json | 25 ++-- src/middleware.js | 30 ++-- .../organizations/organizations.model.js | 16 +- src/tasks/sync-audit-table.js | 69 +++++---- src/tasks/sync-default-organizations.js | 2 +- src/tasks/sync-governance-body.js | 2 +- src/tasks/sync-organization-meta.js | 2 +- src/tasks/sync-picklists.js | 2 +- tests/integration/project.spec.js | 1 + tests/integration/unit.spec.js | 3 + tests/test-fixtures/project-fixtures.js | 2 + tests/test-fixtures/staging-fixtures.js | 1 + tests/test-fixtures/unit-fixtures.js | 2 + 14 files changed, 142 insertions(+), 156 deletions(-) diff --git a/package-lock.json b/package-lock.json index 246cc91c..d1876c1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,33 +8,32 @@ "name": "cadt", "version": "1.6.15", "dependencies": { - "@babel/eslint-parser": "^7.22.9", - "@chia-carbon/core-registry-config": "^1.0.2", - "@chia-carbon/core-registry-logger": "^1.0.12", + "@babel/eslint-parser": "^7.22.15", + "async-mutex": "^0.4.0", "body-parser": "^1.20.2", "cli-spinner": "^0.2.10", "cors": "^2.8.5", "csvtojson": "^2.0.10", - "dotenv": "^16.0.3", + "dotenv": "^16.3.1", "express": "^4.18.2", "express-joi-validation": "^5.0.1", - "joi": "^17.5.0", + "joi": "^17.11.0", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "log-update": "^4.0.0", - "multer": "*", + "multer": "^1.4.5-lts.1", "mysql2": "^2.3.3", "node-xlsx": "^0.23.0", - "regenerator-runtime": "^0.13.9", + "regenerator-runtime": "^0.13.11", "rxjs": "^7.8.1", - "sequelize": "^6.32.0", - "socket.io": "^4.6.1", + "sequelize": "^6.33.0", + "socket.io": "^4.7.2", "sqlite3": "^5.1.6", - "superagent": "^8.0.9", - "toad-scheduler": "^1.6.0", - "uuidv4": "^6", - "winston": "^3.7.2", - "winston-daily-rotate-file": "^4.6.1" + "superagent": "^8.1.2", + "toad-scheduler": "^3.0.0", + "uuidv4": "^6.2.13", + "winston": "^3.11.0", + "winston-daily-rotate-file": "^4.7.1" }, "bin": { "cadt": "build/server.js" @@ -1824,26 +1823,6 @@ "node": ">=6.9.0" } }, - "node_modules/@chia-carbon/core-registry-config": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@chia-carbon/core-registry-config/-/core-registry-config-1.0.3.tgz", - "integrity": "sha512-7bB+fihP0C/eRzTmDiOmbpLpfKYPjI0dN2074hbwmuIGgVHGMu12J2qt5Mae8pEWtkEIKk4517MJQTtWx8GmPw==", - "dependencies": { - "chia-root-resolver": "^1.0.0", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21" - } - }, - "node_modules/@chia-carbon/core-registry-logger": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@chia-carbon/core-registry-logger/-/core-registry-logger-1.0.12.tgz", - "integrity": "sha512-emeAXaKdqohjXXFwpDGkJbmeU4nIOSxtoqbVBARveSy1G8z3fgeK7lekm+4qmMtKPxv0Rmvy24UGT86WwaRj+w==", - "dependencies": { - "chia-root-resolver": "^1.0.0", - "winston": "^3.10.0", - "winston-daily-rotate-file": "^4.7.1" - } - }, "node_modules/@colors/colors": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", @@ -3109,6 +3088,14 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" }, + "node_modules/async-mutex": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.4.0.tgz", + "integrity": "sha512-eJFZ1YhRR8UN8eBLoNzcDPcy/jqjsg6I1AP+KvWQX80BqOSW1oJPJXDylPUEeMr2ZQvHgnQ//Lp6f3RQ1zI7HA==", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -3194,13 +3181,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.5.tgz", - "integrity": "sha512-Q6CdATeAvbScWPNLB8lzSO7fgUVBkQt6zLgNlfyeCr/EQaEQR+bWiBYYPYAFyE528BMjRhL+1QBMOI4jc/c5TA==", + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.6.tgz", + "integrity": "sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==", "dev": true, "dependencies": { "@babel/helper-define-polyfill-provider": "^0.4.3", - "core-js-compat": "^3.32.2" + "core-js-compat": "^3.33.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -3482,9 +3469,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001551", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001551.tgz", - "integrity": "sha512-vtBAez47BoGMMzlbYhfXrMV1kvRF2WP/lqiMuDu1Sb4EE4LKEgjopFDSRtZfdVnslNRpOqV/woE+Xgrwj6VQlg==", + "version": "1.0.30001553", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001553.tgz", + "integrity": "sha512-N0ttd6TrFfuqKNi+pMgWJTb9qrdJu4JSpgPFLe/lrD19ugC6fZgF0pUewRowDwzdDnb9V41mFcdlYgl/PyKf4A==", "funding": [ { "type": "opencollective", @@ -3586,11 +3573,6 @@ "node": "*" } }, - "node_modules/chia-root-resolver": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/chia-root-resolver/-/chia-root-resolver-1.0.0.tgz", - "integrity": "sha512-oZOYbZxzK0688hU9S2EYWZ8ks5NI9zOlABFDsqBtvZwvYZbXEUYaLob+AqMhxLG3p0Dr0Ry+Rm6VPKOl9fQvAA==" - }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -5228,9 +5210,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.562", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.562.tgz", - "integrity": "sha512-kMGVZLP65O2/oH7zzaoIA5hcr4/xPYO6Sa83FrIpWcd7YPPtSlxqwxTd8lJIwKxaiXM6FGsYK4ukyJ40XkW7jg==" + "version": "1.4.565", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.565.tgz", + "integrity": "sha512-XbMoT6yIvg2xzcbs5hCADi0dXBh4//En3oFXmtPX+jiyyiCTiM9DGFT2SLottjpEs9Z8Mh8SqahbR96MaHfuSg==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -6233,14 +6215,14 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6898,14 +6880,6 @@ "node": ">=6" } }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -6915,11 +6889,11 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", "dependencies": { - "get-intrinsic": "^1.1.1" + "get-intrinsic": "^1.2.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6952,6 +6926,17 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -7214,12 +7199,12 @@ } }, "node_modules/is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7809,14 +7794,6 @@ "node": ">= 12.0.0" } }, - "node_modules/logform/node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -10727,9 +10704,9 @@ } }, "node_modules/toad-scheduler": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/toad-scheduler/-/toad-scheduler-1.6.1.tgz", - "integrity": "sha512-UjNerGmJIp72lt1d6wtGZUdgzgYFM9xVJBeDJzCLOVIHbrf8c6e3iq6rswRV/8/KA8WJLUuH71LYu96yoXgNRQ==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toad-scheduler/-/toad-scheduler-3.0.0.tgz", + "integrity": "sha512-BYmrORvaGmjziir/ra8qD3qAKczJveqK5ZOO/wn7oS5qLI4iibOza3DBGgu+EwNp9zdlBTKSeZPmxZxzGy1dxw==" }, "node_modules/toidentifier": { "version": "1.0.1", diff --git a/package.json b/package.json index 61b5be27..cb868d7b 100644 --- a/package.json +++ b/package.json @@ -31,31 +31,32 @@ "assets": "package.json" }, "dependencies": { - "@babel/eslint-parser": "^7.22.9", + "@babel/eslint-parser": "^7.22.15", + "async-mutex": "^0.4.0", "body-parser": "^1.20.2", "cli-spinner": "^0.2.10", "cors": "^2.8.5", "csvtojson": "^2.0.10", - "dotenv": "^16.0.3", + "dotenv": "^16.3.1", "express": "^4.18.2", "express-joi-validation": "^5.0.1", - "joi": "^17.5.0", + "joi": "^17.11.0", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "log-update": "^4.0.0", - "multer": "*", + "multer": "^1.4.5-lts.1", "mysql2": "^2.3.3", "node-xlsx": "^0.23.0", - "regenerator-runtime": "^0.13.9", + "regenerator-runtime": "^0.13.11", "rxjs": "^7.8.1", - "sequelize": "^6.32.0", - "socket.io": "^4.6.1", + "sequelize": "^6.33.0", + "socket.io": "^4.7.2", "sqlite3": "^5.1.6", - "superagent": "^8.0.9", - "toad-scheduler": "^1.6.0", - "uuidv4": "^6", - "winston": "^3.7.2", - "winston-daily-rotate-file": "^4.6.1" + "superagent": "^8.1.2", + "toad-scheduler": "^3.0.0", + "uuidv4": "^6.2.13", + "winston": "^3.11.0", + "winston-daily-rotate-file": "^4.7.1" }, "devDependencies": { "@babel/cli": "^7.23.0", diff --git a/src/middleware.js b/src/middleware.js index 4dbdd3ec..9124e08f 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -101,19 +101,23 @@ app.use(function (req, res, next) { }); app.use(async function (req, res, next) { - // If the home organization is syncing, then we treat all requests as read-only - const homeOrg = await Organization.getHomeOrg(); - - if (req.method !== 'GET' && !homeOrg.synced) { - res.status(400).json({ - message: - 'Your organization data is still resyncing, please try again after it completes', - success: false, - }); - } else if (homeOrg.synced) { - res.setHeader(headerKeys.HOME_ORGANIZATION_SYNCED, true); - } else { - res.setHeader(headerKeys.HOME_ORGANIZATION_SYNCED, false); + if (process.env.NODE_ENV !== 'test') { + // If the home organization is syncing, then we treat all requests as read-only + const homeOrg = await Organization.getHomeOrg(); + + if (homeOrg) { + if (req.method !== 'GET' && !homeOrg.synced) { + res.status(400).json({ + message: + 'Your organization data is still resyncing, please try again after it completes', + success: false, + }); + } else if (homeOrg?.synced) { + res.setHeader(headerKeys.HOME_ORGANIZATION_SYNCED, true); + } else { + res.setHeader(headerKeys.HOME_ORGANIZATION_SYNCED, false); + } + } } next(); diff --git a/src/models/organizations/organizations.model.js b/src/models/organizations/organizations.model.js index 17560dbd..d8cf9971 100644 --- a/src/models/organizations/organizations.model.js +++ b/src/models/organizations/organizations.model.js @@ -23,16 +23,6 @@ import ModelTypes from './organizations.modeltypes.cjs'; class Organization extends Model { static async getHomeOrg(includeAddress = true) { const myOrganization = await Organization.findOne({ - attributes: [ - 'orgUid', - 'name', - 'icon', - 'subscribed', - 'registryId', - 'fileStoreId', - 'metadata', - 'synced', - ], where: { isHome: true }, raw: true, }); @@ -51,14 +41,16 @@ class Organization extends Model { delete myOrganization.metadata; } - myOrganization.synced = myOrganization?.synced === 1; - if (myOrganization && includeAddress) { myOrganization.xchAddress = await datalayer.getPublicAddress(); myOrganization.fileStoreSubscribed = true; return myOrganization; } + if (myOrganization) { + myOrganization.synced = myOrganization.synced === 1; + } + return myOrganization; } diff --git a/src/tasks/sync-audit-table.js b/src/tasks/sync-audit-table.js index 76b4cb77..b725968f 100644 --- a/src/tasks/sync-audit-table.js +++ b/src/tasks/sync-audit-table.js @@ -2,9 +2,10 @@ import _ from 'lodash'; import { Sequelize } from 'sequelize'; import { SimpleIntervalJob, Task } from 'toad-scheduler'; +import { Mutex } from 'async-mutex'; import { Organization, Audit, ModelKeys, Staging, Meta } from '../models'; import datalayer from '../datalayer'; -import { decodeHex } from '../utils/datalayer-utils'; +import { decodeHex, encodeHex } from '../utils/datalayer-utils'; import dotenv from 'dotenv'; import { logger } from '../config/logger.cjs'; import { sequelize, sequelizeMirror } from '../database'; @@ -16,16 +17,13 @@ import { import { mirrorDBEnabled } from '../database'; dotenv.config(); - +const mutex = new Mutex(); const CONFIG = getConfig().APP; -let taskIsRunning = false; - const task = new Task('sync-audit', async () => { - try { - if (!taskIsRunning) { - taskIsRunning = true; - + if (!mutex.isLocked()) { + const releaseMutex = await mutex.acquire(); + try { const hasMigratedToNewSyncMethod = await Meta.findOne({ where: { metaKey: 'migratedToNewSync' }, }); @@ -80,28 +78,28 @@ const task = new Task('sync-audit', async () => { logger.info(`Migration Complete`); } - } - } catch (error) { - logger.error(`Error during datasync: ${error.message}`); + } catch (error) { + logger.error(`Error during datasync: ${error.message}`); - // Log additional information if present in the error object - if (error.response && error.response.body) { - logger.error( - `Additional error details: ${JSON.stringify(error.response.body)}`, - ); + // Log additional information if present in the error object + if (error.response && error.response.body) { + logger.error( + `Additional error details: ${JSON.stringify(error.response.body)}`, + ); + } + } finally { + releaseMutex(); } - } finally { - taskIsRunning = false; } }); const job = new SimpleIntervalJob( { - seconds: 30, + seconds: 10, runImmediately: true, }, task, - 'sync-audit', + { id: 'sync-audit', preventOverrun: true }, ); const processJob = async () => { @@ -221,27 +219,32 @@ const syncOrganizationAudit = async (organization) => { rootHash = lastRootSaved.rootHash; } - const isSynced = rootHistory[rootHistory.length - 1].root_hash === rootHash; + let isSynced = rootHistory[rootHistory.length - 1].root_hash === rootHash; const historyIndex = rootHistory.findIndex( (root) => root.root_hash === rootHash, ); + const syncRemaining = rootHistory.length - historyIndex - 1; + await Organization.update( { synced: isSynced, - sync_remaining: rootHistory.length - historyIndex - 1, + sync_remaining: syncRemaining, }, { where: { orgUid: organization.orgUid } }, ); - if (isSynced) { + if (process.env.NODE_ENV !== 'test' && isSynced) { return; } // Organization not synced, sync it logger.info(' '); logger.info(`Syncing Registry: ${_.get(organization, 'name')}`); + logger.info( + `${organization.name} is ${syncRemaining} DataLayer generations away from being fully synced.`, + ); if (!CONFIG.USE_SIMULATOR) { await new Promise((resolve) => setTimeout(resolve, 30000)); @@ -264,29 +267,29 @@ const syncOrganizationAudit = async (organization) => { ); if (_.isEmpty(kvDiff)) { - const errorMsg = [ - `No data found for ${organization.name} in the current generation.`, + const warningMsg = [ + `No data found for ${organization.name} in the current datalayer generation.`, `Missing data for root hash: ${root2.root_hash}.`, - "Check your internet connection, otherwise the organization's file propagation server may be offline.", - 'Syncing for this organization will be halted until resolved.', - 'If the issue persists, contact the organization.', + `This issue is often temporary and could be due to a lag in data propagation.`, + 'Syncing for this organization will be paused until this is resolved.', + 'For ongoing issues, please contact the organization.', ].join(' '); - logger.error(errorMsg); + logger.warn(warningMsg); return; } - // 0x636f6d6d656e74 is hex for 'comment' const comment = kvDiff.filter( (diff) => - (diff.key === '636f6d6d656e74' || diff.key === '0x636f6d6d656e74') && + (diff.key === encodeHex('comment') || + diff.key === `0x${encodeHex('comment')}`) && diff.type === 'INSERT', ); - // 0x617574686F72 is hex for 'author'T const author = kvDiff.filter( (diff) => - (diff.key === '617574686f72' || diff.key === '0x617574686F72') && + (diff.key === encodeHex('author') || + diff.key === `0x${encodeHex('author')}`) && diff.type === 'INSERT', ); diff --git a/src/tasks/sync-default-organizations.js b/src/tasks/sync-default-organizations.js index 9ba85823..f4bc4ddd 100644 --- a/src/tasks/sync-default-organizations.js +++ b/src/tasks/sync-default-organizations.js @@ -34,7 +34,7 @@ const job = new SimpleIntervalJob( runImmediately: true, }, task, - 'sync-default-organizations', + { id: 'sync-default-organizations', preventOverrun: true }, ); export default job; diff --git a/src/tasks/sync-governance-body.js b/src/tasks/sync-governance-body.js index de9b245e..6efef003 100644 --- a/src/tasks/sync-governance-body.js +++ b/src/tasks/sync-governance-body.js @@ -51,7 +51,7 @@ const job = new SimpleIntervalJob( runImmediately: true, }, task, - 'sync-governance-meta', + { id: 'sync-governance-meta', preventOverrun: true }, ); export default job; diff --git a/src/tasks/sync-organization-meta.js b/src/tasks/sync-organization-meta.js index 652ccb23..c333dba9 100644 --- a/src/tasks/sync-organization-meta.js +++ b/src/tasks/sync-organization-meta.js @@ -36,7 +36,7 @@ const job = new SimpleIntervalJob( runImmediately: true, }, task, - 'sync-organization-meta', + { id: 'sync-organization-meta', preventOverrun: true }, ); export default job; diff --git a/src/tasks/sync-picklists.js b/src/tasks/sync-picklists.js index 0f762370..7d82da67 100644 --- a/src/tasks/sync-picklists.js +++ b/src/tasks/sync-picklists.js @@ -28,7 +28,7 @@ const job = new SimpleIntervalJob( runImmediately: true, }, task, - 'sync-picklist', + { id: 'sync-picklist', preventOverrun: true }, ); export default job; diff --git a/tests/integration/project.spec.js b/tests/integration/project.spec.js index 02bd5d50..ad12769d 100644 --- a/tests/integration/project.spec.js +++ b/tests/integration/project.spec.js @@ -58,6 +58,7 @@ describe('Project Resource Integration Tests', function () { await testFixtures.commitStagingRecords(); await testFixtures.waitForDataLayerSync(); await testFixtures.waitForDataLayerSync(); + await testFixtures.waitForDataLayerSync(); // The staging table should be empty after committing expect(await testFixtures.getLastCreatedStagingRecord()).to.equal( diff --git a/tests/integration/unit.spec.js b/tests/integration/unit.spec.js index 92085191..99081e76 100644 --- a/tests/integration/unit.spec.js +++ b/tests/integration/unit.spec.js @@ -155,6 +155,7 @@ describe('Unit Resource Integration Tests', function () { expect(createdCommitResult.statusCode).to.equal(200); expect(createdCommitResult.body).to.deep.equal({ message: 'Staging Table committed to full node', + success: true, }); // The node simulator runs on an async process, we are importing @@ -191,6 +192,7 @@ describe('Unit Resource Integration Tests', function () { expect(unitRes.body).to.deep.equal({ message: 'Unit split successful', + success: true, }); expect(unitRes.statusCode).to.equal(200); @@ -247,6 +249,7 @@ describe('Unit Resource Integration Tests', function () { expect(stagingRes.statusCode).to.equal(200); expect(commitRes.body).to.deep.equal({ message: 'Staging Table committed to full node', + success: true, }); // After commiting the true flag should be set to this staging record diff --git a/tests/test-fixtures/project-fixtures.js b/tests/test-fixtures/project-fixtures.js index 2a27e467..19ab4446 100644 --- a/tests/test-fixtures/project-fixtures.js +++ b/tests/test-fixtures/project-fixtures.js @@ -37,6 +37,7 @@ export const updateProject = async (warehouseProjectId, originalRecord) => { expect(result.body).to.deep.equal({ message: 'Project update added to staging', + success: true, }); expect(result.statusCode).to.equal(200); @@ -49,6 +50,7 @@ export const deleteProject = async (warehouseProjectId) => { .send({ warehouseProjectId }); expect(result.body).to.deep.equal({ message: 'Project deleted successfully', + success: true, }); expect(result.statusCode).to.equal(200); return result; diff --git a/tests/test-fixtures/staging-fixtures.js b/tests/test-fixtures/staging-fixtures.js index 0d9f2ebd..a7979932 100644 --- a/tests/test-fixtures/staging-fixtures.js +++ b/tests/test-fixtures/staging-fixtures.js @@ -24,6 +24,7 @@ export const commitStagingRecords = async () => { expect(results.statusCode).to.equal(200); expect(results.body).to.deep.equal({ message: 'Staging Table committed to full node', + success: true, }); return results; diff --git a/tests/test-fixtures/unit-fixtures.js b/tests/test-fixtures/unit-fixtures.js index 822b15dc..b5415581 100644 --- a/tests/test-fixtures/unit-fixtures.js +++ b/tests/test-fixtures/unit-fixtures.js @@ -24,6 +24,7 @@ export const deleteUnit = async (warehouseUnitId) => { .send({ warehouseUnitId }); expect(result.body).to.deep.equal({ message: 'Unit deleted successfully', + success: true, }); expect(result.statusCode).to.equal(200); return result; @@ -50,6 +51,7 @@ export const updateUnit = async (warehouseUnitId, originalRecord) => { expect(result.body).to.deep.equal({ message: 'Unit update added to staging', + success: true, }); expect(result.statusCode).to.equal(200); From 12966c879f6a7360a0c2eefb328bd5f38019cd81 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Tue, 24 Oct 2023 14:10:49 -0400 Subject: [PATCH 11/18] test: fix test --- tests/resources/projects.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/resources/projects.spec.js b/tests/resources/projects.spec.js index e2a721cd..bcb87e76 100644 --- a/tests/resources/projects.spec.js +++ b/tests/resources/projects.spec.js @@ -56,7 +56,7 @@ describe('Project Resource CRUD', function () { it('gets all the projects available', async function () { // no query params const projects = await testFixtures.getProjectByQuery(); - expect(projects.length).to.equal(11); + expect(projects.length).to.equal(12); }).timeout(TEST_WAIT_TIME * 10); it('gets all the projects filtered by orgUid', async function () { From f64f650abdc5acdcd12ffaa58ec721799453b5bf Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Sat, 28 Oct 2023 08:56:43 -0400 Subject: [PATCH 12/18] feat: sync fix by looking at timestamps instead of hashes --- src/tasks/sync-audit-table.js | 82 ++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 15 deletions(-) diff --git a/src/tasks/sync-audit-table.js b/src/tasks/sync-audit-table.js index b725968f..beae8776 100644 --- a/src/tasks/sync-audit-table.js +++ b/src/tasks/sync-audit-table.js @@ -116,6 +116,42 @@ const processJob = async () => { } }; +/** + * Optimizes and sorts an array of key-value differences. + * NOTE: The only reason this function works is because we treat INSERTS as UPSERTS + * If that ever changes, this function will need to be removed. + * + * @param {Array} kvDiff - An array of objects with { key, type } structure. + * @returns {Array} - An optimized and sorted array. + */ +function optimizeAndSortKvDiff(kvDiff) { + const deleteKeys = new Set(); + const insertKeys = new Set(); + + // Populate the Sets for quicker lookup + for (const diff of kvDiff) { + if (diff.type === 'DELETE') { + deleteKeys.add(diff.key); + } else if (diff.type === 'INSERT') { + insertKeys.add(diff.key); + } + } + + // Remove DELETE keys that also exist in INSERT keys + for (const insertKey of insertKeys) { + deleteKeys.delete(insertKey); + } + + // Filter and sort the array based on the optimized DELETE keys + const filteredArray = kvDiff.filter((diff) => { + return diff.type !== 'DELETE' || deleteKeys.has(diff.key); + }); + + return filteredArray.sort((a, b) => { + return a.type === b.type ? 0 : a.type === 'DELETE' ? -1 : 1; + }); +} + async function createTransaction(callback, afterCommitCallbacks) { let result = null; @@ -184,20 +220,26 @@ const syncOrganizationAudit = async (organization) => { order: [['onchainConfirmationTimeStamp', 'DESC']], raw: true, }); + + // There was an oversight in the audit model where we named it onChainConfirmationTimeStamp but + // the RPC result calls in timestamp. This is a temporary fix to ensure that we can still sync + lastRootSaved.timestamp = Number( + lastRootSaved.onchainConfirmationTimeStamp, + ); } - let rootHash = _.get(rootHistory, '[0].root_hash'); + let generation = _.get(rootHistory, '[0]'); if (!lastRootSaved) { logger.info(`Syncing new registry ${organization.name}`); await Audit.create({ orgUid: organization.orgUid, registryId: organization.registryId, - rootHash, + rootHash: generation.root_hash, type: 'CREATE REGISTRY', change: null, table: null, - onchainConfirmationTimeStamp: _.get(rootHistory, '[0].timestamp'), + onchainConfirmationTimeStamp: generation.timestamp, }); // Destroy existing records for this singleton @@ -216,15 +258,22 @@ const syncOrganizationAudit = async (organization) => { return; } else { - rootHash = lastRootSaved.rootHash; + generation = lastRootSaved; } - let isSynced = rootHistory[rootHistory.length - 1].root_hash === rootHash; + let isSynced = + rootHistory[rootHistory.length - 1].root_hash === generation.root_hash; const historyIndex = rootHistory.findIndex( - (root) => root.root_hash === rootHash, + (root) => root.timestamp === generation.timestamp, ); + if (historyIndex === -1) { + logger.error( + `Could not find root history for ${organization.name} with timestamp ${generation.timestamp}, something is wrong and the sync for this organization will be paused until this is resolved.`, + ); + } + const syncRemaining = rootHistory.length - historyIndex - 1; await Organization.update( @@ -293,14 +342,13 @@ const syncOrganizationAudit = async (organization) => { diff.type === 'INSERT', ); - // Process any deletes in the kv diff first to ensure correct processing order - kvDiff.sort((a, b) => { - const typeOrder = { DELETE: 0, INSERT: 1 }; - return typeOrder[a.type] - typeOrder[b.type]; - }); + // This optimizedKvDiff will remove all the DELETES that have corresponding INSERTS + // This is because we treat INSERTS as UPSERTS and we can save time and reduce DB thrashing + // by not processing the DELETE for that record. + const optimizedKvDiff = optimizeAndSortKvDiff(kvDiff); const updateTransaction = async (transaction, mirrorTransaction) => { - for (const diff of kvDiff) { + for (const diff of optimizedKvDiff) { const key = decodeHex(diff.key); const modelKey = key.split('|')[0]; @@ -314,12 +362,16 @@ const syncOrganizationAudit = async (organization) => { change: decodeHex(diff.value), onchainConfirmationTimeStamp: root2.timestamp, comment: _.get( - JSON.parse(decodeHex(_.get(comment, '[0].value', '7b7d'))), + JSON.parse( + decodeHex(_.get(comment, '[0].value', encodeHex('{}'))), + ), 'comment', '', ), author: _.get( - JSON.parse(decodeHex(_.get(author, '[0].value', '7b7d'))), + JSON.parse( + decodeHex(_.get(author, '[0].value', encodeHex('{}'))), + ), 'author', '', ), @@ -331,7 +383,7 @@ const syncOrganizationAudit = async (organization) => { record[ModelKeys[modelKey].primaryKeyAttributes[0]]; if (diff.type === 'INSERT') { - logger.info(`INSERTING: ${modelKey} - ${primaryKeyValue}`); + logger.info(`UPSERTING: ${modelKey} - ${primaryKeyValue}`); await ModelKeys[modelKey].upsert(record, { transaction, mirrorTransaction, From 71e12724b7f1885a3951cddfcbd1dac172eeb677 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Sun, 29 Oct 2023 07:56:48 -0400 Subject: [PATCH 13/18] feat: sync fix by looking at timestamps instead of hashes --- src/tasks/sync-audit-table.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tasks/sync-audit-table.js b/src/tasks/sync-audit-table.js index beae8776..74cc9f93 100644 --- a/src/tasks/sync-audit-table.js +++ b/src/tasks/sync-audit-table.js @@ -221,11 +221,13 @@ const syncOrganizationAudit = async (organization) => { raw: true, }); - // There was an oversight in the audit model where we named it onChainConfirmationTimeStamp but - // the RPC result calls in timestamp. This is a temporary fix to ensure that we can still sync - lastRootSaved.timestamp = Number( - lastRootSaved.onchainConfirmationTimeStamp, - ); + if (lastRootSaved) { + // There was an oversight in the audit model where we named it onChainConfirmationTimeStamp but + // the RPC result calls in timestamp. This is a temporary fix to ensure that we can still sync + lastRootSaved.timestamp = Number( + lastRootSaved?.onchainConfirmationTimeStamp || 0, + ); + } } let generation = _.get(rootHistory, '[0]'); From 491b620538062828d5452586d1aa263e5075f588 Mon Sep 17 00:00:00 2001 From: Chris Marslender Date: Wed, 1 Nov 2023 13:58:42 -0700 Subject: [PATCH 14/18] ci: Update glue to use JWT auth (#955) --- .github/workflows/build.yaml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index c419d30b..eb107a3a 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -12,6 +12,10 @@ concurrency: group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }} cancel-in-progress: true +permissions: + id-token: write + contents: write + jobs: build: name: Build Binaries @@ -298,7 +302,10 @@ jobs: cadt-linux-x64-deb/*.deb cadt-linux-arm64-deb/*.deb + - name: Gets JWT Token from GitHub + uses: Chia-Network/actions/github/jwt@main + - name: Trigger apt repo update run: | - curl -s -XPOST -H "Authorization: Bearer ${{ secrets.GLUE_ACCESS_TOKEN }}" --data '{"cadt_repo":"cadt","release_version":"${{ steps.tag-name.outputs.TAGNAME }}"}' ${{ secrets.GLUE_API_URL }}/api/v1/cadt/${{ github.sha }}/start - curl -s -XPOST -H "Authorization: Bearer ${{ secrets.GLUE_ACCESS_TOKEN }}" --data '{"cadt_repo":"cadt","release_version":"${{ steps.tag-name.outputs.TAGNAME }}"}' ${{ secrets.GLUE_API_URL }}/api/v1/cadt/${{ github.sha }}/success/deploy + curl -s -XPOST -H "Authorization: Bearer ${{ env.JWT_TOKEN }}" --data '{"cadt_repo":"cadt","release_version":"${{ steps.tag-name.outputs.TAGNAME }}"}' ${{ secrets.GLUE_API_URL }}/api/v1/cadt/${{ github.sha }}/start + curl -s -XPOST -H "Authorization: Bearer ${{ env.JWT_TOKEN }}" --data '{"cadt_repo":"cadt","release_version":"${{ steps.tag-name.outputs.TAGNAME }}"}' ${{ secrets.GLUE_API_URL }}/api/v1/cadt/${{ github.sha }}/success/deploy From bcb7e42fb84958641024a5b7a119917df513d154 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Mon, 6 Nov 2023 10:15:39 -0500 Subject: [PATCH 15/18] fix: offset for number of generations remaining --- src/tasks/sync-audit-table.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tasks/sync-audit-table.js b/src/tasks/sync-audit-table.js index 74cc9f93..ae3dd0ec 100644 --- a/src/tasks/sync-audit-table.js +++ b/src/tasks/sync-audit-table.js @@ -294,7 +294,9 @@ const syncOrganizationAudit = async (organization) => { logger.info(' '); logger.info(`Syncing Registry: ${_.get(organization, 'name')}`); logger.info( - `${organization.name} is ${syncRemaining} DataLayer generations away from being fully synced.`, + `${organization.name} is ${ + syncRemaining + 1 + } DataLayer generations away from being fully synced.`, ); if (!CONFIG.USE_SIMULATOR) { From 5ea7c75f9a4a97900c18aae265d0c76b85681bbb Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Mon, 6 Nov 2023 12:30:06 -0500 Subject: [PATCH 16/18] fix: logging error in sync process --- src/tasks/sync-audit-table.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tasks/sync-audit-table.js b/src/tasks/sync-audit-table.js index ae3dd0ec..21b5a45b 100644 --- a/src/tasks/sync-audit-table.js +++ b/src/tasks/sync-audit-table.js @@ -227,6 +227,7 @@ const syncOrganizationAudit = async (organization) => { lastRootSaved.timestamp = Number( lastRootSaved?.onchainConfirmationTimeStamp || 0, ); + lastRootSaved.root_hash = lastRootSaved.rootHash; } } From aa610a5ecf3d349ae639eb1fbc5bed4166237613 Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Thu, 16 Nov 2023 11:04:36 -0500 Subject: [PATCH 17/18] fix: middleware bug during home org resync --- src/middleware.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/middleware.js b/src/middleware.js index 9124e08f..327c5390 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -106,12 +106,13 @@ app.use(async function (req, res, next) { const homeOrg = await Organization.getHomeOrg(); if (homeOrg) { - if (req.method !== 'GET' && !homeOrg.synced) { + if (!['GET', 'DELETE'].includes(req.method) && !homeOrg.synced) { res.status(400).json({ message: 'Your organization data is still resyncing, please try again after it completes', success: false, }); + return; } else if (homeOrg?.synced) { res.setHeader(headerKeys.HOME_ORGANIZATION_SYNCED, true); } else { From 4d73664f9d099f537b08d3fb6c9bd82f07826abe Mon Sep 17 00:00:00 2001 From: Zachary Brown Date: Thu, 16 Nov 2023 11:52:39 -0800 Subject: [PATCH 18/18] chore: Update version to 1.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cb868d7b..a56ee4e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cadt", - "version": "1.6.15", + "version": "1.7", "_comment": "DONT CHANGE MAJOR UNLESS DATAMODEL CHANGES: The major version corresponds to the datamodel version your using, so 2.0.0 means it'll use datamodel v2", "private": true, "bin": "build/server.js",