Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cc68af5a68 | |||
| 8b3fd59a69 | |||
| 21d078ed37 | |||
| 1e02eea2f0 | |||
| 2ee39b39bf | |||
| fa7791e203 | |||
| 9fb76e7277 |
165
package-lock.json
generated
165
package-lock.json
generated
@ -12,8 +12,11 @@
|
|||||||
"@aws-sdk/client-athena": "^3.699.0",
|
"@aws-sdk/client-athena": "^3.699.0",
|
||||||
"@aws-sdk/client-s3": "^3.701.0",
|
"@aws-sdk/client-s3": "^3.701.0",
|
||||||
"@aws-sdk/credential-providers": "^3.699.0",
|
"@aws-sdk/credential-providers": "^3.699.0",
|
||||||
|
"@fastify/cors": "^11.0.1",
|
||||||
|
"awsmetrics": "file:",
|
||||||
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"fastify": "^5.1.0",
|
"fastify": "^5.3.0",
|
||||||
"fastify-plugin": "^5.0.1",
|
"fastify-plugin": "^5.0.1",
|
||||||
"sequelize": "^6.37.5",
|
"sequelize": "^6.37.5",
|
||||||
"sqlite3": "^5.1.7"
|
"sqlite3": "^5.1.7"
|
||||||
@ -1040,6 +1043,26 @@
|
|||||||
"fast-uri": "^3.0.0"
|
"fast-uri": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@fastify/cors": {
|
||||||
|
"version": "11.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fastify/cors/-/cors-11.0.1.tgz",
|
||||||
|
"integrity": "sha512-dmZaE7M1f4SM8ZZuk5RhSsDJ+ezTgI7v3HHRj8Ow9CneczsPLZV6+2j2uwdaSLn8zhTv6QV0F4ZRcqdalGx1pQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fastify"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/fastify"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fastify-plugin": "^5.0.0",
|
||||||
|
"toad-cache": "^3.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@fastify/error": {
|
"node_modules/@fastify/error": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@fastify/error/-/error-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@fastify/error/-/error-4.0.0.tgz",
|
||||||
@ -1053,6 +1076,12 @@
|
|||||||
"fast-json-stringify": "^6.0.0"
|
"fast-json-stringify": "^6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@fastify/forwarded": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fastify/forwarded/-/forwarded-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-kJExsp4JCms7ipzg7SJ3y8DwmePaELHxKYtg+tZow+k0znUTf3cb+npgyqm8+ATZOdmfgfydIebPDWM172wfyA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@fastify/merge-json-schemas": {
|
"node_modules/@fastify/merge-json-schemas": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.1.1.tgz",
|
||||||
@ -1061,6 +1090,16 @@
|
|||||||
"fast-deep-equal": "^3.1.3"
|
"fast-deep-equal": "^3.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@fastify/proxy-addr": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fastify/proxy-addr/-/proxy-addr-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-37qVVA1qZ5sgH7KpHkkC4z9SK6StIsIcOmpjvMPXNb3vx2GQxhZocogVYbr2PbbeLCQxYIPDok307xEvRZOzGA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@fastify/forwarded": "^3.0.0",
|
||||||
|
"ipaddr.js": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@gar/promisify": {
|
"node_modules/@gar/promisify": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
|
||||||
@ -1896,6 +1935,10 @@
|
|||||||
"fastq": "^1.17.1"
|
"fastq": "^1.17.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/awsmetrics": {
|
||||||
|
"resolved": "",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
@ -1945,9 +1988,10 @@
|
|||||||
"integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA=="
|
"integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA=="
|
||||||
},
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
@ -2052,6 +2096,19 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"object-assign": "^4",
|
||||||
|
"vary": "^1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||||
@ -2238,9 +2295,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fastify": {
|
"node_modules/fastify": {
|
||||||
"version": "5.2.0",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/fastify/-/fastify-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/fastify/-/fastify-5.3.2.tgz",
|
||||||
"integrity": "sha512-3s+Qt5S14Eq5dCpnE0FxTp3z4xKChI83ZnMv+k0FwX+VUoZrgCFoLAxpfdi/vT4y6Mk+g7aAMt9pgXDoZmkefQ==",
|
"integrity": "sha512-AIPqBgtqBAwkOkrnwesEE+dOyU30dQ4kh7udxeGVR05CRGwubZx+p2H8P0C4cRnQT0+EPK4VGea2DTL2RtWttg==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@ -2251,20 +2308,21 @@
|
|||||||
"url": "https://opencollective.com/fastify"
|
"url": "https://opencollective.com/fastify"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fastify/ajv-compiler": "^4.0.0",
|
"@fastify/ajv-compiler": "^4.0.0",
|
||||||
"@fastify/error": "^4.0.0",
|
"@fastify/error": "^4.0.0",
|
||||||
"@fastify/fast-json-stringify-compiler": "^5.0.0",
|
"@fastify/fast-json-stringify-compiler": "^5.0.0",
|
||||||
|
"@fastify/proxy-addr": "^5.0.0",
|
||||||
"abstract-logging": "^2.0.1",
|
"abstract-logging": "^2.0.1",
|
||||||
"avvio": "^9.0.0",
|
"avvio": "^9.0.0",
|
||||||
"fast-json-stringify": "^6.0.0",
|
"fast-json-stringify": "^6.0.0",
|
||||||
"find-my-way": "^9.0.0",
|
"find-my-way": "^9.0.0",
|
||||||
"light-my-request": "^6.0.0",
|
"light-my-request": "^6.0.0",
|
||||||
"pino": "^9.0.0",
|
"pino": "^9.0.0",
|
||||||
"process-warning": "^4.0.0",
|
"process-warning": "^5.0.0",
|
||||||
"proxy-addr": "^2.0.7",
|
|
||||||
"rfdc": "^1.3.1",
|
"rfdc": "^1.3.1",
|
||||||
"secure-json-parse": "^3.0.1",
|
"secure-json-parse": "^4.0.0",
|
||||||
"semver": "^7.6.0",
|
"semver": "^7.6.0",
|
||||||
"toad-cache": "^3.7.0"
|
"toad-cache": "^3.7.0"
|
||||||
}
|
}
|
||||||
@ -2274,6 +2332,22 @@
|
|||||||
"resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-5.0.1.tgz",
|
||||||
"integrity": "sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ=="
|
"integrity": "sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/fastify/node_modules/process-warning": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fastify"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/fastify"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fastq": {
|
"node_modules/fastq": {
|
||||||
"version": "1.17.1",
|
"version": "1.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
|
||||||
@ -2300,14 +2374,6 @@
|
|||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/forwarded": {
|
|
||||||
"version": "0.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
|
||||||
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/fs-constants": {
|
"node_modules/fs-constants": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||||
@ -2528,11 +2594,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ipaddr.js": {
|
"node_modules/ipaddr.js": {
|
||||||
"version": "1.9.1",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz",
|
||||||
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
|
"integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-fullwidth-code-point": {
|
"node_modules/is-fullwidth-code-point": {
|
||||||
@ -2873,6 +2940,15 @@
|
|||||||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/object-assign": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/on-exit-leak-free": {
|
"node_modules/on-exit-leak-free": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz",
|
||||||
@ -3001,18 +3077,6 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/proxy-addr": {
|
|
||||||
"version": "2.0.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
|
||||||
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
|
|
||||||
"dependencies": {
|
|
||||||
"forwarded": "0.2.0",
|
|
||||||
"ipaddr.js": "1.9.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/pump": {
|
"node_modules/pump": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
|
||||||
@ -3164,9 +3228,20 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/secure-json-parse": {
|
"node_modules/secure-json-parse": {
|
||||||
"version": "3.0.1",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.0.0.tgz",
|
||||||
"integrity": "sha512-9QR7G96th4QJ2+dJwvZB+JoXyt8PN+DbEjOr6kL2/JU4KH8Eb2sFdU+gt8EDdzWDWoWH0uocDdfCoFzdVSixUA=="
|
"integrity": "sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fastify"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/fastify"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
},
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.6.3",
|
"version": "7.6.3",
|
||||||
@ -3475,9 +3550,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tar-fs": {
|
"node_modules/tar-fs": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz",
|
||||||
"integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
|
"integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chownr": "^1.1.1",
|
"chownr": "^1.1.1",
|
||||||
"mkdirp-classic": "^0.5.2",
|
"mkdirp-classic": "^0.5.2",
|
||||||
@ -3598,6 +3674,15 @@
|
|||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vary": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|||||||
@ -12,8 +12,11 @@
|
|||||||
"@aws-sdk/client-athena": "^3.699.0",
|
"@aws-sdk/client-athena": "^3.699.0",
|
||||||
"@aws-sdk/client-s3": "^3.701.0",
|
"@aws-sdk/client-s3": "^3.701.0",
|
||||||
"@aws-sdk/credential-providers": "^3.699.0",
|
"@aws-sdk/credential-providers": "^3.699.0",
|
||||||
|
"@fastify/cors": "^11.0.1",
|
||||||
|
"awsmetrics": "file:",
|
||||||
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"fastify": "^5.1.0",
|
"fastify": "^5.3.0",
|
||||||
"fastify-plugin": "^5.0.1",
|
"fastify-plugin": "^5.0.1",
|
||||||
"sequelize": "^6.37.5",
|
"sequelize": "^6.37.5",
|
||||||
"sqlite3": "^5.1.7"
|
"sqlite3": "^5.1.7"
|
||||||
|
|||||||
244
queries/dashboard.js
Normal file
244
queries/dashboard.js
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
|
||||||
|
import dotenv from "dotenv";
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
export const productResourceUsageQuery = `SELECT DISTINCT
|
||||||
|
line_item_product_code AS productCode,
|
||||||
|
COALESCE(NULLIF(TRIM(product_region_code), ''), 'global') AS regionCode,
|
||||||
|
line_item_usage_account_id AS accountId,
|
||||||
|
line_item_resource_id AS resourceId,
|
||||||
|
line_item_usage_type AS usageType,
|
||||||
|
line_item_usage_amount AS usageAmount,
|
||||||
|
line_item_unblended_rate AS unblendedRate,
|
||||||
|
line_item_unblended_cost AS unblendedCost,
|
||||||
|
line_item_blended_rate AS blendedRate,
|
||||||
|
line_item_blended_cost AS blendedCost,
|
||||||
|
pricing_term AS pricingTerm,
|
||||||
|
pricing_unit AS pricingUnit,
|
||||||
|
pricing_rate_code AS pricingRateCode,
|
||||||
|
pricing_currency AS pricingCurrency,
|
||||||
|
line_item_usage_start_date AS startDate,
|
||||||
|
line_item_usage_end_date AS endDate
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE line_item_usage_account_id = '%accountId%'
|
||||||
|
AND COALESCE(NULLIF(TRIM(product_region_code), ''), 'global') = '%regionCode%'
|
||||||
|
AND LOWER(line_item_product_code) = LOWER('%productCode%')
|
||||||
|
AND line_item_resource_id = '%resourceId%'
|
||||||
|
ORDER BY line_item_usage_start_date ASC;`;
|
||||||
|
|
||||||
|
|
||||||
|
export const allProductUsageQuery = `SELECT DISTINCT
|
||||||
|
line_item_product_code AS productCode,
|
||||||
|
COALESCE(NULLIF(TRIM(product_region_code), ''), 'global') AS regionCode,
|
||||||
|
line_item_usage_account_id AS accountId,
|
||||||
|
line_item_resource_id AS resourceId,
|
||||||
|
line_item_usage_type AS usageType,
|
||||||
|
line_item_usage_amount AS usageAmount,
|
||||||
|
line_item_unblended_cost AS unblendedCost,
|
||||||
|
line_item_blended_cost AS blendedCost,
|
||||||
|
line_item_usage_start_date AS startDate,
|
||||||
|
line_item_usage_end_date AS endDate
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
ORDER BY productCode, regionCode, accountId, startDate ASC;`;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// /accounts/cost-usage-summary
|
||||||
|
export const accountCostUsageSummaryQuery = `
|
||||||
|
SELECT
|
||||||
|
line_item_usage_account_id AS accountId,
|
||||||
|
SUM(line_item_usage_amount) AS totalUsageAmount,
|
||||||
|
SUM(line_item_unblended_cost) AS totalUnblendedCost,
|
||||||
|
SUM(line_item_blended_cost) AS totalBlendedCost
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
GROUP BY line_item_usage_account_id
|
||||||
|
ORDER BY totalUnblendedCost DESC;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const currentMonthSummary = `
|
||||||
|
SELECT
|
||||||
|
SUM(line_item_blended_cost) as totalBlendedCost,
|
||||||
|
SUM(line_item_unblended_cost) as totalUnblendedCost,
|
||||||
|
COUNT(DISTINCT line_item_usage_account_id) as accountCount,
|
||||||
|
COUNT(DISTINCT line_item_product_code) as serviceCount,
|
||||||
|
COUNT(DISTINCT bill_invoice_id) as invoiceCount,
|
||||||
|
CONCAT(year, '-', LPAD(month, 2, '0')) as month
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE year = CAST(YEAR(CURRENT_DATE) AS VARCHAR)
|
||||||
|
AND month = CAST(MONTH(CURRENT_DATE) AS VARCHAR)
|
||||||
|
AND line_item_blended_cost > 0
|
||||||
|
GROUP BY year, month
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const previousMonthSummary = `
|
||||||
|
SELECT
|
||||||
|
SUM(line_item_blended_cost) as totalBlendedCost,
|
||||||
|
CONCAT(year, '-', LPAD(month, 2, '0')) as month
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE year = CAST(YEAR(DATE_ADD('month', -1, CURRENT_DATE)) AS VARCHAR)
|
||||||
|
AND month = CAST(MONTH(DATE_ADD('month', -1, CURRENT_DATE)) AS VARCHAR)
|
||||||
|
AND line_item_blended_cost > 0
|
||||||
|
GROUP BY year, month
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const serviceBreakdown = `
|
||||||
|
SELECT
|
||||||
|
line_item_product_code as productCode,
|
||||||
|
SUM(line_item_blended_cost) as totalCost,
|
||||||
|
COUNT(DISTINCT line_item_resource_id) as resourceCount,
|
||||||
|
COUNT(DISTINCT line_item_usage_account_id) as accountCount
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE year = CAST(YEAR(DATE_ADD('month', -1, CURRENT_DATE)) AS VARCHAR)
|
||||||
|
AND month = CAST(MONTH(DATE_ADD('month', -1, CURRENT_DATE)) AS VARCHAR)
|
||||||
|
AND line_item_blended_cost > 0
|
||||||
|
GROUP BY line_item_product_code
|
||||||
|
ORDER BY totalCost DESC
|
||||||
|
LIMIT 10
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const topAccounts = `
|
||||||
|
SELECT
|
||||||
|
line_item_usage_account_id as accountId,
|
||||||
|
SUM(line_item_blended_cost) as totalCost,
|
||||||
|
COUNT(DISTINCT line_item_product_code) as serviceCount
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE year = CAST(YEAR(DATE_ADD('month', -1, CURRENT_DATE)) AS VARCHAR)
|
||||||
|
AND month = CAST(MONTH(DATE_ADD('month', -1, CURRENT_DATE)) AS VARCHAR)
|
||||||
|
AND line_item_blended_cost > 0
|
||||||
|
GROUP BY line_item_usage_account_id
|
||||||
|
ORDER BY totalCost DESC
|
||||||
|
LIMIT 10
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const dailyTrends = `
|
||||||
|
SELECT
|
||||||
|
line_item_usage_start_date as date,
|
||||||
|
SUM(line_item_blended_cost) as blendedCost,
|
||||||
|
SUM(line_item_unblended_cost) as unblendedCost
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE line_item_usage_start_date >= date_add('day', -30, current_date)
|
||||||
|
AND line_item_blended_cost > 0
|
||||||
|
GROUP BY line_item_usage_start_date
|
||||||
|
ORDER BY date DESC
|
||||||
|
LIMIT 31
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const todaySpending = `
|
||||||
|
SELECT
|
||||||
|
SUM(line_item_blended_cost) as todaysCost,
|
||||||
|
COUNT(DISTINCT line_item_product_code) as servicesUsed
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE line_item_usage_start_date = CURRENT_DATE
|
||||||
|
AND line_item_blended_cost > 0`;
|
||||||
|
|
||||||
|
// This week vs last week
|
||||||
|
export const weeklyComparison = `
|
||||||
|
SELECT
|
||||||
|
CASE
|
||||||
|
WHEN line_item_usage_start_date >= date_add('day', -7, current_date) THEN 'this_week'
|
||||||
|
WHEN line_item_usage_start_date >= date_add('day', -14, current_date) THEN 'last_week'
|
||||||
|
END as week_period,
|
||||||
|
SUM(line_item_blended_cost) as totalCost
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE line_item_usage_start_date >= date_add('day', -14, current_date)
|
||||||
|
GROUP BY CASE
|
||||||
|
WHEN line_item_usage_start_date >= date_add('day', -7, current_date) THEN 'this_week'
|
||||||
|
WHEN line_item_usage_start_date >= date_add('day', -14, current_date) THEN 'last_week'
|
||||||
|
END
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Service drill-down queries
|
||||||
|
export const serviceAccountBreakdown = `
|
||||||
|
SELECT
|
||||||
|
line_item_usage_account_id as accountId,
|
||||||
|
SUM(line_item_blended_cost) as totalCost,
|
||||||
|
COUNT(DISTINCT line_item_resource_id) as resourceCount,
|
||||||
|
COUNT(DISTINCT line_item_usage_start_date) as daysActive
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE line_item_product_code = '%serviceCode%'
|
||||||
|
AND line_item_usage_start_date >= date_add('day', -%days%, current_date)
|
||||||
|
AND line_item_blended_cost > 0
|
||||||
|
GROUP BY line_item_usage_account_id
|
||||||
|
ORDER BY totalCost DESC
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const serviceTrends = `
|
||||||
|
SELECT
|
||||||
|
line_item_usage_start_date as date,
|
||||||
|
SUM(line_item_blended_cost) as dailyCost,
|
||||||
|
COUNT(DISTINCT line_item_usage_account_id) as accountCount
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE line_item_product_code = '%serviceCode%'
|
||||||
|
AND line_item_usage_start_date >= date_add('day', -%days%, current_date)
|
||||||
|
AND line_item_blended_cost > 0
|
||||||
|
GROUP BY line_item_usage_start_date
|
||||||
|
ORDER BY date DESC
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Account drill-down queries
|
||||||
|
export const accountServiceBreakdown = `
|
||||||
|
SELECT
|
||||||
|
line_item_product_code as productCode,
|
||||||
|
SUM(line_item_blended_cost) as totalCost,
|
||||||
|
COUNT(DISTINCT line_item_resource_id) as resourceCount,
|
||||||
|
COUNT(DISTINCT line_item_usage_start_date) as daysActive
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE line_item_usage_account_id = '%accountId%'
|
||||||
|
AND line_item_usage_start_date >= date_add('day', -%days%, current_date)
|
||||||
|
AND line_item_blended_cost > 0
|
||||||
|
GROUP BY line_item_product_code
|
||||||
|
ORDER BY totalCost DESC
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const accountTrends = `
|
||||||
|
SELECT
|
||||||
|
line_item_usage_start_date as date,
|
||||||
|
SUM(line_item_blended_cost) as dailyCost,
|
||||||
|
COUNT(DISTINCT line_item_product_code) as serviceCount
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE line_item_usage_account_id = '%accountId%'
|
||||||
|
AND line_item_usage_start_date >= date_add('day', -%days%, current_date)
|
||||||
|
AND line_item_blended_cost > 0
|
||||||
|
GROUP BY line_item_usage_start_date
|
||||||
|
ORDER BY date DESC
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Flexible date range queries
|
||||||
|
export const trendsWithDateRange = (startDate, endDate) => `
|
||||||
|
SELECT
|
||||||
|
line_item_usage_start_date as date,
|
||||||
|
SUM(line_item_blended_cost) as blendedCost,
|
||||||
|
SUM(line_item_unblended_cost) as unblendedCost,
|
||||||
|
COUNT(DISTINCT line_item_product_code) as serviceCount
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE line_item_usage_start_date >= date('${startDate}')
|
||||||
|
AND line_item_usage_start_date <= date('${endDate}')
|
||||||
|
GROUP BY line_item_usage_start_date
|
||||||
|
ORDER BY date DESC
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const servicesWithDateRange = (startDate, endDate) => `
|
||||||
|
SELECT
|
||||||
|
line_item_product_code as productCode,
|
||||||
|
SUM(line_item_blended_cost) as totalCost,
|
||||||
|
COUNT(DISTINCT line_item_usage_account_id) as accountCount,
|
||||||
|
COUNT(DISTINCT line_item_resource_id) as resourceCount
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE line_item_usage_start_date >= date('${startDate}')
|
||||||
|
AND line_item_usage_start_date <= date('${endDate}')
|
||||||
|
GROUP BY line_item_product_code
|
||||||
|
ORDER BY totalCost DESC
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const accountsWithDateRange = (startDate, endDate) => `
|
||||||
|
SELECT
|
||||||
|
line_item_usage_account_id as accountId,
|
||||||
|
SUM(line_item_blended_cost) as totalCost,
|
||||||
|
COUNT(DISTINCT line_item_product_code) as serviceCount,
|
||||||
|
COUNT(DISTINCT line_item_resource_id) as resourceCount
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE line_item_usage_start_date >= date('${startDate}')
|
||||||
|
AND line_item_usage_start_date <= date('${endDate}')
|
||||||
|
GROUP BY line_item_usage_account_id
|
||||||
|
ORDER BY totalCost DESC
|
||||||
|
`;
|
||||||
@ -186,8 +186,13 @@ WHERE LOWER(line_item_product_code) = LOWER('%productCode%')
|
|||||||
|
|
||||||
export const invoices = `select DISTINCT
|
export const invoices = `select DISTINCT
|
||||||
bill_invoice_id as invoiceId,
|
bill_invoice_id as invoiceId,
|
||||||
year, month
|
year, month,
|
||||||
FROM ${process.env.ATHENA_CU_TABLE}`;
|
SUM(line_item_unblended_cost) AS totalUnblendedCost,
|
||||||
|
SUM(line_item_blended_cost) AS totalBlendedCost
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE bill_invoice_id IS NOT NULL
|
||||||
|
GROUP BY bill_invoice_id, year, month
|
||||||
|
ORDER BY year DESC, month DESC;`
|
||||||
|
|
||||||
export const invoiceById = `select DISTINCT
|
export const invoiceById = `select DISTINCT
|
||||||
bill_invoice_id as invoiceId,
|
bill_invoice_id as invoiceId,
|
||||||
@ -217,7 +222,8 @@ FROM ${process.env.ATHENA_CU_TABLE}
|
|||||||
WHERE bill_invoice_id = '%invoiceId%'
|
WHERE bill_invoice_id = '%invoiceId%'
|
||||||
AND LOWER(line_item_product_code) = LOWER('%productCode%');`;
|
AND LOWER(line_item_product_code) = LOWER('%productCode%');`;
|
||||||
|
|
||||||
export const invoiceByProductCodeUsage = `select DISTINCT
|
export const invoiceByProductCodeUsage = `
|
||||||
|
SELECT DISTINCT
|
||||||
bill_invoice_id as invoiceId,
|
bill_invoice_id as invoiceId,
|
||||||
year, month,
|
year, month,
|
||||||
line_item_product_code as productCode,
|
line_item_product_code as productCode,
|
||||||
@ -234,10 +240,17 @@ export const invoiceByProductCodeUsage = `select DISTINCT
|
|||||||
pricing_rate_code AS pricingRateCode,
|
pricing_rate_code AS pricingRateCode,
|
||||||
pricing_currency AS pricingCurrency,
|
pricing_currency AS pricingCurrency,
|
||||||
line_item_usage_start_date AS startDate,
|
line_item_usage_start_date AS startDate,
|
||||||
line_item_usage_end_date AS endDate
|
line_item_usage_end_date AS endDate,
|
||||||
FROM ${process.env.ATHENA_CU_TABLE}
|
CASE
|
||||||
WHERE bill_invoice_id = '%invoiceId%'
|
WHEN line_item_usage_type LIKE '%BoxUsage:%'
|
||||||
AND LOWER(line_item_product_code) = LOWER('%productCode%');`;
|
THEN SUBSTRING(line_item_usage_type, POSITION('BoxUsage:' IN line_item_usage_type) + 9)
|
||||||
|
ELSE NULL
|
||||||
|
END AS instanceType
|
||||||
|
FROM ${process.env.ATHENA_CU_TABLE}
|
||||||
|
WHERE bill_invoice_id = '%invoiceId%'
|
||||||
|
AND LOWER(line_item_product_code) = LOWER('%productCode%')
|
||||||
|
AND line_item_usage_type LIKE '%BoxUsage%'
|
||||||
|
`;
|
||||||
|
|
||||||
export const invoiceByIdAccounts = `select DISTINCT
|
export const invoiceByIdAccounts = `select DISTINCT
|
||||||
bill_invoice_id as invoiceId,
|
bill_invoice_id as invoiceId,
|
||||||
161
server.js
161
server.js
@ -1,13 +1,26 @@
|
|||||||
import Fastify from "fastify";
|
import Fastify from "fastify";
|
||||||
|
import cors from "@fastify/cors";
|
||||||
import sequelizePlugin from "./plugins/sequelize.js";
|
import sequelizePlugin from "./plugins/sequelize.js";
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
|
import cors from "@fastify/cors";
|
||||||
import { executeQueryAsync, retrieveResultsAsync } from "./services/athena.js";
|
import { executeQueryAsync, retrieveResultsAsync } from "./services/athena.js";
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
import * as queries from "./queries.js";
|
import * as dashboard from "./queries/dashboard.js";
|
||||||
|
import * as queries from "./queries/queries.js";
|
||||||
|
import * as dashboardQueries from "./queries/dashboard.js";
|
||||||
|
|
||||||
const server = Fastify({ logger: true });
|
const server = Fastify({ logger: true });
|
||||||
|
await server.register(cors, {
|
||||||
|
origin: "*",
|
||||||
|
});
|
||||||
server.register(sequelizePlugin);
|
server.register(sequelizePlugin);
|
||||||
|
|
||||||
|
await server.register(cors, {
|
||||||
|
origin: "*",
|
||||||
|
});
|
||||||
|
// await server.register(cors, {
|
||||||
|
// origin: ["http://localhost:3000"],
|
||||||
|
// });
|
||||||
server.get("/", async (request, reply) => {
|
server.get("/", async (request, reply) => {
|
||||||
const [results, metadata] = await server.sequelize.query('SELECT 1 + 2 AS result');
|
const [results, metadata] = await server.sequelize.query('SELECT 1 + 2 AS result');
|
||||||
console.log(results);
|
console.log(results);
|
||||||
@ -220,9 +233,155 @@ server.get("/invoices/:invoiceId/accounts/:accountId/products/:productCode/usage
|
|||||||
return results;
|
return results;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.get("/accounts/:accountId/regions/:regionCode/products/:productCode/resources/:resourceId/usage", async (request, reply) => {
|
||||||
|
let regionCode = request.params.regionCode;
|
||||||
|
if (!regionCode || regionCode === 'global') {
|
||||||
|
regionCode = 'global';
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = dashboard.productResourceUsageQuery
|
||||||
|
.replace('%accountId%', request.params.accountId)
|
||||||
|
.replace('%regionCode%', regionCode)
|
||||||
|
.replace('%productCode%', request.params.productCode)
|
||||||
|
.replace('%resourceId%', request.params.resourceId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const queryExecutionId = await executeQueryAsync(query);
|
||||||
|
const results = await retrieveResultsAsync(queryExecutionId);
|
||||||
|
return results ?? [];
|
||||||
|
} catch (err) {
|
||||||
|
request.log.error(err);
|
||||||
|
return reply.status(500).send({
|
||||||
|
error: 'Failed to fetch resource usage',
|
||||||
|
details: err.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get("/products/usage", async (request, reply) => {
|
||||||
|
const query = dashboard.allProductUsageQuery;
|
||||||
|
const queryExecutionId = await executeQueryAsync(query);
|
||||||
|
const results = await retrieveResultsAsync(queryExecutionId);
|
||||||
|
return results;
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get("/accounts/cost-usage-summary", async (request, reply) => {
|
||||||
|
const query = dashboard.accountCostUsageSummaryQuery;
|
||||||
|
const queryExecutionId = await executeQueryAsync(query);
|
||||||
|
const results = await retrieveResultsAsync(queryExecutionId);
|
||||||
|
return results;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
server.get("/dashboard/summary", async (request, reply) => {
|
||||||
|
const [currentQueryId, previousQueryId] = await Promise.all([
|
||||||
|
executeQueryAsync(dashboardQueries.currentMonthSummary),
|
||||||
|
executeQueryAsync(dashboardQueries.previousMonthSummary)
|
||||||
|
]);
|
||||||
|
const [currentResults, previousResults] = await Promise.all([
|
||||||
|
retrieveResultsAsync(currentQueryId),
|
||||||
|
retrieveResultsAsync(previousQueryId)
|
||||||
|
]);
|
||||||
|
return {
|
||||||
|
current: currentResults[0] || {},
|
||||||
|
previous: previousResults[0] || {}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get("/dashboard/services", async (request, reply) => {
|
||||||
|
const queryExecutionId = await executeQueryAsync(dashboardQueries.serviceBreakdown);
|
||||||
|
const results = await retrieveResultsAsync(queryExecutionId);
|
||||||
|
return results;
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get("/dashboard/trends", async (request, reply) => {
|
||||||
|
const queryExecutionId = await executeQueryAsync(dashboardQueries.dailyTrends);
|
||||||
|
const results = await retrieveResultsAsync(queryExecutionId);
|
||||||
|
return results;
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get("/dashboard/accounts", async (request, reply) => {
|
||||||
|
const queryExecutionId = await executeQueryAsync(dashboardQueries.topAccounts);
|
||||||
|
const results = await retrieveResultsAsync(queryExecutionId);
|
||||||
|
return results;
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get("/dashboard/today", async (request, reply) => {
|
||||||
|
const queryExecutionId = await executeQueryAsync(dashboardQueries.todaySpending);
|
||||||
|
const results = await retrieveResultsAsync(queryExecutionId);
|
||||||
|
return results[0] || {};
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get("/dashboard/weekly", async (request, reply) => {
|
||||||
|
const queryExecutionId = await executeQueryAsync(dashboardQueries.weeklyComparison);
|
||||||
|
const results = await retrieveResultsAsync(queryExecutionId);
|
||||||
|
return results;
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get("/dashboard/services/:serviceCode/accounts", async (request, reply) => {
|
||||||
|
const { days = 30 } = request.query;
|
||||||
|
const query = dashboardQueries.serviceAccountBreakdown
|
||||||
|
.replace('%serviceCode%', request.params.serviceCode)
|
||||||
|
.replace('%days%', days);
|
||||||
|
const queryExecutionId = await executeQueryAsync(query);
|
||||||
|
const results = await retrieveResultsAsync(queryExecutionId);
|
||||||
|
return {
|
||||||
|
serviceCode: request.params.serviceCode,
|
||||||
|
accounts: results,
|
||||||
|
totalCost: results.reduce((sum, account) => sum + parseFloat(account.totalCost || 0), 0).toFixed(2)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get("/dashboard/services/:serviceCode/trends", async (request, reply) => {
|
||||||
|
const { days = 30 } = request.query;
|
||||||
|
const query = dashboardQueries.serviceTrends
|
||||||
|
.replace('%serviceCode%', request.params.serviceCode)
|
||||||
|
.replace('%days%', days);
|
||||||
|
const queryExecutionId = await executeQueryAsync(query);
|
||||||
|
const results = await retrieveResultsAsync(queryExecutionId);
|
||||||
|
return {
|
||||||
|
serviceCode: request.params.serviceCode,
|
||||||
|
trends: results,
|
||||||
|
totalCost: results.reduce((sum, day) => sum + parseFloat(day.dailyCost || 0), 0).toFixed(2)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Account drill-down routes
|
||||||
|
server.get("/dashboard/accounts/:accountId/services", async (request, reply) => {
|
||||||
|
const { days = 30 } = request.query;
|
||||||
|
const query = dashboardQueries.accountServiceBreakdown
|
||||||
|
.replace('%accountId%', request.params.accountId)
|
||||||
|
.replace('%days%', days);
|
||||||
|
const queryExecutionId = await executeQueryAsync(query);
|
||||||
|
const results = await retrieveResultsAsync(queryExecutionId);
|
||||||
|
return {
|
||||||
|
accountId: request.params.accountId,
|
||||||
|
services: results,
|
||||||
|
totalCost: results.reduce((sum, service) => sum + parseFloat(service.totalCost || 0), 0).toFixed(2)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get("/dashboard/accounts/:accountId/trends", async (request, reply) => {
|
||||||
|
const { days = 30 } = request.query;
|
||||||
|
const query = dashboardQueries.accountTrends
|
||||||
|
.replace('%accountId%', request.params.accountId)
|
||||||
|
.replace('%days%', days);
|
||||||
|
const queryExecutionId = await executeQueryAsync(query);
|
||||||
|
const results = await retrieveResultsAsync(queryExecutionId);
|
||||||
|
return {
|
||||||
|
accountId: request.params.accountId,
|
||||||
|
trends: results,
|
||||||
|
totalCost: results.reduce((sum, day) => sum + parseFloat(day.dailyCost || 0), 0).toFixed(2)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await server.listen({ port: 3000 })
|
await server.listen({ port: 3000 })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
server.log.error(err);
|
server.log.error(err);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user