From 86c671ccd89d30a760d34a998be87e3a35634e53 Mon Sep 17 00:00:00 2001 From: Andrew Trieu Date: Thu, 21 Nov 2024 11:21:21 +0200 Subject: [PATCH 1/7] feat: Add new API handlers for user, project, and task management; update package dependencies --- tasker-server/package-lock.json | 589 ++++++++++++++++++ tasker-server/package.json | 2 + tasker-server/serverless.yml | 164 +++++ tasker-server/src/handlers/createProject.ts | 40 ++ tasker-server/src/handlers/createTask.ts | 59 ++ tasker-server/src/handlers/createUser.ts | 43 ++ tasker-server/src/handlers/getProjects.ts | 32 + tasker-server/src/handlers/getTasks.ts | 65 ++ tasker-server/src/handlers/getTeams.ts | 52 ++ tasker-server/src/handlers/getUser.ts | 34 + tasker-server/src/handlers/getUserTasks.ts | 32 + tasker-server/src/handlers/getUsers.ts | 32 + .../src/handlers/updateTaskStatus.ts | 42 ++ tasker-server/src/lib/util.ts | 95 +++ tasker-server/terraform/cognito.tf | 7 + 15 files changed, 1288 insertions(+) create mode 100644 tasker-server/serverless.yml create mode 100644 tasker-server/src/handlers/createProject.ts create mode 100644 tasker-server/src/handlers/createTask.ts create mode 100644 tasker-server/src/handlers/createUser.ts create mode 100644 tasker-server/src/handlers/getProjects.ts create mode 100644 tasker-server/src/handlers/getTasks.ts create mode 100644 tasker-server/src/handlers/getTeams.ts create mode 100644 tasker-server/src/handlers/getUser.ts create mode 100644 tasker-server/src/handlers/getUserTasks.ts create mode 100644 tasker-server/src/handlers/getUsers.ts create mode 100644 tasker-server/src/handlers/updateTaskStatus.ts create mode 100644 tasker-server/src/lib/util.ts diff --git a/tasker-server/package-lock.json b/tasker-server/package-lock.json index a278059..654e74b 100644 --- a/tasker-server/package-lock.json +++ b/tasker-server/package-lock.json @@ -9,12 +9,14 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@types/uuid": "^10.0.0", "aws-sdk": "^2.1692.0" }, "devDependencies": { "@types/node": "^22.9.1", "eslint": "^9.15.0", "prettier": "^3.3.3", + "serverless-prune-plugin": "^2.1.0", "typescript": "^5.6.3" } }, @@ -194,6 +196,35 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "peer": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -215,6 +246,11 @@ "undici-types": "~6.19.8" } }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==" + }, "node_modules/acorn": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", @@ -252,6 +288,19 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -273,6 +322,13 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "peer": true + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -308,6 +364,28 @@ "node": ">= 10.0.0" } }, + "node_modules/axios": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "dev": true, + "peer": true, + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios-proxy-builder": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/axios-proxy-builder/-/axios-proxy-builder-0.1.2.tgz", + "integrity": "sha512-6uBVsBZzkB3tCC8iyx59mCjQckhB8+GQrI9Cop8eC7ybIsvs/KtnNgEBfRMSEa7GqK2VBGUzgjNYMdPIfotyPA==", + "dev": true, + "peer": true, + "dependencies": { + "tunnel": "^0.0.6" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -333,6 +411,12 @@ } ] }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -414,6 +498,19 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "peer": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -473,6 +570,30 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "peer": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "peer": true + }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -723,6 +844,27 @@ "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "peer": true, + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -731,6 +873,38 @@ "is-callable": "^1.1.3" } }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "peer": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dev": true, + "peer": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -757,6 +931,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "peer": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -769,6 +964,32 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -938,6 +1159,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-generator-function": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", @@ -989,6 +1220,22 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "peer": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jmespath": { "version": "0.16.0", "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", @@ -1070,6 +1317,36 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "peer": true + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "peer": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1082,6 +1359,16 @@ "node": "*" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -1141,6 +1428,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "peer": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -1171,6 +1465,23 @@ "node": ">=8" } }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "peer": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", @@ -1203,6 +1514,13 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true, + "peer": true + }, "node_modules/punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", @@ -1226,11 +1544,60 @@ "node": ">=4" } }, + "node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "dev": true, + "peer": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/sax": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" }, + "node_modules/serverless": { + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/serverless/-/serverless-4.4.11.tgz", + "integrity": "sha512-8FC58j1pfLMBlkdKrHyiFDO0FDUXQdVtHs2K+2XHDCd+gXX0J7kSxS49s2oYmAxknfjs0wlrhrzGe9DVlxpb+A==", + "dev": true, + "hasInstallScript": true, + "peer": true, + "dependencies": { + "axios": "^1.7.4", + "axios-proxy-builder": "^0.1.2", + "rimraf": "^5.0.5", + "xml2js": "0.6.2" + }, + "bin": { + "serverless": "run.js", + "sls": "run.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/serverless-prune-plugin": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/serverless-prune-plugin/-/serverless-prune-plugin-2.1.0.tgz", + "integrity": "sha512-++22inpEFECgfw+DR2cRn8huxzcsQVgSii4Rjp5q6cPxKo2eKmFc0dfMaJ81DwQoHEnVhfVipIlGdodkauOm1g==", + "dev": true, + "dependencies": { + "bluebird": "^3.7.2" + }, + "peerDependencies": { + "serverless": "1.x || 2.x || 3.x || 4.x" + } + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -1268,6 +1635,123 @@ "node": ">=8" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "peer": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "peer": true + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -1292,6 +1776,16 @@ "node": ">=8" } }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -1412,6 +1906,101 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "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, + "peer": 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/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "peer": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/xml2js": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", diff --git a/tasker-server/package.json b/tasker-server/package.json index 1eabd7b..3ea5bf8 100644 --- a/tasker-server/package.json +++ b/tasker-server/package.json @@ -11,12 +11,14 @@ "license": "ISC", "description": "", "dependencies": { + "@types/uuid": "^10.0.0", "aws-sdk": "^2.1692.0" }, "devDependencies": { "@types/node": "^22.9.1", "eslint": "^9.15.0", "prettier": "^3.3.3", + "serverless-prune-plugin": "^2.1.0", "typescript": "^5.6.3" } } diff --git a/tasker-server/serverless.yml b/tasker-server/serverless.yml new file mode 100644 index 0000000..8fe9e89 --- /dev/null +++ b/tasker-server/serverless.yml @@ -0,0 +1,164 @@ +service: tasker-server + +plugins: + - serverless-prune-plugin + +provider: + stackName: ${self:service} + name: aws + region: ${opt:region, 'eu-north-1'} + runtime: nodejs20.x + environment: + SLS_REGION: ${self:provider.region} + TASKER_TASK_TABLE_NAME: ${ssm:/tasker/dynamodb/project-table-name} + TASKER_PROJECT_TABLE_NAME: ${ssm:/tasker/dynamodb/task-table-name} + TASKER_USER_TABLE_NAME: ${ssm:/tasker/dynamodb/user-table-name} + TASKER_TASK_EXTRA_TABLE_NAME: ${ssm:/tasker/dynamodb/task-extra-table-name} + TASKER_TEAM_TABLE_NAME: ${ssm:/tasker/dynamodb/team-table-name} + iam: + role: + statements: + - Effect: Allow + Action: + - dynamodb:Query + - dynamodb:Scan + - dynamodb:GetItem + - dynamodb:PutItem + - dynamodb:UpdateItem + Resource: + [ + "arn:aws:dynamodb:${self:provider.region}:*:table/tasker-*", + "arn:aws:dynamodb:${self:provider.region}:*:table/tasker-*/*", + ] + +functions: + # POST /users + createUser: + handler: src/handlers/createUser.handler + memorySize: 1024 + timeout: 60 + events: + - http: + path: users + method: post + cors: true + authorizer: + type: COGNITO_USER_POOLS + arn: ${ssm:/tasker/cognito/user-pool-arn} + # POST /projects + createProject: + handler: src/handlers/createProject.handler + memorySize: 1024 + timeout: 60 + events: + - http: + path: projects + method: post + cors: true + authorizer: + type: COGNITO_USER_POOLS + arn: ${ssm:/tasker/cognito/user-pool-arn} + # POST /tasks + createTask: + handler: src/handlers/createTask.handler + memorySize: 1024 + timeout: 60 + events: + - http: + path: tasks + method: post + cors: true + authorizer: + type: COGNITO_USER_POOLS + arn: ${ssm:/tasker/cognito/user-pool-arn} + # GET /projects + getProjects: + handler: src/handlers/getProjects.handler + memorySize: 1024 + timeout: 60 + events: + - http: + path: projects + method: get + cors: true + authorizer: + type: COGNITO_USER_POOLS + arn: ${ssm:/tasker/cognito/user-pool-arn} + # GET /tasks?projectId= + getTasks: + handler: src/handlers/getTasks.handler + memorySize: 1024 + timeout: 60 + events: + - http: + path: tasks + method: get + cors: true + authorizer: + type: COGNITO_USER_POOLS + arn: ${ssm:/tasker/cognito/user-pool-arn} + # GET /teams + getTeams: + handler: src/handlers/getTeams.handler + memorySize: 1024 + timeout: 60 + events: + - http: + path: teams + method: get + cors: true + authorizer: + type: COGNITO_USER_POOLS + arn: ${ssm:/tasker/cognito/user-pool-arn} + # GET /users + getUsers: + handler: src/handlers/getUsers.handler + memorySize: 1024 + timeout: 60 + events: + - http: + path: users + method: get + cors: true + authorizer: + type: COGNITO_USER_POOLS + arn: ${ssm:/tasker/cognito/user-pool-arn} + # GET /users/{cognitoId} + getUser: + handler: src/handlers/getUser.handler + memorySize: 1024 + timeout: 60 + events: + - http: + path: users/{cognitoId} + method: get + cors: true + authorizer: + type: COGNITO_USER_POOLS + arn: ${ssm:/tasker/cognito/user-pool-arn} + # GET /tasks/user/${userId} + getTasksByUser: + handler: src/handlers/getTasksByUser.handler + memorySize: 1024 + timeout: 60 + events: + - http: + path: tasks/user/{userId} + method: get + cors: true + authorizer: + type: COGNITO_USER_POOLS + arn: ${ssm:/tasker/cognito/user-pool-arn} + # PATCH /tasks/{taskId}/status + updateTaskStatus: + handler: src/handlers/updateTaskStatus.handler + memorySize: 1024 + timeout: 60 + events: + - http: + path: tasks/{taskId}/status + method: patch + cors: true + authorizer: + type: COGNITO_USER_POOLS + arn: ${ssm:/tasker/cognito/user-pool-arn} diff --git a/tasker-server/src/handlers/createProject.ts b/tasker-server/src/handlers/createProject.ts new file mode 100644 index 0000000..751205b --- /dev/null +++ b/tasker-server/src/handlers/createProject.ts @@ -0,0 +1,40 @@ +import { DynamoDB } from "aws-sdk"; +import { v4 as uuidv4 } from "uuid"; + +const SLS_REGION = process.env.SLS_REGION; +const TASKER_PROJECT_TABLE_NAME = process.env.TASKER_PROJECT_TABLE_NAME || ""; + +const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); + +export const handler = async (event: any): Promise => { + const { name, description, startDate, endDate } = event.body; + try { + const newProject = { + type: "projects", + projectId: `project#${uuidv4()}`, + name, + description, + startDate, + endDate, + }; + + const params = { + TableName: TASKER_PROJECT_TABLE_NAME, + Item: newProject, + }; + + await docClient.put(params).promise(); + + return { + status: 201, + body: JSON.stringify(newProject), + }; + } catch (error: any) { + return { + status: 500, + body: JSON.stringify({ + message: `Error creating project: ${error.message}`, + }), + }; + } +}; diff --git a/tasker-server/src/handlers/createTask.ts b/tasker-server/src/handlers/createTask.ts new file mode 100644 index 0000000..c6ecea6 --- /dev/null +++ b/tasker-server/src/handlers/createTask.ts @@ -0,0 +1,59 @@ +import { DynamoDB } from "aws-sdk"; +import { v4 as uuidv4 } from "uuid"; + +const SLS_REGION = process.env.SLS_REGION; +const TASKER_TASK_TABLE_NAME = process.env.TASKER_TASK_TABLE_NAME || ""; + +const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); + +export const handler = async (event: any): Promise => { + const { + title, + description, + status, + priority, + tags, + startDate, + dueDate, + points, + projectId, + authorUserId, + assignedUserId, + } = event.body; + try { + const newTask = { + type: "tasks", + taskId: `task#${uuidv4()}`, + title, + description, + status, + priority, + tags, + startDate, + dueDate, + points, + projectId, + authorUserId, + assignedUserId, + }; + + const params = { + TableName: TASKER_TASK_TABLE_NAME, + Item: newTask, + }; + + await docClient.put(params).promise(); + + return { + status: 201, + body: JSON.stringify(newTask), + }; + } catch (error: any) { + return { + status: 500, + body: JSON.stringify({ + message: `Error creating task: ${error.message}`, + }), + }; + } +}; diff --git a/tasker-server/src/handlers/createUser.ts b/tasker-server/src/handlers/createUser.ts new file mode 100644 index 0000000..96df5af --- /dev/null +++ b/tasker-server/src/handlers/createUser.ts @@ -0,0 +1,43 @@ +import { fetchRandomTeamId } from "@/lib/util"; +import { DynamoDB } from "aws-sdk"; +import { v4 as uuidv4 } from "uuid"; + +const SLS_REGION = process.env.SLS_REGION; +const TASKER_USER_TABLE_NAME = process.env.TASKER_USER_TABLE_NAME || ""; + +const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); + +export const handler = async (event: any): Promise => { + const { username, cognitoId, profilePictureUrl = "i0.jpg" } = event.body; + const teamId = fetchRandomTeamId(); + + try { + const newUser = { + type: "users", + cognitoId, + userId: `user#${uuidv4()}`, + username, + profilePictureUrl, + teamId, + }; + + const params = { + TableName: TASKER_USER_TABLE_NAME, + Item: newUser, + }; + + await docClient.put(params).promise(); + + return { + status: 201, + body: JSON.stringify(newUser), + }; + } catch (error: any) { + return { + status: 500, + body: JSON.stringify({ + message: `Error creating user: ${error.message}`, + }), + }; + } +}; diff --git a/tasker-server/src/handlers/getProjects.ts b/tasker-server/src/handlers/getProjects.ts new file mode 100644 index 0000000..daa036e --- /dev/null +++ b/tasker-server/src/handlers/getProjects.ts @@ -0,0 +1,32 @@ +import { DynamoDB } from "aws-sdk"; + +const SLS_REGION = process.env.SLS_REGION; +const TASKER_PROJECT_TABLE_NAME = process.env.TASKER_PROJECT_TABLE_NAME || ""; + +const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); + +export const handler = async (event: any): Promise => { + try { + const params = { + TableName: TASKER_PROJECT_TABLE_NAME, + KeyConditionExpression: "type = :type", + ExpressionAttributeValues: { + ":type": "projects", + }, + }; + + const projects = await docClient.query(params).promise(); + + return { + status: 200, + body: JSON.stringify(projects.Items), + }; + } catch (error: any) { + return { + status: 500, + body: JSON.stringify({ + message: `Error retrieving projects: ${error.message}`, + }), + }; + } +}; diff --git a/tasker-server/src/handlers/getTasks.ts b/tasker-server/src/handlers/getTasks.ts new file mode 100644 index 0000000..534f6d9 --- /dev/null +++ b/tasker-server/src/handlers/getTasks.ts @@ -0,0 +1,65 @@ +import { + fetchAttachments, + fetchComments, + fetchUserWithUserId, +} from "@/lib/util"; +import { DynamoDB } from "aws-sdk"; + +const SLS_REGION = process.env.SLS_REGION; +const TASKER_TASK_TABLE_NAME = process.env.TASKER_TASK_TABLE_NAME || ""; + +const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); + +export const handler = async (event: any): Promise => { + const { projectId } = event.queryStringParameters; + try { + const params = { + TableName: TASKER_TASK_TABLE_NAME, + KeyConditionExpression: "type = :type AND projectId = :projectId", + IndexName: "GSI-project-id", + ExpressionAttributeValues: { + ":type": "tasks", + ":projectId": projectId, + }, + }; + + const result = await docClient.query(params).promise(); + const tasks = result.Items || []; + + const tasksWithDetails = await Promise.all( + tasks.map(async (task: any) => { + const author = task.authorUserId + ? await fetchUserWithUserId(task.authorUserId) + : null; + + const assignee = task.assignedUserId + ? await fetchUserWithUserId(task.assignedUserId) + : null; + + const comments = await fetchComments(task.taskId); + + const attachments = await fetchAttachments(task.taskId); + + return { + ...task, + author, + assignee, + comments, + attachments, + }; + }) + ); + + return { + status: 200, + body: JSON.stringify(tasksWithDetails), + }; + } catch (error: any) { + return { + status: 500, + body: JSON.stringify({ + message: `Error retrieving tasks: ${error.message}`, + }), + }; + } +}; diff --git a/tasker-server/src/handlers/getTeams.ts b/tasker-server/src/handlers/getTeams.ts new file mode 100644 index 0000000..50c1105 --- /dev/null +++ b/tasker-server/src/handlers/getTeams.ts @@ -0,0 +1,52 @@ +import { fetchUserWithUserId } from "@/lib/util"; +import { DynamoDB } from "aws-sdk"; + +const SLS_REGION = process.env.SLS_REGION; +const TASKER_TEAM_TABLE_NAME = process.env.TASKER_TEAM_TABLE_NAME || ""; + +const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); + +export const handler = async (event: any): Promise => { + try { + const params = { + TableName: TASKER_TEAM_TABLE_NAME, + KeyConditionExpression: "type = :type", + ExpressionAttributeValues: { + ":type": "teams", + }, + }; + + const result = await docClient.query(params).promise(); + const teams = result.Items || []; + + const teamsWithUsernames = await Promise.all( + teams.map(async (team: any) => { + const productOwnerUsername = team.productOwnerUserId + ? (await fetchUserWithUserId(team.productOwnerUserId))?.username + : null; + + const projectManagerUsername = team.projectManagerUserId + ? (await fetchUserWithUserId(team.projectManagerUserId))?.username + : null; + + return { + ...team, + productOwnerUsername, + projectManagerUsername, + }; + }) + ); + + return { + status: 200, + body: JSON.stringify(teamsWithUsernames), + }; + } catch (error: any) { + return { + status: 500, + body: JSON.stringify({ + message: `Error retrieving teams: ${error.message}`, + }), + }; + } +}; diff --git a/tasker-server/src/handlers/getUser.ts b/tasker-server/src/handlers/getUser.ts new file mode 100644 index 0000000..6defa64 --- /dev/null +++ b/tasker-server/src/handlers/getUser.ts @@ -0,0 +1,34 @@ +import { DynamoDB } from "aws-sdk"; + +const SLS_REGION = process.env.SLS_REGION; +const TASKER_USER_TABLE_NAME = process.env.TASKER_USER_TABLE_NAME || ""; + +const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); + +export const handler = async (event: any): Promise => { + const { cognitoId } = event.pathParameters; + try { + const params = { + TableName: TASKER_USER_TABLE_NAME, + KeyConditionExpression: "type = :type AND cognitoId = :cognitoId", + ExpressionAttributeValues: { + ":type": "users", + ":cognitoId": cognitoId, + }, + }; + + const user = await docClient.query(params).promise(); + + return { + status: 200, + body: JSON.stringify(user.Items?.[0] || {}), + }; + } catch (error: any) { + return { + status: 500, + body: JSON.stringify({ + message: `Error retrieving user: ${error.message}`, + }), + }; + } +}; diff --git a/tasker-server/src/handlers/getUserTasks.ts b/tasker-server/src/handlers/getUserTasks.ts new file mode 100644 index 0000000..d6c2d07 --- /dev/null +++ b/tasker-server/src/handlers/getUserTasks.ts @@ -0,0 +1,32 @@ +import { queryTasks } from "@/lib/util"; + +export const handler = async (event: any): Promise => { + const { userId } = event.pathParameters; + try { + const authorTasks = await queryTasks( + userId, + "GSI-author-user-id", + "authorUserId" + ); + + const assigneeTasks = await queryTasks( + userId, + "GSI-assigned-user-id", + "assignedUserId" + ); + + const userTasks = [...authorTasks, ...assigneeTasks]; + + return { + status: 200, + body: JSON.stringify(userTasks), + }; + } catch (error: any) { + return { + status: 500, + body: JSON.stringify({ + message: `Error retrieving tasks for user: ${error.message}`, + }), + }; + } +}; diff --git a/tasker-server/src/handlers/getUsers.ts b/tasker-server/src/handlers/getUsers.ts new file mode 100644 index 0000000..83e6d0b --- /dev/null +++ b/tasker-server/src/handlers/getUsers.ts @@ -0,0 +1,32 @@ +import { DynamoDB } from "aws-sdk"; + +const SLS_REGION = process.env.SLS_REGION; +const TASKER_USER_TABLE_NAME = process.env.TASKER_USER_TABLE_NAME || ""; + +const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); + +export const handler = async (event: any): Promise => { + try { + const params = { + TableName: TASKER_USER_TABLE_NAME, + KeyConditionExpression: "type = :type", + ExpressionAttributeValues: { + ":type": "users", + }, + }; + + const users = await docClient.query(params).promise(); + + return { + status: 200, + body: JSON.stringify(users.Items), + }; + } catch (error: any) { + return { + status: 500, + body: JSON.stringify({ + message: `Error retrieving users: ${error.message}`, + }), + }; + } +}; diff --git a/tasker-server/src/handlers/updateTaskStatus.ts b/tasker-server/src/handlers/updateTaskStatus.ts new file mode 100644 index 0000000..9c9b4d4 --- /dev/null +++ b/tasker-server/src/handlers/updateTaskStatus.ts @@ -0,0 +1,42 @@ +import { DynamoDB } from "aws-sdk"; + +const SLS_REGION = process.env.SLS_REGION; +const TASKER_TASK_TABLE_NAME = process.env.TASKER_TASK_TABLE_NAME || ""; + +const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); + +export const handler = async (event: any): Promise => { + const { taskId } = event.pathParameters; + const { status } = event.body; + try { + const params = { + TableName: TASKER_TASK_TABLE_NAME, + Key: { + type: "tasks", + taskId, + }, + UpdateExpression: "set #status = :status", + ExpressionAttributeNames: { + "#status": "status", + }, + ExpressionAttributeValues: { + ":status": status, + }, + ReturnValues: "ALL_NEW", + }; + + const updatedTask = await docClient.update(params).promise(); + + return { + status: 200, + body: JSON.stringify(updatedTask.Attributes), + }; + } catch (error: any) { + return { + status: 500, + body: JSON.stringify({ + message: `Error updating task: ${error.message}`, + }), + }; + } +}; diff --git a/tasker-server/src/lib/util.ts b/tasker-server/src/lib/util.ts new file mode 100644 index 0000000..15727f1 --- /dev/null +++ b/tasker-server/src/lib/util.ts @@ -0,0 +1,95 @@ +import { DynamoDB } from "aws-sdk"; + +const SLS_REGION = process.env.SLS_REGION; +const TASKER_PROJECT_TABLE_NAME = process.env.TASKER_PROJECT_TABLE_NAME || ""; +const TASKER_USER_TABLE_NAME = process.env.TASKER_USER_TABLE_NAME || ""; +const TASKER_TASK_TABLE_NAME = process.env.TASKER_TASK_TABLE_NAME || ""; +const TASKER_TASK_EXTRA_TABLE_NAME = + process.env.TASKER_TASK_EXTRA_TABLE_NAME || ""; + +const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); + +export const fetchRandomTeamId = async () => { + const params = { + TableName: TASKER_PROJECT_TABLE_NAME, + KeyConditionExpression: "type = :type", + ExpressionAttributeValues: { + ":type": "teams", + }, + }; + + const projects = await docClient.query(params).promise(); + if (!projects.Items) { + return null; + } + const randomProject = + projects.Items[Math.floor(Math.random() * projects.Items.length)]; + return randomProject.id; +}; + +export const fetchUserWithUserId = async (userId: string): Promise => { + const params: DynamoDB.DocumentClient.QueryInput = { + TableName: TASKER_USER_TABLE_NAME, + KeyConditionExpression: "type = :type AND userId = :userId", + IndexName: "GSI-user-id", + ExpressionAttributeValues: { + ":type": "users", + ":userId": userId, + }, + }; + + const result = await docClient.query(params).promise(); + return result.Items?.[0]; +}; + +export const fetchComments = async (taskId: string): Promise => { + const params: DynamoDB.DocumentClient.QueryInput = { + TableName: TASKER_TASK_EXTRA_TABLE_NAME, + KeyConditionExpression: "type = :type AND taskId = :taskId", + IndexName: "GSI-task-id", + ExpressionAttributeValues: { + ":type": "comments", + ":taskId": taskId, + }, + }; + + const result = await docClient.query(params).promise(); + return result.Items; +}; + +export const fetchAttachments = async (taskId: string): Promise => { + const params: DynamoDB.DocumentClient.QueryInput = { + TableName: TASKER_TASK_EXTRA_TABLE_NAME, + KeyConditionExpression: "type = :type AND taskId = :taskId", + IndexName: "GSI-task-id", + ExpressionAttributeValues: { + ":type": "attachments", + ":taskId": taskId, + }, + }; + + const result = await docClient.query(params).promise(); + return result.Items; +}; + +export const queryTasks = async ( + userId: string, + indexName: string, + key: string +): Promise => { + const params = { + TableName: TASKER_TASK_TABLE_NAME, + KeyConditionExpression: "type = :type AND #key = :userId", + IndexName: indexName, + ExpressionAttributeValues: { + ":type": "tasks", + ":userId": userId, + }, + ExpressionAttributeNames: { + "#key": key, + }, + }; + + const result = await docClient.query(params).promise(); + return result.Items ?? []; +}; diff --git a/tasker-server/terraform/cognito.tf b/tasker-server/terraform/cognito.tf index 4471b55..dee2443 100644 --- a/tasker-server/terraform/cognito.tf +++ b/tasker-server/terraform/cognito.tf @@ -76,6 +76,13 @@ resource "aws_ssm_parameter" "user_pool_id" { value = aws_cognito_user_pool.tasker_cognito_user_pool.id } +resource "aws_ssm_parameter" "user_pool_arn" { + name = "/tasker/cognito/user-pool-arn" + description = "Tasker Cognito User Pool ARN" + type = "String" + value = aws_cognito_user_pool.tasker_cognito_user_pool.arn +} + resource "aws_ssm_parameter" "client_id" { name = "/tasker/cognito/client-id" description = "Tasker Cognito Client ID" -- 2.49.1 From f57d96345377f3577080451809bb161847bac8ec Mon Sep 17 00:00:00 2001 From: Andrew Trieu Date: Sat, 23 Nov 2024 06:28:02 +0200 Subject: [PATCH 2/7] feat: Update .gitignore, add Lambda layer configuration, and refactor DynamoDB handlers to use AWS SDK v3 --- .gitignore | 10 +- tasker-server/layers/nodejs/package-lock.json | 1340 +++++++++++++++++ tasker-server/layers/nodejs/package.json | 18 + tasker-server/package-lock.json | 1329 +++++++++++++++- tasker-server/package.json | 11 +- tasker-server/serverless.yml | 15 +- tasker-server/src/handlers/createProject.ts | 12 +- tasker-server/src/handlers/createTask.ts | 12 +- tasker-server/src/handlers/createUser.ts | 16 +- tasker-server/src/handlers/getProjects.ts | 14 +- tasker-server/src/handlers/getTasks.ts | 14 +- tasker-server/src/handlers/getTeams.ts | 14 +- tasker-server/src/handlers/getUser.ts | 14 +- tasker-server/src/handlers/getUsers.ts | 14 +- tasker-server/src/handlers/postSignUp.ts | 34 + .../src/handlers/updateTaskStatus.ts | 12 +- tasker-server/src/lib/util.ts | 46 +- tasker-server/terraform/dynamodb.tf | 30 +- tasker-server/terraform/layer.tf | 24 + 19 files changed, 2877 insertions(+), 102 deletions(-) create mode 100644 tasker-server/layers/nodejs/package-lock.json create mode 100644 tasker-server/layers/nodejs/package.json create mode 100644 tasker-server/src/handlers/postSignUp.ts create mode 100644 tasker-server/terraform/layer.tf diff --git a/.gitignore b/.gitignore index 2811946..1854a18 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,13 @@ **/next-env.d.ts # images -**/public/** +tasker-client/public/** # terraform -**/**/.terraform** +**/.terraform** + +# serverless +**/.serverless/** + +# zipped layers +**/layers/**.zip diff --git a/tasker-server/layers/nodejs/package-lock.json b/tasker-server/layers/nodejs/package-lock.json new file mode 100644 index 0000000..3dd5c38 --- /dev/null +++ b/tasker-server/layers/nodejs/package-lock.json @@ -0,0 +1,1340 @@ +{ + "name": "nodejs", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "nodejs", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@aws-sdk/client-dynamodb": "^3.699.0", + "@aws-sdk/lib-dynamodb": "^3.699.0", + "@types/uuid": "^10.0.0", + "uuid": "^11.0.3" + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.699.0.tgz", + "integrity": "sha512-npf2ZPUbFyyeWb0Fmgs/hGdjeecyUyldVU6okwM9DaaeOtlUmXA9e1vtrplgRJs3DLJdDJCGSTrBI+4w0MtgGg==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.699.0", + "@aws-sdk/client-sts": "3.699.0", + "@aws-sdk/core": "3.696.0", + "@aws-sdk/credential-provider-node": "3.699.0", + "@aws-sdk/middleware-endpoint-discovery": "3.696.0", + "@aws-sdk/middleware-host-header": "3.696.0", + "@aws-sdk/middleware-logger": "3.696.0", + "@aws-sdk/middleware-recursion-detection": "3.696.0", + "@aws-sdk/middleware-user-agent": "3.696.0", + "@aws-sdk/region-config-resolver": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@aws-sdk/util-endpoints": "3.696.0", + "@aws-sdk/util-user-agent-browser": "3.696.0", + "@aws-sdk/util-user-agent-node": "3.696.0", + "@smithy/config-resolver": "^3.0.12", + "@smithy/core": "^2.5.3", + "@smithy/fetch-http-handler": "^4.1.1", + "@smithy/hash-node": "^3.0.10", + "@smithy/invalid-dependency": "^3.0.10", + "@smithy/middleware-content-length": "^3.0.12", + "@smithy/middleware-endpoint": "^3.2.3", + "@smithy/middleware-retry": "^3.0.27", + "@smithy/middleware-serde": "^3.0.10", + "@smithy/middleware-stack": "^3.0.10", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/node-http-handler": "^3.3.1", + "@smithy/protocol-http": "^4.1.7", + "@smithy/smithy-client": "^3.4.4", + "@smithy/types": "^3.7.1", + "@smithy/url-parser": "^3.0.10", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.27", + "@smithy/util-defaults-mode-node": "^3.0.27", + "@smithy/util-endpoints": "^2.1.6", + "@smithy/util-middleware": "^3.0.10", + "@smithy/util-retry": "^3.0.10", + "@smithy/util-utf8": "^3.0.0", + "@smithy/util-waiter": "^3.1.9", + "@types/uuid": "^9.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==" + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.696.0.tgz", + "integrity": "sha512-q5TTkd08JS0DOkHfUL853tuArf7NrPeqoS5UOvqJho8ibV9Ak/a/HO4kNvy9Nj3cib/toHYHsQIEtecUPSUUrQ==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.696.0", + "@aws-sdk/middleware-host-header": "3.696.0", + "@aws-sdk/middleware-logger": "3.696.0", + "@aws-sdk/middleware-recursion-detection": "3.696.0", + "@aws-sdk/middleware-user-agent": "3.696.0", + "@aws-sdk/region-config-resolver": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@aws-sdk/util-endpoints": "3.696.0", + "@aws-sdk/util-user-agent-browser": "3.696.0", + "@aws-sdk/util-user-agent-node": "3.696.0", + "@smithy/config-resolver": "^3.0.12", + "@smithy/core": "^2.5.3", + "@smithy/fetch-http-handler": "^4.1.1", + "@smithy/hash-node": "^3.0.10", + "@smithy/invalid-dependency": "^3.0.10", + "@smithy/middleware-content-length": "^3.0.12", + "@smithy/middleware-endpoint": "^3.2.3", + "@smithy/middleware-retry": "^3.0.27", + "@smithy/middleware-serde": "^3.0.10", + "@smithy/middleware-stack": "^3.0.10", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/node-http-handler": "^3.3.1", + "@smithy/protocol-http": "^4.1.7", + "@smithy/smithy-client": "^3.4.4", + "@smithy/types": "^3.7.1", + "@smithy/url-parser": "^3.0.10", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.27", + "@smithy/util-defaults-mode-node": "^3.0.27", + "@smithy/util-endpoints": "^2.1.6", + "@smithy/util-middleware": "^3.0.10", + "@smithy/util-retry": "^3.0.10", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.699.0.tgz", + "integrity": "sha512-u8a1GorY5D1l+4FQAf4XBUC1T10/t7neuwT21r0ymrtMFSK2a9QqVHKMoLkvavAwyhJnARSBM9/UQC797PFOFw==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.696.0", + "@aws-sdk/credential-provider-node": "3.699.0", + "@aws-sdk/middleware-host-header": "3.696.0", + "@aws-sdk/middleware-logger": "3.696.0", + "@aws-sdk/middleware-recursion-detection": "3.696.0", + "@aws-sdk/middleware-user-agent": "3.696.0", + "@aws-sdk/region-config-resolver": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@aws-sdk/util-endpoints": "3.696.0", + "@aws-sdk/util-user-agent-browser": "3.696.0", + "@aws-sdk/util-user-agent-node": "3.696.0", + "@smithy/config-resolver": "^3.0.12", + "@smithy/core": "^2.5.3", + "@smithy/fetch-http-handler": "^4.1.1", + "@smithy/hash-node": "^3.0.10", + "@smithy/invalid-dependency": "^3.0.10", + "@smithy/middleware-content-length": "^3.0.12", + "@smithy/middleware-endpoint": "^3.2.3", + "@smithy/middleware-retry": "^3.0.27", + "@smithy/middleware-serde": "^3.0.10", + "@smithy/middleware-stack": "^3.0.10", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/node-http-handler": "^3.3.1", + "@smithy/protocol-http": "^4.1.7", + "@smithy/smithy-client": "^3.4.4", + "@smithy/types": "^3.7.1", + "@smithy/url-parser": "^3.0.10", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.27", + "@smithy/util-defaults-mode-node": "^3.0.27", + "@smithy/util-endpoints": "^2.1.6", + "@smithy/util-middleware": "^3.0.10", + "@smithy/util-retry": "^3.0.10", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.699.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.699.0.tgz", + "integrity": "sha512-++lsn4x2YXsZPIzFVwv3fSUVM55ZT0WRFmPeNilYIhZClxHLmVAWKH4I55cY9ry60/aTKYjzOXkWwyBKGsGvQg==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.699.0", + "@aws-sdk/core": "3.696.0", + "@aws-sdk/credential-provider-node": "3.699.0", + "@aws-sdk/middleware-host-header": "3.696.0", + "@aws-sdk/middleware-logger": "3.696.0", + "@aws-sdk/middleware-recursion-detection": "3.696.0", + "@aws-sdk/middleware-user-agent": "3.696.0", + "@aws-sdk/region-config-resolver": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@aws-sdk/util-endpoints": "3.696.0", + "@aws-sdk/util-user-agent-browser": "3.696.0", + "@aws-sdk/util-user-agent-node": "3.696.0", + "@smithy/config-resolver": "^3.0.12", + "@smithy/core": "^2.5.3", + "@smithy/fetch-http-handler": "^4.1.1", + "@smithy/hash-node": "^3.0.10", + "@smithy/invalid-dependency": "^3.0.10", + "@smithy/middleware-content-length": "^3.0.12", + "@smithy/middleware-endpoint": "^3.2.3", + "@smithy/middleware-retry": "^3.0.27", + "@smithy/middleware-serde": "^3.0.10", + "@smithy/middleware-stack": "^3.0.10", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/node-http-handler": "^3.3.1", + "@smithy/protocol-http": "^4.1.7", + "@smithy/smithy-client": "^3.4.4", + "@smithy/types": "^3.7.1", + "@smithy/url-parser": "^3.0.10", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.27", + "@smithy/util-defaults-mode-node": "^3.0.27", + "@smithy/util-endpoints": "^2.1.6", + "@smithy/util-middleware": "^3.0.10", + "@smithy/util-retry": "^3.0.10", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.696.0.tgz", + "integrity": "sha512-3c9III1k03DgvRZWg8vhVmfIXPG6hAciN9MzQTzqGngzWAELZF/WONRTRQuDFixVtarQatmLHYVw/atGeA2Byw==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/core": "^2.5.3", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/property-provider": "^3.1.9", + "@smithy/protocol-http": "^4.1.7", + "@smithy/signature-v4": "^4.2.2", + "@smithy/smithy-client": "^3.4.4", + "@smithy/types": "^3.7.1", + "@smithy/util-middleware": "^3.0.10", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.696.0.tgz", + "integrity": "sha512-T9iMFnJL7YTlESLpVFT3fg1Lkb1lD+oiaIC8KMpepb01gDUBIpj9+Y+pA/cgRWW0yRxmkDXNazAE2qQTVFGJzA==", + "dependencies": { + "@aws-sdk/core": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.696.0.tgz", + "integrity": "sha512-GV6EbvPi2eq1+WgY/o2RFA3P7HGmnkIzCNmhwtALFlqMroLYWKE7PSeHw66Uh1dFQeVESn0/+hiUNhu1mB0emA==", + "dependencies": { + "@aws-sdk/core": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@smithy/fetch-http-handler": "^4.1.1", + "@smithy/node-http-handler": "^3.3.1", + "@smithy/property-provider": "^3.1.9", + "@smithy/protocol-http": "^4.1.7", + "@smithy/smithy-client": "^3.4.4", + "@smithy/types": "^3.7.1", + "@smithy/util-stream": "^3.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.699.0.tgz", + "integrity": "sha512-dXmCqjJnKmG37Q+nLjPVu22mNkrGHY8hYoOt3Jo9R2zr5MYV7s/NHsCHr+7E+BZ+tfZYLRPeB1wkpTeHiEcdRw==", + "dependencies": { + "@aws-sdk/core": "3.696.0", + "@aws-sdk/credential-provider-env": "3.696.0", + "@aws-sdk/credential-provider-http": "3.696.0", + "@aws-sdk/credential-provider-process": "3.696.0", + "@aws-sdk/credential-provider-sso": "3.699.0", + "@aws-sdk/credential-provider-web-identity": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@smithy/credential-provider-imds": "^3.2.6", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.699.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.699.0.tgz", + "integrity": "sha512-MmEmNDo1bBtTgRmdNfdQksXu4uXe66s0p1hi1YPrn1h59Q605eq/xiWbGL6/3KdkViH6eGUuABeV2ODld86ylg==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.696.0", + "@aws-sdk/credential-provider-http": "3.696.0", + "@aws-sdk/credential-provider-ini": "3.699.0", + "@aws-sdk/credential-provider-process": "3.696.0", + "@aws-sdk/credential-provider-sso": "3.699.0", + "@aws-sdk/credential-provider-web-identity": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@smithy/credential-provider-imds": "^3.2.6", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.696.0.tgz", + "integrity": "sha512-mL1RcFDe9sfmyU5K1nuFkO8UiJXXxLX4JO1gVaDIOvPqwStpUAwi3A1BoeZhWZZNQsiKI810RnYGo0E0WB/hUA==", + "dependencies": { + "@aws-sdk/core": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.699.0.tgz", + "integrity": "sha512-Ekp2cZG4pl9D8+uKWm4qO1xcm8/MeiI8f+dnlZm8aQzizeC+aXYy9GyoclSf6daK8KfRPiRfM7ZHBBL5dAfdMA==", + "dependencies": { + "@aws-sdk/client-sso": "3.696.0", + "@aws-sdk/core": "3.696.0", + "@aws-sdk/token-providers": "3.699.0", + "@aws-sdk/types": "3.696.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.696.0.tgz", + "integrity": "sha512-XJ/CVlWChM0VCoc259vWguFUjJDn/QwDqHwbx+K9cg3v6yrqXfK5ai+p/6lx0nQpnk4JzPVeYYxWRpaTsGC9rg==", + "dependencies": { + "@aws-sdk/core": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.696.0" + } + }, + "node_modules/@aws-sdk/endpoint-cache": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.693.0.tgz", + "integrity": "sha512-/zK0ZZncBf5FbTfo8rJMcQIXXk4Ibhe5zEMiwFNivVPR2uNC0+oqfwXz7vjxwY0t6BPE3Bs4h9uFEz4xuGCY6w==", + "dependencies": { + "mnemonist": "0.38.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/lib-dynamodb": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.699.0.tgz", + "integrity": "sha512-k28YlOaoZ0p71SZYxOgqSRGjK+RIg8EYEoG7DoFoBeXxXX5R3Zpu07Mjl480y1enYULaLKroeKunUxd50qWNrw==", + "dependencies": { + "@aws-sdk/core": "3.696.0", + "@aws-sdk/util-dynamodb": "3.699.0", + "@smithy/core": "^2.5.3", + "@smithy/smithy-client": "^3.4.4", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.699.0" + } + }, + "node_modules/@aws-sdk/middleware-endpoint-discovery": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.696.0.tgz", + "integrity": "sha512-KZvgR3lB9zdLuuO+SxeQQVDn8R46Brlolsbv7JGyR6id0BNy6pqitHdcrZCyp9jaMjrSFcPROceeLy70Cu3pZg==", + "dependencies": { + "@aws-sdk/endpoint-cache": "3.693.0", + "@aws-sdk/types": "3.696.0", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.696.0.tgz", + "integrity": "sha512-zELJp9Ta2zkX7ELggMN9qMCgekqZhFC5V2rOr4hJDEb/Tte7gpfKSObAnw/3AYiVqt36sjHKfdkoTsuwGdEoDg==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.696.0.tgz", + "integrity": "sha512-KhkHt+8AjCxcR/5Zp3++YPJPpFQzxpr+jmONiT/Jw2yqnSngZ0Yspm5wGoRx2hS1HJbyZNuaOWEGuJoxLeBKfA==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.696.0.tgz", + "integrity": "sha512-si/maV3Z0hH7qa99f9ru2xpS5HlfSVcasRlNUXKSDm611i7jFMWwGNLUOXFAOLhXotPX5G3Z6BLwL34oDeBMug==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.696.0.tgz", + "integrity": "sha512-Lvyj8CTyxrHI6GHd2YVZKIRI5Fmnugt3cpJo0VrKKEgK5zMySwEZ1n4dqPK6czYRWKd5+WnYHYAuU+Wdk6Jsjw==", + "dependencies": { + "@aws-sdk/core": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@aws-sdk/util-endpoints": "3.696.0", + "@smithy/core": "^2.5.3", + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.696.0.tgz", + "integrity": "sha512-7EuH142lBXjI8yH6dVS/CZeiK/WZsmb/8zP6bQbVYpMrppSTgB3MzZZdxVZGzL5r8zPQOU10wLC4kIMy0qdBVQ==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/types": "^3.7.1", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.10", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.699.0.tgz", + "integrity": "sha512-kuiEW9DWs7fNos/SM+y58HCPhcIzm1nEZLhe2/7/6+TvAYLuEWURYsbK48gzsxXlaJ2k/jGY3nIsA7RptbMOwA==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.699.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.696.0.tgz", + "integrity": "sha512-9rTvUJIAj5d3//U5FDPWGJ1nFJLuWb30vugGOrWk7aNZ6y9tuA3PI7Cc9dP8WEXKVyK1vuuk8rSFP2iqXnlgrw==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/util-dynamodb": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.699.0.tgz", + "integrity": "sha512-OamtYYyvVuEXiGUmjrKQqPhAUD1L8I1Eb7XcLcKIJKjegtadxr8Alp+wiefz/4Tandmb5erOjNJNYUCU3KfPog==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.699.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.696.0.tgz", + "integrity": "sha512-T5s0IlBVX+gkb9g/I6CLt4yAZVzMSiGnbUqWihWsHvQR1WOoIcndQy/Oz/IJXT9T2ipoy7a80gzV6a5mglrioA==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/types": "^3.7.1", + "@smithy/util-endpoints": "^2.1.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.693.0.tgz", + "integrity": "sha512-ttrag6haJLWABhLqtg1Uf+4LgHWIMOVSYL+VYZmAp2v4PUGOwWmWQH0Zk8RM7YuQcLfH/EoR72/Yxz6A4FKcuw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.696.0.tgz", + "integrity": "sha512-Z5rVNDdmPOe6ELoM5AhF/ja5tSjbe6ctSctDPb0JdDf4dT0v2MfwhJKzXju2RzX8Es/77Glh7MlaXLE0kCB9+Q==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/types": "^3.7.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.696.0.tgz", + "integrity": "sha512-KhKqcfyXIB0SCCt+qsu4eJjsfiOrNzK5dCV7RAW2YIpp+msxGUUX0NdRE9rkzjiv+3EMktgJm3eEIS+yxtlVdQ==", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@smithy/abort-controller": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.8.tgz", + "integrity": "sha512-+3DOBcUn5/rVjlxGvUPKc416SExarAQ+Qe0bqk30YSUjbepwpS7QN0cyKUSifvLJhdMZ0WPzPP5ymut0oonrpQ==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.12.tgz", + "integrity": "sha512-YAJP9UJFZRZ8N+UruTeq78zkdjUHmzsY62J4qKWZ4SXB4QXJ/+680EfXXgkYA2xj77ooMqtUY9m406zGNqwivQ==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.11", + "@smithy/types": "^3.7.1", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.10", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.5.4.tgz", + "integrity": "sha512-iFh2Ymn2sCziBRLPuOOxRPkuCx/2gBdXtBGuCUFLUe6bWYjKnhHyIPqGeNkLZ5Aco/5GjebRTBFiWID3sDbrKw==", + "dependencies": { + "@smithy/middleware-serde": "^3.0.10", + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-middleware": "^3.0.10", + "@smithy/util-stream": "^3.3.1", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.7.tgz", + "integrity": "sha512-cEfbau+rrWF8ylkmmVAObOmjbTIzKyUC5TkBL58SbLywD0RCBC4JAUKbmtSm2w5KUJNRPGgpGFMvE2FKnuNlWQ==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.11", + "@smithy/property-provider": "^3.1.10", + "@smithy/types": "^3.7.1", + "@smithy/url-parser": "^3.0.10", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.1.tgz", + "integrity": "sha512-bH7QW0+JdX0bPBadXt8GwMof/jz0H28I84hU1Uet9ISpzUqXqRQ3fEZJ+ANPOhzSEczYvANNl3uDQDYArSFDtA==", + "dependencies": { + "@smithy/protocol-http": "^4.1.7", + "@smithy/querystring-builder": "^3.0.10", + "@smithy/types": "^3.7.1", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/hash-node": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.10.tgz", + "integrity": "sha512-3zWGWCHI+FlJ5WJwx73Mw2llYR8aflVyZN5JhoqLxbdPZi6UyKSdCeXAWJw9ja22m6S6Tzz1KZ+kAaSwvydi0g==", + "dependencies": { + "@smithy/types": "^3.7.1", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.10.tgz", + "integrity": "sha512-Lp2L65vFi+cj0vFMu2obpPW69DU+6O5g3086lmI4XcnRCG8PxvpWC7XyaVwJCxsZFzueHjXnrOH/E0pl0zikfA==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.12.tgz", + "integrity": "sha512-1mDEXqzM20yywaMDuf5o9ue8OkJ373lSPbaSjyEvkWdqELhFMyNNgKGWL/rCSf4KME8B+HlHKuR8u9kRj8HzEQ==", + "dependencies": { + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.4.tgz", + "integrity": "sha512-TybiW2LA3kYVd3e+lWhINVu1o26KJbBwOpADnf0L4x/35vLVica77XVR5hvV9+kWeTGeSJ3IHTcYxbRxlbwhsg==", + "dependencies": { + "@smithy/core": "^2.5.4", + "@smithy/middleware-serde": "^3.0.10", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.11", + "@smithy/types": "^3.7.1", + "@smithy/url-parser": "^3.0.10", + "@smithy/util-middleware": "^3.0.10", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "3.0.28", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.28.tgz", + "integrity": "sha512-vK2eDfvIXG1U64FEUhYxoZ1JSj4XFbYWkK36iz02i3pFwWiDz1Q7jKhGTBCwx/7KqJNk4VS7d7cDLXFOvP7M+g==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.7", + "@smithy/service-error-classification": "^3.0.10", + "@smithy/smithy-client": "^3.4.5", + "@smithy/types": "^3.7.1", + "@smithy/util-middleware": "^3.0.10", + "@smithy/util-retry": "^3.0.10", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.10.tgz", + "integrity": "sha512-MnAuhh+dD14F428ubSJuRnmRsfOpxSzvRhaGVTvd/lrUDE3kxzCCmH8lnVTvoNQnV2BbJ4c15QwZ3UdQBtFNZA==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.10.tgz", + "integrity": "sha512-grCHyoiARDBBGPyw2BeicpjgpsDFWZZxptbVKb3CRd/ZA15F/T6rZjCCuBUjJwdck1nwUuIxYtsS4H9DDpbP5w==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.11.tgz", + "integrity": "sha512-URq3gT3RpDikh/8MBJUB+QGZzfS7Bm6TQTqoh4CqE8NBuyPkWa5eUXj0XFcFfeZVgg3WMh1u19iaXn8FvvXxZw==", + "dependencies": { + "@smithy/property-provider": "^3.1.10", + "@smithy/shared-ini-file-loader": "^3.1.11", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.3.1.tgz", + "integrity": "sha512-fr+UAOMGWh6bn4YSEezBCpJn9Ukp9oR4D32sCjCo7U81evE11YePOQ58ogzyfgmjIO79YeOdfXXqr0jyhPQeMg==", + "dependencies": { + "@smithy/abort-controller": "^3.1.8", + "@smithy/protocol-http": "^4.1.7", + "@smithy/querystring-builder": "^3.0.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.10.tgz", + "integrity": "sha512-n1MJZGTorTH2DvyTVj+3wXnd4CzjJxyXeOgnTlgNVFxaaMeT4OteEp4QrzF8p9ee2yg42nvyVK6R/awLCakjeQ==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.7.tgz", + "integrity": "sha512-FP2LepWD0eJeOTm0SjssPcgqAlDFzOmRXqXmGhfIM52G7Lrox/pcpQf6RP4F21k0+O12zaqQt5fCDOeBtqY6Cg==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.10.tgz", + "integrity": "sha512-nT9CQF3EIJtIUepXQuBFb8dxJi3WVZS3XfuDksxSCSn+/CzZowRLdhDn+2acbBv8R6eaJqPupoI/aRFIImNVPQ==", + "dependencies": { + "@smithy/types": "^3.7.1", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.10.tgz", + "integrity": "sha512-Oa0XDcpo9SmjhiDD9ua2UyM3uU01ZTuIrNdZvzwUTykW1PM8o2yJvMh1Do1rY5sUQg4NDV70dMi0JhDx4GyxuQ==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.10.tgz", + "integrity": "sha512-zHe642KCqDxXLuhs6xmHVgRwy078RfqxP2wRDpIyiF8EmsWXptMwnMwbVa50lw+WOGNrYm9zbaEg0oDe3PTtvQ==", + "dependencies": { + "@smithy/types": "^3.7.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.11.tgz", + "integrity": "sha512-AUdrIZHFtUgmfSN4Gq9nHu3IkHMa1YDcN+s061Nfm+6pQ0mJy85YQDB0tZBCmls0Vuj22pLwDPmL92+Hvfwwlg==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.3.tgz", + "integrity": "sha512-pPSQQ2v2vu9vc8iew7sszLd0O09I5TRc5zhY71KA+Ao0xYazIG+uLeHbTJfIWGO3BGVLiXjUr3EEeCcEQLjpWQ==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-middleware": "^3.0.10", + "@smithy/util-uri-escape": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.4.5.tgz", + "integrity": "sha512-k0sybYT9zlP79sIKd1XGm4TmK0AS1nA2bzDHXx7m0nGi3RQ8dxxQUs4CPkSmQTKAo+KF9aINU3KzpGIpV7UoMw==", + "dependencies": { + "@smithy/core": "^2.5.4", + "@smithy/middleware-endpoint": "^3.2.4", + "@smithy/middleware-stack": "^3.0.10", + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "@smithy/util-stream": "^3.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.7.1.tgz", + "integrity": "sha512-XKLcLXZY7sUQgvvWyeaL/qwNPp6V3dWcUjqrQKjSb+tzYiCy340R/c64LV5j+Tnb2GhmunEX0eou+L+m2hJNYA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.10.tgz", + "integrity": "sha512-j90NUalTSBR2NaZTuruEgavSdh8MLirf58LoGSk4AtQfyIymogIhgnGUU2Mga2bkMkpSoC9gxb74xBXL5afKAQ==", + "dependencies": { + "@smithy/querystring-parser": "^3.0.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", + "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", + "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "3.0.28", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.28.tgz", + "integrity": "sha512-6bzwAbZpHRFVJsOztmov5PGDmJYsbNSoIEfHSJJyFLzfBGCCChiO3od9k7E/TLgrCsIifdAbB9nqbVbyE7wRUw==", + "dependencies": { + "@smithy/property-provider": "^3.1.10", + "@smithy/smithy-client": "^3.4.5", + "@smithy/types": "^3.7.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "3.0.28", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.28.tgz", + "integrity": "sha512-78ENJDorV1CjOQselGmm3+z7Yqjj5HWCbjzh0Ixuq736dh1oEnD9sAttSBNSLlpZsX8VQnmERqA2fEFlmqWn8w==", + "dependencies": { + "@smithy/config-resolver": "^3.0.12", + "@smithy/credential-provider-imds": "^3.2.7", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/property-provider": "^3.1.10", + "@smithy/smithy-client": "^3.4.5", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.6.tgz", + "integrity": "sha512-mFV1t3ndBh0yZOJgWxO9J/4cHZVn5UG1D8DeCc6/echfNkeEJWu9LD7mgGH5fHrEdR7LDoWw7PQO6QiGpHXhgA==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.11", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.10.tgz", + "integrity": "sha512-eJO+/+RsrG2RpmY68jZdwQtnfsxjmPxzMlQpnHKjFPwrYqvlcT+fHdT+ZVwcjlWSrByOhGr9Ff2GG17efc192A==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.10.tgz", + "integrity": "sha512-1l4qatFp4PiU6j7UsbasUHL2VU023NRB/gfaa1M0rDqVrRN4g3mCArLRyH3OuktApA4ye+yjWQHjdziunw2eWA==", + "dependencies": { + "@smithy/service-error-classification": "^3.0.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.3.1.tgz", + "integrity": "sha512-Ff68R5lJh2zj+AUTvbAU/4yx+6QPRzg7+pI7M1FbtQHcRIp7xvguxVsQBKyB3fwiOwhAKu0lnNyYBaQfSW6TNw==", + "dependencies": { + "@smithy/fetch-http-handler": "^4.1.1", + "@smithy/node-http-handler": "^3.3.1", + "@smithy/types": "^3.7.1", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-waiter": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.1.9.tgz", + "integrity": "sha512-/aMXPANhMOlMPjfPtSrDfPeVP8l56SJlz93xeiLmhLe5xvlXA5T3abZ2ilEsDEPeY9T/wnN/vNGn9wa1SbufWA==", + "dependencies": { + "@smithy/abort-controller": "^3.1.8", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==" + }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + }, + "node_modules/fast-xml-parser": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", + "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/mnemonist": { + "version": "0.38.3", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.3.tgz", + "integrity": "sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw==", + "dependencies": { + "obliterator": "^1.6.1" + } + }, + "node_modules/obliterator": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-1.6.1.tgz", + "integrity": "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==" + }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "node_modules/uuid": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.3.tgz", + "integrity": "sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/esm/bin/uuid" + } + } + } +} diff --git a/tasker-server/layers/nodejs/package.json b/tasker-server/layers/nodejs/package.json new file mode 100644 index 0000000..7bc32fa --- /dev/null +++ b/tasker-server/layers/nodejs/package.json @@ -0,0 +1,18 @@ +{ + "name": "nodejs", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "@aws-sdk/client-dynamodb": "^3.699.0", + "@aws-sdk/lib-dynamodb": "^3.699.0", + "@types/uuid": "^10.0.0", + "uuid": "^11.0.3" + } +} diff --git a/tasker-server/package-lock.json b/tasker-server/package-lock.json index 654e74b..8f56123 100644 --- a/tasker-server/package-lock.json +++ b/tasker-server/package-lock.json @@ -9,8 +9,11 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@aws-sdk/client-dynamodb": "^3.699.0", + "@aws-sdk/lib-dynamodb": "^3.699.0", "@types/uuid": "^10.0.0", - "aws-sdk": "^2.1692.0" + "aws-sdk": "^2.1692.0", + "uuid": "^11.0.3" }, "devDependencies": { "@types/node": "^22.9.1", @@ -20,6 +23,722 @@ "typescript": "^5.6.3" } }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.699.0.tgz", + "integrity": "sha512-npf2ZPUbFyyeWb0Fmgs/hGdjeecyUyldVU6okwM9DaaeOtlUmXA9e1vtrplgRJs3DLJdDJCGSTrBI+4w0MtgGg==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.699.0", + "@aws-sdk/client-sts": "3.699.0", + "@aws-sdk/core": "3.696.0", + "@aws-sdk/credential-provider-node": "3.699.0", + "@aws-sdk/middleware-endpoint-discovery": "3.696.0", + "@aws-sdk/middleware-host-header": "3.696.0", + "@aws-sdk/middleware-logger": "3.696.0", + "@aws-sdk/middleware-recursion-detection": "3.696.0", + "@aws-sdk/middleware-user-agent": "3.696.0", + "@aws-sdk/region-config-resolver": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@aws-sdk/util-endpoints": "3.696.0", + "@aws-sdk/util-user-agent-browser": "3.696.0", + "@aws-sdk/util-user-agent-node": "3.696.0", + "@smithy/config-resolver": "^3.0.12", + "@smithy/core": "^2.5.3", + "@smithy/fetch-http-handler": "^4.1.1", + "@smithy/hash-node": "^3.0.10", + "@smithy/invalid-dependency": "^3.0.10", + "@smithy/middleware-content-length": "^3.0.12", + "@smithy/middleware-endpoint": "^3.2.3", + "@smithy/middleware-retry": "^3.0.27", + "@smithy/middleware-serde": "^3.0.10", + "@smithy/middleware-stack": "^3.0.10", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/node-http-handler": "^3.3.1", + "@smithy/protocol-http": "^4.1.7", + "@smithy/smithy-client": "^3.4.4", + "@smithy/types": "^3.7.1", + "@smithy/url-parser": "^3.0.10", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.27", + "@smithy/util-defaults-mode-node": "^3.0.27", + "@smithy/util-endpoints": "^2.1.6", + "@smithy/util-middleware": "^3.0.10", + "@smithy/util-retry": "^3.0.10", + "@smithy/util-utf8": "^3.0.0", + "@smithy/util-waiter": "^3.1.9", + "@types/uuid": "^9.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==" + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.696.0.tgz", + "integrity": "sha512-q5TTkd08JS0DOkHfUL853tuArf7NrPeqoS5UOvqJho8ibV9Ak/a/HO4kNvy9Nj3cib/toHYHsQIEtecUPSUUrQ==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.696.0", + "@aws-sdk/middleware-host-header": "3.696.0", + "@aws-sdk/middleware-logger": "3.696.0", + "@aws-sdk/middleware-recursion-detection": "3.696.0", + "@aws-sdk/middleware-user-agent": "3.696.0", + "@aws-sdk/region-config-resolver": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@aws-sdk/util-endpoints": "3.696.0", + "@aws-sdk/util-user-agent-browser": "3.696.0", + "@aws-sdk/util-user-agent-node": "3.696.0", + "@smithy/config-resolver": "^3.0.12", + "@smithy/core": "^2.5.3", + "@smithy/fetch-http-handler": "^4.1.1", + "@smithy/hash-node": "^3.0.10", + "@smithy/invalid-dependency": "^3.0.10", + "@smithy/middleware-content-length": "^3.0.12", + "@smithy/middleware-endpoint": "^3.2.3", + "@smithy/middleware-retry": "^3.0.27", + "@smithy/middleware-serde": "^3.0.10", + "@smithy/middleware-stack": "^3.0.10", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/node-http-handler": "^3.3.1", + "@smithy/protocol-http": "^4.1.7", + "@smithy/smithy-client": "^3.4.4", + "@smithy/types": "^3.7.1", + "@smithy/url-parser": "^3.0.10", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.27", + "@smithy/util-defaults-mode-node": "^3.0.27", + "@smithy/util-endpoints": "^2.1.6", + "@smithy/util-middleware": "^3.0.10", + "@smithy/util-retry": "^3.0.10", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.699.0.tgz", + "integrity": "sha512-u8a1GorY5D1l+4FQAf4XBUC1T10/t7neuwT21r0ymrtMFSK2a9QqVHKMoLkvavAwyhJnARSBM9/UQC797PFOFw==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.696.0", + "@aws-sdk/credential-provider-node": "3.699.0", + "@aws-sdk/middleware-host-header": "3.696.0", + "@aws-sdk/middleware-logger": "3.696.0", + "@aws-sdk/middleware-recursion-detection": "3.696.0", + "@aws-sdk/middleware-user-agent": "3.696.0", + "@aws-sdk/region-config-resolver": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@aws-sdk/util-endpoints": "3.696.0", + "@aws-sdk/util-user-agent-browser": "3.696.0", + "@aws-sdk/util-user-agent-node": "3.696.0", + "@smithy/config-resolver": "^3.0.12", + "@smithy/core": "^2.5.3", + "@smithy/fetch-http-handler": "^4.1.1", + "@smithy/hash-node": "^3.0.10", + "@smithy/invalid-dependency": "^3.0.10", + "@smithy/middleware-content-length": "^3.0.12", + "@smithy/middleware-endpoint": "^3.2.3", + "@smithy/middleware-retry": "^3.0.27", + "@smithy/middleware-serde": "^3.0.10", + "@smithy/middleware-stack": "^3.0.10", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/node-http-handler": "^3.3.1", + "@smithy/protocol-http": "^4.1.7", + "@smithy/smithy-client": "^3.4.4", + "@smithy/types": "^3.7.1", + "@smithy/url-parser": "^3.0.10", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.27", + "@smithy/util-defaults-mode-node": "^3.0.27", + "@smithy/util-endpoints": "^2.1.6", + "@smithy/util-middleware": "^3.0.10", + "@smithy/util-retry": "^3.0.10", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.699.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.699.0.tgz", + "integrity": "sha512-++lsn4x2YXsZPIzFVwv3fSUVM55ZT0WRFmPeNilYIhZClxHLmVAWKH4I55cY9ry60/aTKYjzOXkWwyBKGsGvQg==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.699.0", + "@aws-sdk/core": "3.696.0", + "@aws-sdk/credential-provider-node": "3.699.0", + "@aws-sdk/middleware-host-header": "3.696.0", + "@aws-sdk/middleware-logger": "3.696.0", + "@aws-sdk/middleware-recursion-detection": "3.696.0", + "@aws-sdk/middleware-user-agent": "3.696.0", + "@aws-sdk/region-config-resolver": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@aws-sdk/util-endpoints": "3.696.0", + "@aws-sdk/util-user-agent-browser": "3.696.0", + "@aws-sdk/util-user-agent-node": "3.696.0", + "@smithy/config-resolver": "^3.0.12", + "@smithy/core": "^2.5.3", + "@smithy/fetch-http-handler": "^4.1.1", + "@smithy/hash-node": "^3.0.10", + "@smithy/invalid-dependency": "^3.0.10", + "@smithy/middleware-content-length": "^3.0.12", + "@smithy/middleware-endpoint": "^3.2.3", + "@smithy/middleware-retry": "^3.0.27", + "@smithy/middleware-serde": "^3.0.10", + "@smithy/middleware-stack": "^3.0.10", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/node-http-handler": "^3.3.1", + "@smithy/protocol-http": "^4.1.7", + "@smithy/smithy-client": "^3.4.4", + "@smithy/types": "^3.7.1", + "@smithy/url-parser": "^3.0.10", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.27", + "@smithy/util-defaults-mode-node": "^3.0.27", + "@smithy/util-endpoints": "^2.1.6", + "@smithy/util-middleware": "^3.0.10", + "@smithy/util-retry": "^3.0.10", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.696.0.tgz", + "integrity": "sha512-3c9III1k03DgvRZWg8vhVmfIXPG6hAciN9MzQTzqGngzWAELZF/WONRTRQuDFixVtarQatmLHYVw/atGeA2Byw==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/core": "^2.5.3", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/property-provider": "^3.1.9", + "@smithy/protocol-http": "^4.1.7", + "@smithy/signature-v4": "^4.2.2", + "@smithy/smithy-client": "^3.4.4", + "@smithy/types": "^3.7.1", + "@smithy/util-middleware": "^3.0.10", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.696.0.tgz", + "integrity": "sha512-T9iMFnJL7YTlESLpVFT3fg1Lkb1lD+oiaIC8KMpepb01gDUBIpj9+Y+pA/cgRWW0yRxmkDXNazAE2qQTVFGJzA==", + "dependencies": { + "@aws-sdk/core": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.696.0.tgz", + "integrity": "sha512-GV6EbvPi2eq1+WgY/o2RFA3P7HGmnkIzCNmhwtALFlqMroLYWKE7PSeHw66Uh1dFQeVESn0/+hiUNhu1mB0emA==", + "dependencies": { + "@aws-sdk/core": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@smithy/fetch-http-handler": "^4.1.1", + "@smithy/node-http-handler": "^3.3.1", + "@smithy/property-provider": "^3.1.9", + "@smithy/protocol-http": "^4.1.7", + "@smithy/smithy-client": "^3.4.4", + "@smithy/types": "^3.7.1", + "@smithy/util-stream": "^3.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.699.0.tgz", + "integrity": "sha512-dXmCqjJnKmG37Q+nLjPVu22mNkrGHY8hYoOt3Jo9R2zr5MYV7s/NHsCHr+7E+BZ+tfZYLRPeB1wkpTeHiEcdRw==", + "dependencies": { + "@aws-sdk/core": "3.696.0", + "@aws-sdk/credential-provider-env": "3.696.0", + "@aws-sdk/credential-provider-http": "3.696.0", + "@aws-sdk/credential-provider-process": "3.696.0", + "@aws-sdk/credential-provider-sso": "3.699.0", + "@aws-sdk/credential-provider-web-identity": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@smithy/credential-provider-imds": "^3.2.6", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.699.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.699.0.tgz", + "integrity": "sha512-MmEmNDo1bBtTgRmdNfdQksXu4uXe66s0p1hi1YPrn1h59Q605eq/xiWbGL6/3KdkViH6eGUuABeV2ODld86ylg==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.696.0", + "@aws-sdk/credential-provider-http": "3.696.0", + "@aws-sdk/credential-provider-ini": "3.699.0", + "@aws-sdk/credential-provider-process": "3.696.0", + "@aws-sdk/credential-provider-sso": "3.699.0", + "@aws-sdk/credential-provider-web-identity": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@smithy/credential-provider-imds": "^3.2.6", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.696.0.tgz", + "integrity": "sha512-mL1RcFDe9sfmyU5K1nuFkO8UiJXXxLX4JO1gVaDIOvPqwStpUAwi3A1BoeZhWZZNQsiKI810RnYGo0E0WB/hUA==", + "dependencies": { + "@aws-sdk/core": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.699.0.tgz", + "integrity": "sha512-Ekp2cZG4pl9D8+uKWm4qO1xcm8/MeiI8f+dnlZm8aQzizeC+aXYy9GyoclSf6daK8KfRPiRfM7ZHBBL5dAfdMA==", + "dependencies": { + "@aws-sdk/client-sso": "3.696.0", + "@aws-sdk/core": "3.696.0", + "@aws-sdk/token-providers": "3.699.0", + "@aws-sdk/types": "3.696.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.696.0.tgz", + "integrity": "sha512-XJ/CVlWChM0VCoc259vWguFUjJDn/QwDqHwbx+K9cg3v6yrqXfK5ai+p/6lx0nQpnk4JzPVeYYxWRpaTsGC9rg==", + "dependencies": { + "@aws-sdk/core": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.696.0" + } + }, + "node_modules/@aws-sdk/endpoint-cache": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.693.0.tgz", + "integrity": "sha512-/zK0ZZncBf5FbTfo8rJMcQIXXk4Ibhe5zEMiwFNivVPR2uNC0+oqfwXz7vjxwY0t6BPE3Bs4h9uFEz4xuGCY6w==", + "dependencies": { + "mnemonist": "0.38.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/lib-dynamodb": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.699.0.tgz", + "integrity": "sha512-k28YlOaoZ0p71SZYxOgqSRGjK+RIg8EYEoG7DoFoBeXxXX5R3Zpu07Mjl480y1enYULaLKroeKunUxd50qWNrw==", + "dependencies": { + "@aws-sdk/core": "3.696.0", + "@aws-sdk/util-dynamodb": "3.699.0", + "@smithy/core": "^2.5.3", + "@smithy/smithy-client": "^3.4.4", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.699.0" + } + }, + "node_modules/@aws-sdk/middleware-endpoint-discovery": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.696.0.tgz", + "integrity": "sha512-KZvgR3lB9zdLuuO+SxeQQVDn8R46Brlolsbv7JGyR6id0BNy6pqitHdcrZCyp9jaMjrSFcPROceeLy70Cu3pZg==", + "dependencies": { + "@aws-sdk/endpoint-cache": "3.693.0", + "@aws-sdk/types": "3.696.0", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.696.0.tgz", + "integrity": "sha512-zELJp9Ta2zkX7ELggMN9qMCgekqZhFC5V2rOr4hJDEb/Tte7gpfKSObAnw/3AYiVqt36sjHKfdkoTsuwGdEoDg==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.696.0.tgz", + "integrity": "sha512-KhkHt+8AjCxcR/5Zp3++YPJPpFQzxpr+jmONiT/Jw2yqnSngZ0Yspm5wGoRx2hS1HJbyZNuaOWEGuJoxLeBKfA==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.696.0.tgz", + "integrity": "sha512-si/maV3Z0hH7qa99f9ru2xpS5HlfSVcasRlNUXKSDm611i7jFMWwGNLUOXFAOLhXotPX5G3Z6BLwL34oDeBMug==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.696.0.tgz", + "integrity": "sha512-Lvyj8CTyxrHI6GHd2YVZKIRI5Fmnugt3cpJo0VrKKEgK5zMySwEZ1n4dqPK6czYRWKd5+WnYHYAuU+Wdk6Jsjw==", + "dependencies": { + "@aws-sdk/core": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@aws-sdk/util-endpoints": "3.696.0", + "@smithy/core": "^2.5.3", + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.696.0.tgz", + "integrity": "sha512-7EuH142lBXjI8yH6dVS/CZeiK/WZsmb/8zP6bQbVYpMrppSTgB3MzZZdxVZGzL5r8zPQOU10wLC4kIMy0qdBVQ==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/types": "^3.7.1", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.10", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.699.0.tgz", + "integrity": "sha512-kuiEW9DWs7fNos/SM+y58HCPhcIzm1nEZLhe2/7/6+TvAYLuEWURYsbK48gzsxXlaJ2k/jGY3nIsA7RptbMOwA==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.699.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.696.0.tgz", + "integrity": "sha512-9rTvUJIAj5d3//U5FDPWGJ1nFJLuWb30vugGOrWk7aNZ6y9tuA3PI7Cc9dP8WEXKVyK1vuuk8rSFP2iqXnlgrw==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/util-dynamodb": { + "version": "3.699.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.699.0.tgz", + "integrity": "sha512-OamtYYyvVuEXiGUmjrKQqPhAUD1L8I1Eb7XcLcKIJKjegtadxr8Alp+wiefz/4Tandmb5erOjNJNYUCU3KfPog==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.699.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.696.0.tgz", + "integrity": "sha512-T5s0IlBVX+gkb9g/I6CLt4yAZVzMSiGnbUqWihWsHvQR1WOoIcndQy/Oz/IJXT9T2ipoy7a80gzV6a5mglrioA==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/types": "^3.7.1", + "@smithy/util-endpoints": "^2.1.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.693.0.tgz", + "integrity": "sha512-ttrag6haJLWABhLqtg1Uf+4LgHWIMOVSYL+VYZmAp2v4PUGOwWmWQH0Zk8RM7YuQcLfH/EoR72/Yxz6A4FKcuw==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.696.0.tgz", + "integrity": "sha512-Z5rVNDdmPOe6ELoM5AhF/ja5tSjbe6ctSctDPb0JdDf4dT0v2MfwhJKzXju2RzX8Es/77Glh7MlaXLE0kCB9+Q==", + "dependencies": { + "@aws-sdk/types": "3.696.0", + "@smithy/types": "^3.7.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.696.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.696.0.tgz", + "integrity": "sha512-KhKqcfyXIB0SCCt+qsu4eJjsfiOrNzK5dCV7RAW2YIpp+msxGUUX0NdRE9rkzjiv+3EMktgJm3eEIS+yxtlVdQ==", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.696.0", + "@aws-sdk/types": "3.696.0", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", @@ -225,6 +944,545 @@ "node": ">=14" } }, + "node_modules/@smithy/abort-controller": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.8.tgz", + "integrity": "sha512-+3DOBcUn5/rVjlxGvUPKc416SExarAQ+Qe0bqk30YSUjbepwpS7QN0cyKUSifvLJhdMZ0WPzPP5ymut0oonrpQ==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.12.tgz", + "integrity": "sha512-YAJP9UJFZRZ8N+UruTeq78zkdjUHmzsY62J4qKWZ4SXB4QXJ/+680EfXXgkYA2xj77ooMqtUY9m406zGNqwivQ==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.11", + "@smithy/types": "^3.7.1", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.10", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.5.4.tgz", + "integrity": "sha512-iFh2Ymn2sCziBRLPuOOxRPkuCx/2gBdXtBGuCUFLUe6bWYjKnhHyIPqGeNkLZ5Aco/5GjebRTBFiWID3sDbrKw==", + "dependencies": { + "@smithy/middleware-serde": "^3.0.10", + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-middleware": "^3.0.10", + "@smithy/util-stream": "^3.3.1", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.7.tgz", + "integrity": "sha512-cEfbau+rrWF8ylkmmVAObOmjbTIzKyUC5TkBL58SbLywD0RCBC4JAUKbmtSm2w5KUJNRPGgpGFMvE2FKnuNlWQ==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.11", + "@smithy/property-provider": "^3.1.10", + "@smithy/types": "^3.7.1", + "@smithy/url-parser": "^3.0.10", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.1.tgz", + "integrity": "sha512-bH7QW0+JdX0bPBadXt8GwMof/jz0H28I84hU1Uet9ISpzUqXqRQ3fEZJ+ANPOhzSEczYvANNl3uDQDYArSFDtA==", + "dependencies": { + "@smithy/protocol-http": "^4.1.7", + "@smithy/querystring-builder": "^3.0.10", + "@smithy/types": "^3.7.1", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/hash-node": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.10.tgz", + "integrity": "sha512-3zWGWCHI+FlJ5WJwx73Mw2llYR8aflVyZN5JhoqLxbdPZi6UyKSdCeXAWJw9ja22m6S6Tzz1KZ+kAaSwvydi0g==", + "dependencies": { + "@smithy/types": "^3.7.1", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.10.tgz", + "integrity": "sha512-Lp2L65vFi+cj0vFMu2obpPW69DU+6O5g3086lmI4XcnRCG8PxvpWC7XyaVwJCxsZFzueHjXnrOH/E0pl0zikfA==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.12.tgz", + "integrity": "sha512-1mDEXqzM20yywaMDuf5o9ue8OkJ373lSPbaSjyEvkWdqELhFMyNNgKGWL/rCSf4KME8B+HlHKuR8u9kRj8HzEQ==", + "dependencies": { + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.4.tgz", + "integrity": "sha512-TybiW2LA3kYVd3e+lWhINVu1o26KJbBwOpADnf0L4x/35vLVica77XVR5hvV9+kWeTGeSJ3IHTcYxbRxlbwhsg==", + "dependencies": { + "@smithy/core": "^2.5.4", + "@smithy/middleware-serde": "^3.0.10", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/shared-ini-file-loader": "^3.1.11", + "@smithy/types": "^3.7.1", + "@smithy/url-parser": "^3.0.10", + "@smithy/util-middleware": "^3.0.10", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "3.0.28", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.28.tgz", + "integrity": "sha512-vK2eDfvIXG1U64FEUhYxoZ1JSj4XFbYWkK36iz02i3pFwWiDz1Q7jKhGTBCwx/7KqJNk4VS7d7cDLXFOvP7M+g==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.11", + "@smithy/protocol-http": "^4.1.7", + "@smithy/service-error-classification": "^3.0.10", + "@smithy/smithy-client": "^3.4.5", + "@smithy/types": "^3.7.1", + "@smithy/util-middleware": "^3.0.10", + "@smithy/util-retry": "^3.0.10", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.10.tgz", + "integrity": "sha512-MnAuhh+dD14F428ubSJuRnmRsfOpxSzvRhaGVTvd/lrUDE3kxzCCmH8lnVTvoNQnV2BbJ4c15QwZ3UdQBtFNZA==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.10.tgz", + "integrity": "sha512-grCHyoiARDBBGPyw2BeicpjgpsDFWZZxptbVKb3CRd/ZA15F/T6rZjCCuBUjJwdck1nwUuIxYtsS4H9DDpbP5w==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.11.tgz", + "integrity": "sha512-URq3gT3RpDikh/8MBJUB+QGZzfS7Bm6TQTqoh4CqE8NBuyPkWa5eUXj0XFcFfeZVgg3WMh1u19iaXn8FvvXxZw==", + "dependencies": { + "@smithy/property-provider": "^3.1.10", + "@smithy/shared-ini-file-loader": "^3.1.11", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.3.1.tgz", + "integrity": "sha512-fr+UAOMGWh6bn4YSEezBCpJn9Ukp9oR4D32sCjCo7U81evE11YePOQ58ogzyfgmjIO79YeOdfXXqr0jyhPQeMg==", + "dependencies": { + "@smithy/abort-controller": "^3.1.8", + "@smithy/protocol-http": "^4.1.7", + "@smithy/querystring-builder": "^3.0.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.10.tgz", + "integrity": "sha512-n1MJZGTorTH2DvyTVj+3wXnd4CzjJxyXeOgnTlgNVFxaaMeT4OteEp4QrzF8p9ee2yg42nvyVK6R/awLCakjeQ==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.7.tgz", + "integrity": "sha512-FP2LepWD0eJeOTm0SjssPcgqAlDFzOmRXqXmGhfIM52G7Lrox/pcpQf6RP4F21k0+O12zaqQt5fCDOeBtqY6Cg==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.10.tgz", + "integrity": "sha512-nT9CQF3EIJtIUepXQuBFb8dxJi3WVZS3XfuDksxSCSn+/CzZowRLdhDn+2acbBv8R6eaJqPupoI/aRFIImNVPQ==", + "dependencies": { + "@smithy/types": "^3.7.1", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.10.tgz", + "integrity": "sha512-Oa0XDcpo9SmjhiDD9ua2UyM3uU01ZTuIrNdZvzwUTykW1PM8o2yJvMh1Do1rY5sUQg4NDV70dMi0JhDx4GyxuQ==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.10.tgz", + "integrity": "sha512-zHe642KCqDxXLuhs6xmHVgRwy078RfqxP2wRDpIyiF8EmsWXptMwnMwbVa50lw+WOGNrYm9zbaEg0oDe3PTtvQ==", + "dependencies": { + "@smithy/types": "^3.7.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.11.tgz", + "integrity": "sha512-AUdrIZHFtUgmfSN4Gq9nHu3IkHMa1YDcN+s061Nfm+6pQ0mJy85YQDB0tZBCmls0Vuj22pLwDPmL92+Hvfwwlg==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.3.tgz", + "integrity": "sha512-pPSQQ2v2vu9vc8iew7sszLd0O09I5TRc5zhY71KA+Ao0xYazIG+uLeHbTJfIWGO3BGVLiXjUr3EEeCcEQLjpWQ==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-middleware": "^3.0.10", + "@smithy/util-uri-escape": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.4.5.tgz", + "integrity": "sha512-k0sybYT9zlP79sIKd1XGm4TmK0AS1nA2bzDHXx7m0nGi3RQ8dxxQUs4CPkSmQTKAo+KF9aINU3KzpGIpV7UoMw==", + "dependencies": { + "@smithy/core": "^2.5.4", + "@smithy/middleware-endpoint": "^3.2.4", + "@smithy/middleware-stack": "^3.0.10", + "@smithy/protocol-http": "^4.1.7", + "@smithy/types": "^3.7.1", + "@smithy/util-stream": "^3.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.7.1.tgz", + "integrity": "sha512-XKLcLXZY7sUQgvvWyeaL/qwNPp6V3dWcUjqrQKjSb+tzYiCy340R/c64LV5j+Tnb2GhmunEX0eou+L+m2hJNYA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.10.tgz", + "integrity": "sha512-j90NUalTSBR2NaZTuruEgavSdh8MLirf58LoGSk4AtQfyIymogIhgnGUU2Mga2bkMkpSoC9gxb74xBXL5afKAQ==", + "dependencies": { + "@smithy/querystring-parser": "^3.0.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", + "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", + "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "3.0.28", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.28.tgz", + "integrity": "sha512-6bzwAbZpHRFVJsOztmov5PGDmJYsbNSoIEfHSJJyFLzfBGCCChiO3od9k7E/TLgrCsIifdAbB9nqbVbyE7wRUw==", + "dependencies": { + "@smithy/property-provider": "^3.1.10", + "@smithy/smithy-client": "^3.4.5", + "@smithy/types": "^3.7.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "3.0.28", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.28.tgz", + "integrity": "sha512-78ENJDorV1CjOQselGmm3+z7Yqjj5HWCbjzh0Ixuq736dh1oEnD9sAttSBNSLlpZsX8VQnmERqA2fEFlmqWn8w==", + "dependencies": { + "@smithy/config-resolver": "^3.0.12", + "@smithy/credential-provider-imds": "^3.2.7", + "@smithy/node-config-provider": "^3.1.11", + "@smithy/property-provider": "^3.1.10", + "@smithy/smithy-client": "^3.4.5", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.6.tgz", + "integrity": "sha512-mFV1t3ndBh0yZOJgWxO9J/4cHZVn5UG1D8DeCc6/echfNkeEJWu9LD7mgGH5fHrEdR7LDoWw7PQO6QiGpHXhgA==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.11", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.10.tgz", + "integrity": "sha512-eJO+/+RsrG2RpmY68jZdwQtnfsxjmPxzMlQpnHKjFPwrYqvlcT+fHdT+ZVwcjlWSrByOhGr9Ff2GG17efc192A==", + "dependencies": { + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.10.tgz", + "integrity": "sha512-1l4qatFp4PiU6j7UsbasUHL2VU023NRB/gfaa1M0rDqVrRN4g3mCArLRyH3OuktApA4ye+yjWQHjdziunw2eWA==", + "dependencies": { + "@smithy/service-error-classification": "^3.0.10", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.3.1.tgz", + "integrity": "sha512-Ff68R5lJh2zj+AUTvbAU/4yx+6QPRzg7+pI7M1FbtQHcRIp7xvguxVsQBKyB3fwiOwhAKu0lnNyYBaQfSW6TNw==", + "dependencies": { + "@smithy/fetch-http-handler": "^4.1.1", + "@smithy/node-http-handler": "^3.3.1", + "@smithy/types": "^3.7.1", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-waiter": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.1.9.tgz", + "integrity": "sha512-/aMXPANhMOlMPjfPtSrDfPeVP8l56SJlz93xeiLmhLe5xvlXA5T3abZ2ilEsDEPeY9T/wnN/vNGn9wa1SbufWA==", + "dependencies": { + "@smithy/abort-controller": "^3.1.8", + "@smithy/types": "^3.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -364,6 +1622,14 @@ "node": ">= 10.0.0" } }, + "node_modules/aws-sdk/node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/axios": { "version": "1.7.7", "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", @@ -417,6 +1683,11 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -797,6 +2068,27 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-xml-parser": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", + "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -1369,6 +2661,14 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mnemonist": { + "version": "0.38.3", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.3.tgz", + "integrity": "sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw==", + "dependencies": { + "obliterator": "^1.6.1" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -1381,6 +2681,11 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/obliterator": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-1.6.1.tgz", + "integrity": "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==" + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -1764,6 +3069,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -1776,6 +3086,11 @@ "node": ">=8" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -1857,11 +3172,15 @@ } }, "node_modules/uuid": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", - "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.3.tgz", + "integrity": "sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist/esm/bin/uuid" } }, "node_modules/which": { diff --git a/tasker-server/package.json b/tasker-server/package.json index 3ea5bf8..e0a018b 100644 --- a/tasker-server/package.json +++ b/tasker-server/package.json @@ -5,14 +5,21 @@ "scripts": { "infra:init": "cd terraform && AWS_PROFILE=default terraform init", "infra:plan": "cd terraform && AWS_PROFILE=default terraform plan", - "infra:apply": "cd terraform && AWS_PROFILE=default terraform apply" + "infra:apply": "cd terraform && AWS_PROFILE=default terraform apply", + "infra:destroy": "cd terraform && AWS_PROFILE=default terraform destroy", + "sls:package": "AWS_PROFILE=default sls package", + "sls:deploy": "AWS_PROFILE=default sls deploy", + "sls:remove": "AWS_PROFILE=default sls remove" }, "author": "", "license": "ISC", "description": "", "dependencies": { + "@aws-sdk/client-dynamodb": "^3.699.0", + "@aws-sdk/lib-dynamodb": "^3.699.0", "@types/uuid": "^10.0.0", - "aws-sdk": "^2.1692.0" + "aws-sdk": "^2.1692.0", + "uuid": "^11.0.3" }, "devDependencies": { "@types/node": "^22.9.1", diff --git a/tasker-server/serverless.yml b/tasker-server/serverless.yml index 8fe9e89..da8cbf6 100644 --- a/tasker-server/serverless.yml +++ b/tasker-server/serverless.yml @@ -6,7 +6,7 @@ plugins: provider: stackName: ${self:service} name: aws - region: ${opt:region, 'eu-north-1'} + region: "eu-north-1" runtime: nodejs20.x environment: SLS_REGION: ${self:provider.region} @@ -15,6 +15,8 @@ provider: TASKER_USER_TABLE_NAME: ${ssm:/tasker/dynamodb/user-table-name} TASKER_TASK_EXTRA_TABLE_NAME: ${ssm:/tasker/dynamodb/task-extra-table-name} TASKER_TEAM_TABLE_NAME: ${ssm:/tasker/dynamodb/team-table-name} + layers: + - ${ssm:/tasker/layers/tasker-layer-arn} iam: role: statements: @@ -32,6 +34,14 @@ provider: ] functions: + postSignUp: + handler: src/handlers/postSignUp.handler + memorySize: 1024 + timeout: 60 + events: + - cognitoUserPool: + pool: ${ssm:/tasker/cognito/user-pool-id} + trigger: PostConfirmation # POST /users createUser: handler: src/handlers/createUser.handler @@ -42,9 +52,6 @@ functions: path: users method: post cors: true - authorizer: - type: COGNITO_USER_POOLS - arn: ${ssm:/tasker/cognito/user-pool-arn} # POST /projects createProject: handler: src/handlers/createProject.handler diff --git a/tasker-server/src/handlers/createProject.ts b/tasker-server/src/handlers/createProject.ts index 751205b..cfdd20c 100644 --- a/tasker-server/src/handlers/createProject.ts +++ b/tasker-server/src/handlers/createProject.ts @@ -1,16 +1,18 @@ -import { DynamoDB } from "aws-sdk"; +import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; +import { DynamoDBDocument, PutCommandInput } from "@aws-sdk/lib-dynamodb"; import { v4 as uuidv4 } from "uuid"; const SLS_REGION = process.env.SLS_REGION; const TASKER_PROJECT_TABLE_NAME = process.env.TASKER_PROJECT_TABLE_NAME || ""; -const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); +const client = new DynamoDBClient({ region: SLS_REGION }); +const docClient = DynamoDBDocument.from(client); export const handler = async (event: any): Promise => { const { name, description, startDate, endDate } = event.body; try { const newProject = { - type: "projects", + category: "projects", projectId: `project#${uuidv4()}`, name, description, @@ -18,12 +20,12 @@ export const handler = async (event: any): Promise => { endDate, }; - const params = { + const params: PutCommandInput = { TableName: TASKER_PROJECT_TABLE_NAME, Item: newProject, }; - await docClient.put(params).promise(); + await docClient.put(params); return { status: 201, diff --git a/tasker-server/src/handlers/createTask.ts b/tasker-server/src/handlers/createTask.ts index c6ecea6..bec3b1f 100644 --- a/tasker-server/src/handlers/createTask.ts +++ b/tasker-server/src/handlers/createTask.ts @@ -1,10 +1,12 @@ -import { DynamoDB } from "aws-sdk"; +import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; +import { DynamoDBDocument, PutCommandInput } from "@aws-sdk/lib-dynamodb"; import { v4 as uuidv4 } from "uuid"; const SLS_REGION = process.env.SLS_REGION; const TASKER_TASK_TABLE_NAME = process.env.TASKER_TASK_TABLE_NAME || ""; -const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); +const client = new DynamoDBClient({ region: SLS_REGION }); +const docClient = DynamoDBDocument.from(client); export const handler = async (event: any): Promise => { const { @@ -22,7 +24,7 @@ export const handler = async (event: any): Promise => { } = event.body; try { const newTask = { - type: "tasks", + category: "tasks", taskId: `task#${uuidv4()}`, title, description, @@ -37,12 +39,12 @@ export const handler = async (event: any): Promise => { assignedUserId, }; - const params = { + const params: PutCommandInput = { TableName: TASKER_TASK_TABLE_NAME, Item: newTask, }; - await docClient.put(params).promise(); + await docClient.put(params); return { status: 201, diff --git a/tasker-server/src/handlers/createUser.ts b/tasker-server/src/handlers/createUser.ts index 96df5af..762586d 100644 --- a/tasker-server/src/handlers/createUser.ts +++ b/tasker-server/src/handlers/createUser.ts @@ -1,32 +1,34 @@ import { fetchRandomTeamId } from "@/lib/util"; -import { DynamoDB } from "aws-sdk"; +import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; +import { DynamoDBDocument, PutCommandInput } from "@aws-sdk/lib-dynamodb"; import { v4 as uuidv4 } from "uuid"; const SLS_REGION = process.env.SLS_REGION; const TASKER_USER_TABLE_NAME = process.env.TASKER_USER_TABLE_NAME || ""; -const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); +const client = new DynamoDBClient({ region: SLS_REGION }); +const docClient = DynamoDBDocument.from(client); export const handler = async (event: any): Promise => { - const { username, cognitoId, profilePictureUrl = "i0.jpg" } = event.body; + const { username, cognitoId } = event.body; const teamId = fetchRandomTeamId(); try { const newUser = { - type: "users", + category: "users", cognitoId, userId: `user#${uuidv4()}`, username, - profilePictureUrl, + profilePictureUrl: "i0.jpg", teamId, }; - const params = { + const params: PutCommandInput = { TableName: TASKER_USER_TABLE_NAME, Item: newUser, }; - await docClient.put(params).promise(); + await docClient.put(params); return { status: 201, diff --git a/tasker-server/src/handlers/getProjects.ts b/tasker-server/src/handlers/getProjects.ts index daa036e..9375246 100644 --- a/tasker-server/src/handlers/getProjects.ts +++ b/tasker-server/src/handlers/getProjects.ts @@ -1,21 +1,23 @@ -import { DynamoDB } from "aws-sdk"; +import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; +import { DynamoDBDocument, QueryCommandInput } from "@aws-sdk/lib-dynamodb"; const SLS_REGION = process.env.SLS_REGION; const TASKER_PROJECT_TABLE_NAME = process.env.TASKER_PROJECT_TABLE_NAME || ""; -const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); +const client = new DynamoDBClient({ region: SLS_REGION }); +const docClient = DynamoDBDocument.from(client); export const handler = async (event: any): Promise => { try { - const params = { + const params: QueryCommandInput = { TableName: TASKER_PROJECT_TABLE_NAME, - KeyConditionExpression: "type = :type", + KeyConditionExpression: "category = :category", ExpressionAttributeValues: { - ":type": "projects", + ":category": "projects", }, }; - const projects = await docClient.query(params).promise(); + const projects = await docClient.query(params); return { status: 200, diff --git a/tasker-server/src/handlers/getTasks.ts b/tasker-server/src/handlers/getTasks.ts index 534f6d9..5a722d0 100644 --- a/tasker-server/src/handlers/getTasks.ts +++ b/tasker-server/src/handlers/getTasks.ts @@ -3,27 +3,29 @@ import { fetchComments, fetchUserWithUserId, } from "@/lib/util"; -import { DynamoDB } from "aws-sdk"; +import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; +import { DynamoDBDocument, QueryCommandInput } from "@aws-sdk/lib-dynamodb"; const SLS_REGION = process.env.SLS_REGION; const TASKER_TASK_TABLE_NAME = process.env.TASKER_TASK_TABLE_NAME || ""; -const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); +const client = new DynamoDBClient({ region: SLS_REGION }); +const docClient = DynamoDBDocument.from(client); export const handler = async (event: any): Promise => { const { projectId } = event.queryStringParameters; try { - const params = { + const params: QueryCommandInput = { TableName: TASKER_TASK_TABLE_NAME, - KeyConditionExpression: "type = :type AND projectId = :projectId", + KeyConditionExpression: "category = :category AND projectId = :projectId", IndexName: "GSI-project-id", ExpressionAttributeValues: { - ":type": "tasks", + ":category": "tasks", ":projectId": projectId, }, }; - const result = await docClient.query(params).promise(); + const result = await docClient.query(params); const tasks = result.Items || []; const tasksWithDetails = await Promise.all( diff --git a/tasker-server/src/handlers/getTeams.ts b/tasker-server/src/handlers/getTeams.ts index 50c1105..59d55d5 100644 --- a/tasker-server/src/handlers/getTeams.ts +++ b/tasker-server/src/handlers/getTeams.ts @@ -1,22 +1,24 @@ import { fetchUserWithUserId } from "@/lib/util"; -import { DynamoDB } from "aws-sdk"; +import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; +import { DynamoDBDocument, QueryCommandInput } from "@aws-sdk/lib-dynamodb"; const SLS_REGION = process.env.SLS_REGION; const TASKER_TEAM_TABLE_NAME = process.env.TASKER_TEAM_TABLE_NAME || ""; -const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); +const client = new DynamoDBClient({ region: SLS_REGION }); +const docClient = DynamoDBDocument.from(client); export const handler = async (event: any): Promise => { try { - const params = { + const params: QueryCommandInput = { TableName: TASKER_TEAM_TABLE_NAME, - KeyConditionExpression: "type = :type", + KeyConditionExpression: "category = :category", ExpressionAttributeValues: { - ":type": "teams", + ":category": "teams", }, }; - const result = await docClient.query(params).promise(); + const result = await docClient.query(params); const teams = result.Items || []; const teamsWithUsernames = await Promise.all( diff --git a/tasker-server/src/handlers/getUser.ts b/tasker-server/src/handlers/getUser.ts index 6defa64..872c08c 100644 --- a/tasker-server/src/handlers/getUser.ts +++ b/tasker-server/src/handlers/getUser.ts @@ -1,23 +1,25 @@ -import { DynamoDB } from "aws-sdk"; +import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; +import { DynamoDBDocument, QueryCommandInput } from "@aws-sdk/lib-dynamodb"; const SLS_REGION = process.env.SLS_REGION; const TASKER_USER_TABLE_NAME = process.env.TASKER_USER_TABLE_NAME || ""; -const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); +const client = new DynamoDBClient({ region: SLS_REGION }); +const docClient = DynamoDBDocument.from(client); export const handler = async (event: any): Promise => { const { cognitoId } = event.pathParameters; try { - const params = { + const params: QueryCommandInput = { TableName: TASKER_USER_TABLE_NAME, - KeyConditionExpression: "type = :type AND cognitoId = :cognitoId", + KeyConditionExpression: "category = :category AND cognitoId = :cognitoId", ExpressionAttributeValues: { - ":type": "users", + ":category": "users", ":cognitoId": cognitoId, }, }; - const user = await docClient.query(params).promise(); + const user = await docClient.query(params); return { status: 200, diff --git a/tasker-server/src/handlers/getUsers.ts b/tasker-server/src/handlers/getUsers.ts index 83e6d0b..7d280eb 100644 --- a/tasker-server/src/handlers/getUsers.ts +++ b/tasker-server/src/handlers/getUsers.ts @@ -1,21 +1,23 @@ -import { DynamoDB } from "aws-sdk"; +import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; +import { DynamoDBDocument, QueryCommandInput } from "@aws-sdk/lib-dynamodb"; const SLS_REGION = process.env.SLS_REGION; const TASKER_USER_TABLE_NAME = process.env.TASKER_USER_TABLE_NAME || ""; -const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); +const client = new DynamoDBClient({ region: SLS_REGION }); +const docClient = DynamoDBDocument.from(client); export const handler = async (event: any): Promise => { try { - const params = { + const params: QueryCommandInput = { TableName: TASKER_USER_TABLE_NAME, - KeyConditionExpression: "type = :type", + KeyConditionExpression: "category = :category", ExpressionAttributeValues: { - ":type": "users", + ":category": "users", }, }; - const users = await docClient.query(params).promise(); + const users = await docClient.query(params); return { status: 200, diff --git a/tasker-server/src/handlers/postSignUp.ts b/tasker-server/src/handlers/postSignUp.ts new file mode 100644 index 0000000..26f9322 --- /dev/null +++ b/tasker-server/src/handlers/postSignUp.ts @@ -0,0 +1,34 @@ +import https from "https"; + +export const handler = async (event: any): Promise => { + const postData = JSON.stringify({ + username: + event.request.userAttributes["preferred_username"] || event.userName, + cognitoId: event.userName, + }); + + const options = { + hostname: process.env.API_URL, + port: 443, + path: "/users", + method: "POST", + headers: { + "Content-category": "application/json", + "Content-Length": Buffer.byteLength(postData), + }, + }; + + const responseBody = new Promise((resolve, reject) => { + const req = https.request(options, (res) => { + res.setEncoding("utf8"); + let responseBody = ""; + res.on("data", (chunk) => (responseBody += chunk)); + res.on("end", () => resolve(responseBody)); + }); + req.on("error", (error) => reject(error)); + req.write(postData); + req.end(); + }); + + return event; +}; diff --git a/tasker-server/src/handlers/updateTaskStatus.ts b/tasker-server/src/handlers/updateTaskStatus.ts index 9c9b4d4..f9ad61e 100644 --- a/tasker-server/src/handlers/updateTaskStatus.ts +++ b/tasker-server/src/handlers/updateTaskStatus.ts @@ -1,18 +1,20 @@ -import { DynamoDB } from "aws-sdk"; +import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; +import { DynamoDBDocument, UpdateCommandInput } from "@aws-sdk/lib-dynamodb"; const SLS_REGION = process.env.SLS_REGION; const TASKER_TASK_TABLE_NAME = process.env.TASKER_TASK_TABLE_NAME || ""; -const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); +const client = new DynamoDBClient({ region: SLS_REGION }); +const docClient = DynamoDBDocument.from(client); export const handler = async (event: any): Promise => { const { taskId } = event.pathParameters; const { status } = event.body; try { - const params = { + const params: UpdateCommandInput = { TableName: TASKER_TASK_TABLE_NAME, Key: { - type: "tasks", + category: "tasks", taskId, }, UpdateExpression: "set #status = :status", @@ -25,7 +27,7 @@ export const handler = async (event: any): Promise => { ReturnValues: "ALL_NEW", }; - const updatedTask = await docClient.update(params).promise(); + const updatedTask = await docClient.update(params); return { status: 200, diff --git a/tasker-server/src/lib/util.ts b/tasker-server/src/lib/util.ts index 15727f1..bdaa6d2 100644 --- a/tasker-server/src/lib/util.ts +++ b/tasker-server/src/lib/util.ts @@ -1,4 +1,5 @@ -import { DynamoDB } from "aws-sdk"; +import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; +import { DynamoDBDocument, QueryCommandInput } from "@aws-sdk/lib-dynamodb"; const SLS_REGION = process.env.SLS_REGION; const TASKER_PROJECT_TABLE_NAME = process.env.TASKER_PROJECT_TABLE_NAME || ""; @@ -7,18 +8,19 @@ const TASKER_TASK_TABLE_NAME = process.env.TASKER_TASK_TABLE_NAME || ""; const TASKER_TASK_EXTRA_TABLE_NAME = process.env.TASKER_TASK_EXTRA_TABLE_NAME || ""; -const docClient = new DynamoDB.DocumentClient({ region: SLS_REGION }); +const client = new DynamoDBClient({ region: SLS_REGION }); +const docClient = DynamoDBDocument.from(client); export const fetchRandomTeamId = async () => { const params = { TableName: TASKER_PROJECT_TABLE_NAME, - KeyConditionExpression: "type = :type", + KeyConditionExpression: "category = :category", ExpressionAttributeValues: { - ":type": "teams", + ":category": "teams", }, }; - const projects = await docClient.query(params).promise(); + const projects = await docClient.query(params); if (!projects.Items) { return null; } @@ -28,47 +30,47 @@ export const fetchRandomTeamId = async () => { }; export const fetchUserWithUserId = async (userId: string): Promise => { - const params: DynamoDB.DocumentClient.QueryInput = { + const params: QueryCommandInput = { TableName: TASKER_USER_TABLE_NAME, - KeyConditionExpression: "type = :type AND userId = :userId", + KeyConditionExpression: "category = :category AND userId = :userId", IndexName: "GSI-user-id", ExpressionAttributeValues: { - ":type": "users", + ":category": "users", ":userId": userId, }, }; - const result = await docClient.query(params).promise(); + const result = await docClient.query(params); return result.Items?.[0]; }; export const fetchComments = async (taskId: string): Promise => { - const params: DynamoDB.DocumentClient.QueryInput = { + const params: QueryCommandInput = { TableName: TASKER_TASK_EXTRA_TABLE_NAME, - KeyConditionExpression: "type = :type AND taskId = :taskId", + KeyConditionExpression: "category = :category AND taskId = :taskId", IndexName: "GSI-task-id", ExpressionAttributeValues: { - ":type": "comments", + ":category": "comments", ":taskId": taskId, }, }; - const result = await docClient.query(params).promise(); + const result = await docClient.query(params); return result.Items; }; export const fetchAttachments = async (taskId: string): Promise => { - const params: DynamoDB.DocumentClient.QueryInput = { + const params: QueryCommandInput = { TableName: TASKER_TASK_EXTRA_TABLE_NAME, - KeyConditionExpression: "type = :type AND taskId = :taskId", + KeyConditionExpression: "category = :category AND taskId = :taskId", IndexName: "GSI-task-id", ExpressionAttributeValues: { - ":type": "attachments", + ":category": "attachments", ":taskId": taskId, }, }; - const result = await docClient.query(params).promise(); + const result = await docClient.query(params); return result.Items; }; @@ -76,13 +78,13 @@ export const queryTasks = async ( userId: string, indexName: string, key: string -): Promise => { - const params = { +): Promise => { + const params: QueryCommandInput = { TableName: TASKER_TASK_TABLE_NAME, - KeyConditionExpression: "type = :type AND #key = :userId", + KeyConditionExpression: "category = :category AND #key = :userId", IndexName: indexName, ExpressionAttributeValues: { - ":type": "tasks", + ":category": "tasks", ":userId": userId, }, ExpressionAttributeNames: { @@ -90,6 +92,6 @@ export const queryTasks = async ( }, }; - const result = await docClient.query(params).promise(); + const result = await docClient.query(params); return result.Items ?? []; }; diff --git a/tasker-server/terraform/dynamodb.tf b/tasker-server/terraform/dynamodb.tf index 617fbbe..ec62629 100644 --- a/tasker-server/terraform/dynamodb.tf +++ b/tasker-server/terraform/dynamodb.tf @@ -1,11 +1,11 @@ resource "aws_dynamodb_table" "tasker_project_table" { name = "tasker-project-table" billing_mode = "PAY_PER_REQUEST" - hash_key = "type" + hash_key = "category" range_key = "projectId" attribute { - name = "type" + name = "category" type = "S" } @@ -30,11 +30,11 @@ resource "aws_ssm_parameter" "tasker_project_table_arn" { resource "aws_dynamodb_table" "tasker_user_table" { name = "tasker-user-table" billing_mode = "PAY_PER_REQUEST" - hash_key = "type" + hash_key = "category" range_key = "cognitoId" attribute { - name = "type" + name = "category" type = "S" } @@ -50,7 +50,7 @@ resource "aws_dynamodb_table" "tasker_user_table" { global_secondary_index { name = "GSI-user-id" - hash_key = "type" + hash_key = "category" range_key = "userId" projection_type = "ALL" } @@ -71,11 +71,11 @@ resource "aws_ssm_parameter" "tasker_user_table_arn" { resource "aws_dynamodb_table" "tasker_team_table" { name = "tasker-team-table" billing_mode = "PAY_PER_REQUEST" - hash_key = "type" + hash_key = "category" range_key = "teamId" attribute { - name = "type" + name = "category" type = "S" } @@ -100,11 +100,11 @@ resource "aws_ssm_parameter" "tasker_team_table_arn" { resource "aws_dynamodb_table" "tasker_task_table" { name = "tasker-task-table" billing_mode = "PAY_PER_REQUEST" - hash_key = "type" + hash_key = "category" range_key = "taskId" attribute { - name = "type" + name = "category" type = "S" } @@ -130,21 +130,21 @@ resource "aws_dynamodb_table" "tasker_task_table" { global_secondary_index { name = "GSI-project-id" - hash_key = "type" + hash_key = "category" range_key = "projectId" projection_type = "ALL" } global_secondary_index { name = "GSI-author-user-id" - hash_key = "type" + hash_key = "category" range_key = "authorUserId" projection_type = "ALL" } global_secondary_index { name = "GSI-assigned-user-id" - hash_key = "type" + hash_key = "category" range_key = "assignedUserId" projection_type = "ALL" } @@ -165,11 +165,11 @@ resource "aws_ssm_parameter" "tasker_task_table_arn" { resource "aws_dynamodb_table" "tasker_task_extra_table" { name = "tasker-task-extra-table" billing_mode = "PAY_PER_REQUEST" - hash_key = "type" + hash_key = "category" range_key = "id" attribute { - name = "type" + name = "category" type = "S" } @@ -185,7 +185,7 @@ resource "aws_dynamodb_table" "tasker_task_extra_table" { global_secondary_index { name = "GSI-task-id" - hash_key = "type" + hash_key = "category" range_key = "taskId" projection_type = "ALL" } diff --git a/tasker-server/terraform/layer.tf b/tasker-server/terraform/layer.tf new file mode 100644 index 0000000..d6f998a --- /dev/null +++ b/tasker-server/terraform/layer.tf @@ -0,0 +1,24 @@ +resource "aws_s3_bucket" "tasker_lambda_layer" { + bucket = "tasker-lambda-layer" +} + +resource "aws_s3_object" "tasker_lambda_layer_zip" { + bucket = aws_s3_bucket.tasker_lambda_layer.id + key = "layers/tasker-layer.zip" + source = "../layers/tasker-layer.zip" +} + +resource "aws_lambda_layer_version" "tasker_layer" { + layer_name = "tasker-layer" + s3_bucket = aws_s3_object.tasker_lambda_layer_zip.bucket + s3_key = aws_s3_object.tasker_lambda_layer_zip.key + compatible_runtimes = ["nodejs20.x"] + + description = "Tasker Lambda Layer with shared dependencies" +} + +resource "aws_ssm_parameter" "tasker_layer_arn" { + name = "/tasker/layers/tasker-layer-arn" + type = "String" + value = aws_lambda_layer_version.tasker_layer.arn +} -- 2.49.1 From 59c0c97252c882a5cdbcb12ca568ac408f2e515f Mon Sep 17 00:00:00 2001 From: Andrew Trieu Date: Sat, 23 Nov 2024 08:42:31 +0200 Subject: [PATCH 3/7] feat: Update serverless configuration and refactor API handlers to improve error handling and response structure --- tasker-server/serverless.yml | 11 +++++++++-- tasker-server/src/handlers/createProject.ts | 9 ++++++--- tasker-server/src/handlers/createTask.ts | 8 +++++--- tasker-server/src/handlers/createUser.ts | 8 +++++--- tasker-server/src/handlers/getProjects.ts | 6 ++++-- tasker-server/src/handlers/getTasks.ts | 6 ++++-- tasker-server/src/handlers/getTeams.ts | 6 ++++-- tasker-server/src/handlers/getUser.ts | 6 ++++-- tasker-server/src/handlers/getUserTasks.ts | 6 ++++-- tasker-server/src/handlers/getUsers.ts | 6 ++++-- tasker-server/src/handlers/postSignUp.ts | 11 ++++++++--- tasker-server/src/handlers/updateTaskStatus.ts | 8 +++++--- 12 files changed, 62 insertions(+), 29 deletions(-) diff --git a/tasker-server/serverless.yml b/tasker-server/serverless.yml index da8cbf6..48e420d 100644 --- a/tasker-server/serverless.yml +++ b/tasker-server/serverless.yml @@ -10,8 +10,9 @@ provider: runtime: nodejs20.x environment: SLS_REGION: ${self:provider.region} - TASKER_TASK_TABLE_NAME: ${ssm:/tasker/dynamodb/project-table-name} - TASKER_PROJECT_TABLE_NAME: ${ssm:/tasker/dynamodb/task-table-name} + API_BASE_URL: ${ssm:/tasker/api/base-url} + TASKER_TASK_TABLE_NAME: ${ssm:/tasker/dynamodb/task-table-name} + TASKER_PROJECT_TABLE_NAME: ${ssm:/tasker/dynamodb/project-table-name} TASKER_USER_TABLE_NAME: ${ssm:/tasker/dynamodb/user-table-name} TASKER_TASK_EXTRA_TABLE_NAME: ${ssm:/tasker/dynamodb/task-extra-table-name} TASKER_TEAM_TABLE_NAME: ${ssm:/tasker/dynamodb/team-table-name} @@ -32,6 +33,11 @@ provider: "arn:aws:dynamodb:${self:provider.region}:*:table/tasker-*", "arn:aws:dynamodb:${self:provider.region}:*:table/tasker-*/*", ] + - Effect: Allow + Action: + - execute-api:Invoke + Resource: + - "arn:aws:execute-api:${self:provider.region}:*:*/*/POST/users" functions: postSignUp: @@ -52,6 +58,7 @@ functions: path: users method: post cors: true + authorizer: aws_iam # POST /projects createProject: handler: src/handlers/createProject.handler diff --git a/tasker-server/src/handlers/createProject.ts b/tasker-server/src/handlers/createProject.ts index cfdd20c..0770c47 100644 --- a/tasker-server/src/handlers/createProject.ts +++ b/tasker-server/src/handlers/createProject.ts @@ -9,7 +9,8 @@ const client = new DynamoDBClient({ region: SLS_REGION }); const docClient = DynamoDBDocument.from(client); export const handler = async (event: any): Promise => { - const { name, description, startDate, endDate } = event.body; + const { name, description, startDate, endDate } = JSON.parse(event.body); + try { const newProject = { category: "projects", @@ -28,12 +29,14 @@ export const handler = async (event: any): Promise => { await docClient.put(params); return { - status: 201, + statusCode: 201, + headers: { "Content-Type": "application/json" }, body: JSON.stringify(newProject), }; } catch (error: any) { return { - status: 500, + statusCode: 500, + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: `Error creating project: ${error.message}`, }), diff --git a/tasker-server/src/handlers/createTask.ts b/tasker-server/src/handlers/createTask.ts index bec3b1f..2ee1dcc 100644 --- a/tasker-server/src/handlers/createTask.ts +++ b/tasker-server/src/handlers/createTask.ts @@ -21,7 +21,7 @@ export const handler = async (event: any): Promise => { projectId, authorUserId, assignedUserId, - } = event.body; + } = JSON.parse(event.body); try { const newTask = { category: "tasks", @@ -47,12 +47,14 @@ export const handler = async (event: any): Promise => { await docClient.put(params); return { - status: 201, + statusCode: 201, + headers: { "Content-Type": "application/json" }, body: JSON.stringify(newTask), }; } catch (error: any) { return { - status: 500, + statusCode: 500, + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: `Error creating task: ${error.message}`, }), diff --git a/tasker-server/src/handlers/createUser.ts b/tasker-server/src/handlers/createUser.ts index 762586d..e991ac4 100644 --- a/tasker-server/src/handlers/createUser.ts +++ b/tasker-server/src/handlers/createUser.ts @@ -10,7 +10,7 @@ const client = new DynamoDBClient({ region: SLS_REGION }); const docClient = DynamoDBDocument.from(client); export const handler = async (event: any): Promise => { - const { username, cognitoId } = event.body; + const { username, cognitoId } = JSON.parse(event.body); const teamId = fetchRandomTeamId(); try { @@ -31,12 +31,14 @@ export const handler = async (event: any): Promise => { await docClient.put(params); return { - status: 201, + statusCode: 201, + headers: { "Content-Type": "application/json" }, body: JSON.stringify(newUser), }; } catch (error: any) { return { - status: 500, + statusCode: 500, + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: `Error creating user: ${error.message}`, }), diff --git a/tasker-server/src/handlers/getProjects.ts b/tasker-server/src/handlers/getProjects.ts index 9375246..1dcbdeb 100644 --- a/tasker-server/src/handlers/getProjects.ts +++ b/tasker-server/src/handlers/getProjects.ts @@ -20,12 +20,14 @@ export const handler = async (event: any): Promise => { const projects = await docClient.query(params); return { - status: 200, + statusCode: 200, + headers: { "Content-Type": "application/json" }, body: JSON.stringify(projects.Items), }; } catch (error: any) { return { - status: 500, + statusCode: 500, + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: `Error retrieving projects: ${error.message}`, }), diff --git a/tasker-server/src/handlers/getTasks.ts b/tasker-server/src/handlers/getTasks.ts index 5a722d0..ee56eb1 100644 --- a/tasker-server/src/handlers/getTasks.ts +++ b/tasker-server/src/handlers/getTasks.ts @@ -53,12 +53,14 @@ export const handler = async (event: any): Promise => { ); return { - status: 200, + statusCode: 200, + headers: { "Content-Type": "application/json" }, body: JSON.stringify(tasksWithDetails), }; } catch (error: any) { return { - status: 500, + statusCode: 500, + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: `Error retrieving tasks: ${error.message}`, }), diff --git a/tasker-server/src/handlers/getTeams.ts b/tasker-server/src/handlers/getTeams.ts index 59d55d5..c1054a6 100644 --- a/tasker-server/src/handlers/getTeams.ts +++ b/tasker-server/src/handlers/getTeams.ts @@ -40,12 +40,14 @@ export const handler = async (event: any): Promise => { ); return { - status: 200, + statusCode: 200, + headers: { "Content-Type": "application/json" }, body: JSON.stringify(teamsWithUsernames), }; } catch (error: any) { return { - status: 500, + statusCode: 500, + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: `Error retrieving teams: ${error.message}`, }), diff --git a/tasker-server/src/handlers/getUser.ts b/tasker-server/src/handlers/getUser.ts index 872c08c..4f67b98 100644 --- a/tasker-server/src/handlers/getUser.ts +++ b/tasker-server/src/handlers/getUser.ts @@ -22,12 +22,14 @@ export const handler = async (event: any): Promise => { const user = await docClient.query(params); return { - status: 200, + statusCode: 200, + headers: { "Content-Type": "application/json" }, body: JSON.stringify(user.Items?.[0] || {}), }; } catch (error: any) { return { - status: 500, + statusCode: 500, + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: `Error retrieving user: ${error.message}`, }), diff --git a/tasker-server/src/handlers/getUserTasks.ts b/tasker-server/src/handlers/getUserTasks.ts index d6c2d07..e578766 100644 --- a/tasker-server/src/handlers/getUserTasks.ts +++ b/tasker-server/src/handlers/getUserTasks.ts @@ -18,12 +18,14 @@ export const handler = async (event: any): Promise => { const userTasks = [...authorTasks, ...assigneeTasks]; return { - status: 200, + statusCode: 200, + headers: { "Content-Type": "application/json" }, body: JSON.stringify(userTasks), }; } catch (error: any) { return { - status: 500, + statusCode: 500, + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: `Error retrieving tasks for user: ${error.message}`, }), diff --git a/tasker-server/src/handlers/getUsers.ts b/tasker-server/src/handlers/getUsers.ts index 7d280eb..d111aaf 100644 --- a/tasker-server/src/handlers/getUsers.ts +++ b/tasker-server/src/handlers/getUsers.ts @@ -20,12 +20,14 @@ export const handler = async (event: any): Promise => { const users = await docClient.query(params); return { - status: 200, + statusCode: 200, + headers: { "Content-Type": "application/json" }, body: JSON.stringify(users.Items), }; } catch (error: any) { return { - status: 500, + statusCode: 500, + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: `Error retrieving users: ${error.message}`, }), diff --git a/tasker-server/src/handlers/postSignUp.ts b/tasker-server/src/handlers/postSignUp.ts index 26f9322..1ac6d39 100644 --- a/tasker-server/src/handlers/postSignUp.ts +++ b/tasker-server/src/handlers/postSignUp.ts @@ -1,4 +1,7 @@ import https from "https"; +import path from "path"; + +const API_BASE_URL = process.env.API_BASE_URL || ""; export const handler = async (event: any): Promise => { const postData = JSON.stringify({ @@ -8,9 +11,11 @@ export const handler = async (event: any): Promise => { }); const options = { - hostname: process.env.API_URL, + hostname: API_BASE_URL ? new URL(API_BASE_URL).hostname : "", port: 443, - path: "/users", + path: API_BASE_URL + ? path.join(new URL(API_BASE_URL).pathname, "/users") + : "", method: "POST", headers: { "Content-category": "application/json", @@ -18,7 +23,7 @@ export const handler = async (event: any): Promise => { }, }; - const responseBody = new Promise((resolve, reject) => { + const responseBody = await new Promise((resolve, reject) => { const req = https.request(options, (res) => { res.setEncoding("utf8"); let responseBody = ""; diff --git a/tasker-server/src/handlers/updateTaskStatus.ts b/tasker-server/src/handlers/updateTaskStatus.ts index f9ad61e..77842d4 100644 --- a/tasker-server/src/handlers/updateTaskStatus.ts +++ b/tasker-server/src/handlers/updateTaskStatus.ts @@ -9,7 +9,7 @@ const docClient = DynamoDBDocument.from(client); export const handler = async (event: any): Promise => { const { taskId } = event.pathParameters; - const { status } = event.body; + const { status } = JSON.parse(event.body); try { const params: UpdateCommandInput = { TableName: TASKER_TASK_TABLE_NAME, @@ -30,12 +30,14 @@ export const handler = async (event: any): Promise => { const updatedTask = await docClient.update(params); return { - status: 200, + statusCode: 200, + headers: { "Content-Type": "application/json" }, body: JSON.stringify(updatedTask.Attributes), }; } catch (error: any) { return { - status: 500, + statusCode: 500, + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: `Error updating task: ${error.message}`, }), -- 2.49.1 From 5f9ee29c8dd9d1d8eb4a283897d914f46720eeb3 Mon Sep 17 00:00:00 2001 From: Andrew Trieu Date: Sat, 23 Nov 2024 11:12:46 +0200 Subject: [PATCH 4/7] feat: Add Cognito user pool name parameter and update API handlers to include CORS headers --- tasker-client/src/state/api.ts | 8 +++---- tasker-server/serverless.yml | 18 ++++++--------- tasker-server/src/handlers/createProject.ts | 10 +++++++-- tasker-server/src/handlers/createTask.ts | 10 +++++++-- tasker-server/src/handlers/createUser.ts | 22 +++++++------------ tasker-server/src/handlers/getProjects.ts | 10 +++++++-- tasker-server/src/handlers/getTasks.ts | 10 +++++++-- tasker-server/src/handlers/getTeams.ts | 10 +++++++-- tasker-server/src/handlers/getUser.ts | 10 +++++++-- tasker-server/src/handlers/getUserTasks.ts | 10 +++++++-- tasker-server/src/handlers/getUsers.ts | 10 +++++++-- tasker-server/src/handlers/postSignUp.ts | 5 +++++ .../src/handlers/updateTaskStatus.ts | 10 +++++++-- tasker-server/terraform/cognito.tf | 7 ++++++ 14 files changed, 103 insertions(+), 47 deletions(-) diff --git a/tasker-client/src/state/api.ts b/tasker-client/src/state/api.ts index 00a6264..5ceb25b 100644 --- a/tasker-client/src/state/api.ts +++ b/tasker-client/src/state/api.ts @@ -80,9 +80,9 @@ export const api = createApi({ baseUrl: process.env.NEXT_PUBLIC_API_BASE_URL, prepareHeaders: async (headers) => { const session = await fetchAuthSession(); - const { accessToken } = session.tokens ?? {}; - if (accessToken) { - headers.set("Authorization", `Bearer ${accessToken}`); + const { idToken } = session.tokens ?? {}; + if (idToken) { + headers.set("Authorization", `Bearer ${idToken}`); } return headers; }, @@ -120,7 +120,7 @@ export const api = createApi({ }), invalidatesTags: ["Projects"], }), - getTasks: build.query({ + getTasks: build.query({ query: ({ projectId }) => `tasks?projectId=${projectId}`, providesTags: (result) => result diff --git a/tasker-server/serverless.yml b/tasker-server/serverless.yml index 48e420d..bc2349f 100644 --- a/tasker-server/serverless.yml +++ b/tasker-server/serverless.yml @@ -40,15 +40,7 @@ provider: - "arn:aws:execute-api:${self:provider.region}:*:*/*/POST/users" functions: - postSignUp: - handler: src/handlers/postSignUp.handler - memorySize: 1024 - timeout: 60 - events: - - cognitoUserPool: - pool: ${ssm:/tasker/cognito/user-pool-id} - trigger: PostConfirmation - # POST /users + # POST /users or triggered by Cognito createUser: handler: src/handlers/createUser.handler memorySize: 1024 @@ -59,6 +51,10 @@ functions: method: post cors: true authorizer: aws_iam + - cognitoUserPool: + existing: true + pool: ${ssm:/tasker/cognito/user-pool-name} + trigger: PostConfirmation # POST /projects createProject: handler: src/handlers/createProject.handler @@ -151,8 +147,8 @@ functions: type: COGNITO_USER_POOLS arn: ${ssm:/tasker/cognito/user-pool-arn} # GET /tasks/user/${userId} - getTasksByUser: - handler: src/handlers/getTasksByUser.handler + getUserTasks: + handler: src/handlers/getUserTasks.handler memorySize: 1024 timeout: 60 events: diff --git a/tasker-server/src/handlers/createProject.ts b/tasker-server/src/handlers/createProject.ts index 0770c47..75e6354 100644 --- a/tasker-server/src/handlers/createProject.ts +++ b/tasker-server/src/handlers/createProject.ts @@ -30,13 +30,19 @@ export const handler = async (event: any): Promise => { return { statusCode: 201, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify(newProject), }; } catch (error: any) { return { statusCode: 500, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify({ message: `Error creating project: ${error.message}`, }), diff --git a/tasker-server/src/handlers/createTask.ts b/tasker-server/src/handlers/createTask.ts index 2ee1dcc..caef865 100644 --- a/tasker-server/src/handlers/createTask.ts +++ b/tasker-server/src/handlers/createTask.ts @@ -48,13 +48,19 @@ export const handler = async (event: any): Promise => { return { statusCode: 201, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify(newTask), }; } catch (error: any) { return { statusCode: 500, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify({ message: `Error creating task: ${error.message}`, }), diff --git a/tasker-server/src/handlers/createUser.ts b/tasker-server/src/handlers/createUser.ts index e991ac4..0cd9032 100644 --- a/tasker-server/src/handlers/createUser.ts +++ b/tasker-server/src/handlers/createUser.ts @@ -10,8 +10,10 @@ const client = new DynamoDBClient({ region: SLS_REGION }); const docClient = DynamoDBDocument.from(client); export const handler = async (event: any): Promise => { - const { username, cognitoId } = JSON.parse(event.body); - const teamId = fetchRandomTeamId(); + const username = + event.request.userAttributes["preferred_username"] || event.userName; + const cognitoId = event.userName; + const teamId = await fetchRandomTeamId(); try { const newUser = { @@ -30,18 +32,10 @@ export const handler = async (event: any): Promise => { await docClient.put(params); - return { - statusCode: 201, - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(newUser), - }; + console.info(`User ${username} created with teamId ${teamId}`); } catch (error: any) { - return { - statusCode: 500, - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - message: `Error creating user: ${error.message}`, - }), - }; + throw new Error(`Error creating user: ${error.message}`); } + + return event; }; diff --git a/tasker-server/src/handlers/getProjects.ts b/tasker-server/src/handlers/getProjects.ts index 1dcbdeb..b2e6f8b 100644 --- a/tasker-server/src/handlers/getProjects.ts +++ b/tasker-server/src/handlers/getProjects.ts @@ -21,13 +21,19 @@ export const handler = async (event: any): Promise => { return { statusCode: 200, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify(projects.Items), }; } catch (error: any) { return { statusCode: 500, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify({ message: `Error retrieving projects: ${error.message}`, }), diff --git a/tasker-server/src/handlers/getTasks.ts b/tasker-server/src/handlers/getTasks.ts index ee56eb1..592f3b9 100644 --- a/tasker-server/src/handlers/getTasks.ts +++ b/tasker-server/src/handlers/getTasks.ts @@ -54,13 +54,19 @@ export const handler = async (event: any): Promise => { return { statusCode: 200, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify(tasksWithDetails), }; } catch (error: any) { return { statusCode: 500, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify({ message: `Error retrieving tasks: ${error.message}`, }), diff --git a/tasker-server/src/handlers/getTeams.ts b/tasker-server/src/handlers/getTeams.ts index c1054a6..e09e5f6 100644 --- a/tasker-server/src/handlers/getTeams.ts +++ b/tasker-server/src/handlers/getTeams.ts @@ -41,13 +41,19 @@ export const handler = async (event: any): Promise => { return { statusCode: 200, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify(teamsWithUsernames), }; } catch (error: any) { return { statusCode: 500, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify({ message: `Error retrieving teams: ${error.message}`, }), diff --git a/tasker-server/src/handlers/getUser.ts b/tasker-server/src/handlers/getUser.ts index 4f67b98..b8ae931 100644 --- a/tasker-server/src/handlers/getUser.ts +++ b/tasker-server/src/handlers/getUser.ts @@ -23,13 +23,19 @@ export const handler = async (event: any): Promise => { return { statusCode: 200, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify(user.Items?.[0] || {}), }; } catch (error: any) { return { statusCode: 500, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify({ message: `Error retrieving user: ${error.message}`, }), diff --git a/tasker-server/src/handlers/getUserTasks.ts b/tasker-server/src/handlers/getUserTasks.ts index e578766..b9dc8d9 100644 --- a/tasker-server/src/handlers/getUserTasks.ts +++ b/tasker-server/src/handlers/getUserTasks.ts @@ -19,13 +19,19 @@ export const handler = async (event: any): Promise => { return { statusCode: 200, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify(userTasks), }; } catch (error: any) { return { statusCode: 500, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify({ message: `Error retrieving tasks for user: ${error.message}`, }), diff --git a/tasker-server/src/handlers/getUsers.ts b/tasker-server/src/handlers/getUsers.ts index d111aaf..9a9e86d 100644 --- a/tasker-server/src/handlers/getUsers.ts +++ b/tasker-server/src/handlers/getUsers.ts @@ -21,13 +21,19 @@ export const handler = async (event: any): Promise => { return { statusCode: 200, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify(users.Items), }; } catch (error: any) { return { statusCode: 500, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify({ message: `Error retrieving users: ${error.message}`, }), diff --git a/tasker-server/src/handlers/postSignUp.ts b/tasker-server/src/handlers/postSignUp.ts index 1ac6d39..cf63274 100644 --- a/tasker-server/src/handlers/postSignUp.ts +++ b/tasker-server/src/handlers/postSignUp.ts @@ -10,6 +10,8 @@ export const handler = async (event: any): Promise => { cognitoId: event.userName, }); + console.log(postData); + const options = { hostname: API_BASE_URL ? new URL(API_BASE_URL).hostname : "", port: 443, @@ -20,6 +22,7 @@ export const handler = async (event: any): Promise => { headers: { "Content-category": "application/json", "Content-Length": Buffer.byteLength(postData), + "Allow-Control-Allow-Origin": "*", }, }; @@ -35,5 +38,7 @@ export const handler = async (event: any): Promise => { req.end(); }); + console.log(responseBody); + return event; }; diff --git a/tasker-server/src/handlers/updateTaskStatus.ts b/tasker-server/src/handlers/updateTaskStatus.ts index 77842d4..5910f8e 100644 --- a/tasker-server/src/handlers/updateTaskStatus.ts +++ b/tasker-server/src/handlers/updateTaskStatus.ts @@ -31,13 +31,19 @@ export const handler = async (event: any): Promise => { return { statusCode: 200, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify(updatedTask.Attributes), }; } catch (error: any) { return { statusCode: 500, - headers: { "Content-Type": "application/json" }, + headers: { + "Content-Type": "application/json", + "Access-Control-Allow-Origin": "*", + }, body: JSON.stringify({ message: `Error updating task: ${error.message}`, }), diff --git a/tasker-server/terraform/cognito.tf b/tasker-server/terraform/cognito.tf index dee2443..474651d 100644 --- a/tasker-server/terraform/cognito.tf +++ b/tasker-server/terraform/cognito.tf @@ -83,6 +83,13 @@ resource "aws_ssm_parameter" "user_pool_arn" { value = aws_cognito_user_pool.tasker_cognito_user_pool.arn } +resource "aws_ssm_parameter" "user_pool_name" { + name = "/tasker/cognito/user-pool-name" + description = "Tasker Cognito User Pool Name" + type = "String" + value = aws_cognito_user_pool.tasker_cognito_user_pool.name +} + resource "aws_ssm_parameter" "client_id" { name = "/tasker/cognito/client-id" description = "Tasker Cognito Client ID" -- 2.49.1 From 14284e1d357c25d1da6cbe1f76791a1cee3113d2 Mon Sep 17 00:00:00 2001 From: Andrew Trieu Date: Sat, 23 Nov 2024 17:19:09 +0200 Subject: [PATCH 5/7] feat: Update task and project ID formats, add populateSeedData function, and enhance user ID handling --- .../src/app/components/ModalNewTask/index.tsx | 22 +- .../src/app/components/Sidebar/index.tsx | 5 +- .../src/app/components/TaskCard/index.tsx | 2 +- tasker-client/src/app/home/page.tsx | 7 +- .../priority/reusablePriorityPage/index.tsx | 6 +- .../src/app/projects/BoardView/index.tsx | 46 +- .../src/app/projects/ListView/index.tsx | 12 +- .../src/app/projects/TableView/index.tsx | 13 +- .../src/app/projects/TimelineView/index.tsx | 12 +- tasker-client/src/app/projects/[id]/page.tsx | 11 +- tasker-client/src/app/search/page.tsx | 4 +- tasker-client/src/app/teams/page.tsx | 3 +- tasker-client/src/app/timeline/page.tsx | 2 +- tasker-server/seed/populateSeedData.ts | 1181 +++++++++++++++++ tasker-server/serverless.yml | 5 + tasker-server/src/handlers/createProject.ts | 2 +- tasker-server/src/handlers/createTask.ts | 2 +- tasker-server/src/handlers/createUser.ts | 5 +- tasker-server/src/handlers/postSignUp.ts | 44 - tasker-server/src/lib/util.ts | 14 +- tasker-server/terraform/s3.tf | 19 +- 21 files changed, 1299 insertions(+), 118 deletions(-) create mode 100644 tasker-server/seed/populateSeedData.ts delete mode 100644 tasker-server/src/handlers/postSignUp.ts diff --git a/tasker-client/src/app/components/ModalNewTask/index.tsx b/tasker-client/src/app/components/ModalNewTask/index.tsx index 6ce89d5..9748383 100644 --- a/tasker-client/src/app/components/ModalNewTask/index.tsx +++ b/tasker-client/src/app/components/ModalNewTask/index.tsx @@ -23,7 +23,14 @@ const ModalNewTask = ({ isOpen, onClose, id = null }: Props) => { const [projectId, setProjectId] = useState(""); const handleSubmit = async () => { - if (!title || !authorUserId || !(id !== null || projectId)) return; + console.log(title, authorUserId, id, projectId); + + console.log("Creating task 1.."); + if ( + !(title && authorUserId && assignedUserId && (id !== null || projectId)) + ) + return; + console.log("Creating task 2..."); const formattedStartDate = formatISO(new Date(startDate), { representation: "complete", @@ -40,14 +47,17 @@ const ModalNewTask = ({ isOpen, onClose, id = null }: Props) => { tags, startDate: formattedStartDate, dueDate: formattedDueDate, - authorUserId: parseInt(authorUserId), - assignedUserId: parseInt(assignedUserId), - projectId: id !== null ? Number(id) : Number(projectId), + authorUserId: authorUserId, + assignedUserId: assignedUserId, + projectId: id !== null ? id : projectId, }); }; const isFormValid = () => { - return title && authorUserId && !(id !== null || projectId); + console.log(title, authorUserId, id, projectId); + return ( + title && authorUserId && assignedUserId && (id !== null || projectId) + ); }; const selectStyles = @@ -87,7 +97,7 @@ const ModalNewTask = ({ isOpen, onClose, id = null }: Props) => { } > - + diff --git a/tasker-client/src/app/components/Sidebar/index.tsx b/tasker-client/src/app/components/Sidebar/index.tsx index 419cf34..928b23b 100644 --- a/tasker-client/src/app/components/Sidebar/index.tsx +++ b/tasker-client/src/app/components/Sidebar/index.tsx @@ -93,7 +93,6 @@ const Sidebar = () => {