diff --git a/package-lock.json b/package-lock.json index 2c843eedf..514042ae8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,10 +7,15 @@ "": { "name": "Panora", "version": "1.0.0", + "hasInstallScript": true, "license": "ISC", "dependencies": { "@changesets/cli": "^2.26.2", + "@nestjs/common": "^10.3.10", + "axios": "^1.7.2", "gitmoji-cli": "^9.0.0", + "optional": "^0.1.4", + "sharp": "^0.33.2", "turbo": "^1.10.16" }, "devDependencies": { @@ -19,7 +24,7 @@ "lint-staged": "^15.0.2" }, "engines": { - "node": ">=16.14.2" + "node": "20.9.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -286,6 +291,15 @@ "prettier": "^2.7.1" } }, + "node_modules/@emnapi/runtime": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz", + "integrity": "sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -393,6 +407,437 @@ "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz", + "integrity": "sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.2" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.4.tgz", + "integrity": "sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.2" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.2.tgz", + "integrity": "sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "macos": ">=11", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.2.tgz", + "integrity": "sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "macos": ">=10.13", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.2.tgz", + "integrity": "sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.2.tgz", + "integrity": "sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.2.tgz", + "integrity": "sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.2.tgz", + "integrity": "sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.2.tgz", + "integrity": "sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.2.tgz", + "integrity": "sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.4.tgz", + "integrity": "sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.2" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.4.tgz", + "integrity": "sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.2" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.4.tgz", + "integrity": "sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.31", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.2" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.4.tgz", + "integrity": "sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.2" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.4.tgz", + "integrity": "sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.2" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.4.tgz", + "integrity": "sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.2" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.4.tgz", + "integrity": "sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==", + "cpu": [ + "wasm32" + ], + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.1.1" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.4.tgz", + "integrity": "sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.4.tgz", + "integrity": "sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@ljharb/through": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.11.tgz", @@ -404,6 +849,14 @@ "node": ">= 0.4" } }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "engines": { + "node": ">=8" + } + }, "node_modules/@manypkg/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz", @@ -459,6 +912,34 @@ "node": ">=6 <7 || >=8" } }, + "node_modules/@nestjs/common": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.3.10.tgz", + "integrity": "sha512-H8k0jZtxk1IdtErGDmxFRy0PfcOAUg41Prrqpx76DQusGGJjsaovs1zjXVD1rZWaVYchfT1uczJ6L4Kio10VNg==", + "dependencies": { + "iterare": "1.2.1", + "tslib": "2.6.3", + "uid": "2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "class-transformer": "*", + "class-validator": "*", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -814,6 +1295,11 @@ "node": ">=4" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/atomically": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/atomically/-/atomically-2.0.2.tgz", @@ -834,6 +1320,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1355,6 +1851,18 @@ "node": ">=0.8" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -1368,12 +1876,48 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "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==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", @@ -1713,6 +2257,14 @@ "node": ">= 14" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/detect-indent": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", @@ -1721,6 +2273,14 @@ "node": ">=8" } }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "engines": { + "node": ">=8" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -2457,6 +3017,25 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "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", @@ -2465,6 +3044,19 @@ "is-callable": "^1.1.3" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/form-data-encoder": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", @@ -3766,6 +4358,14 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "node_modules/iterare": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", + "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4380,6 +4980,25 @@ "node": ">=8.6" } }, + "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==", + "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==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", @@ -4624,6 +5243,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/optional": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/optional/-/optional-0.1.4.tgz", + "integrity": "sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==" + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -5299,6 +5923,12 @@ "node": ">=8" } }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "peer": true + }, "node_modules/regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", @@ -5571,12 +6201,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { "semver": "bin/semver.js" }, @@ -5598,17 +6225,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -5641,6 +6257,45 @@ "node": ">= 0.4" } }, + "node_modules/sharp": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.4.tgz", + "integrity": "sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==", + "hasInstallScript": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.0" + }, + "engines": { + "libvips": ">=8.15.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.4", + "@img/sharp-darwin-x64": "0.33.4", + "@img/sharp-libvips-darwin-arm64": "1.0.2", + "@img/sharp-libvips-darwin-x64": "1.0.2", + "@img/sharp-libvips-linux-arm": "1.0.2", + "@img/sharp-libvips-linux-arm64": "1.0.2", + "@img/sharp-libvips-linux-s390x": "1.0.2", + "@img/sharp-libvips-linux-x64": "1.0.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.2", + "@img/sharp-libvips-linuxmusl-x64": "1.0.2", + "@img/sharp-linux-arm": "0.33.4", + "@img/sharp-linux-arm64": "0.33.4", + "@img/sharp-linux-s390x": "0.33.4", + "@img/sharp-linux-x64": "0.33.4", + "@img/sharp-linuxmusl-arm64": "0.33.4", + "@img/sharp-linuxmusl-x64": "0.33.4", + "@img/sharp-wasm32": "0.33.4", + "@img/sharp-win32-ia32": "0.33.4", + "@img/sharp-win32-x64": "0.33.4" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5684,6 +6339,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -6155,9 +6823,9 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/tty-table": { "version": "4.2.3", @@ -6423,6 +7091,17 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/uid": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", + "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", + "dependencies": { + "@lukeed/csprng": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/uint8array-extras": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-0.3.0.tgz", @@ -6765,11 +7444,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/yaml": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", @@ -7075,6 +7749,15 @@ "prettier": "^2.7.1" } }, + "@emnapi/runtime": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz", + "integrity": "sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==", + "optional": true, + "requires": { + "tslib": "^2.4.0" + } + }, "@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -7153,6 +7836,147 @@ "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, + "@img/sharp-darwin-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz", + "integrity": "sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==", + "optional": true, + "requires": { + "@img/sharp-libvips-darwin-arm64": "1.0.2" + } + }, + "@img/sharp-darwin-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.4.tgz", + "integrity": "sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==", + "optional": true, + "requires": { + "@img/sharp-libvips-darwin-x64": "1.0.2" + } + }, + "@img/sharp-libvips-darwin-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.2.tgz", + "integrity": "sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==", + "optional": true + }, + "@img/sharp-libvips-darwin-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.2.tgz", + "integrity": "sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==", + "optional": true + }, + "@img/sharp-libvips-linux-arm": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.2.tgz", + "integrity": "sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==", + "optional": true + }, + "@img/sharp-libvips-linux-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.2.tgz", + "integrity": "sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==", + "optional": true + }, + "@img/sharp-libvips-linux-s390x": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.2.tgz", + "integrity": "sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==", + "optional": true + }, + "@img/sharp-libvips-linux-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.2.tgz", + "integrity": "sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==", + "optional": true + }, + "@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.2.tgz", + "integrity": "sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==", + "optional": true + }, + "@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.2.tgz", + "integrity": "sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==", + "optional": true + }, + "@img/sharp-linux-arm": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.4.tgz", + "integrity": "sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-arm": "1.0.2" + } + }, + "@img/sharp-linux-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.4.tgz", + "integrity": "sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-arm64": "1.0.2" + } + }, + "@img/sharp-linux-s390x": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.4.tgz", + "integrity": "sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-s390x": "1.0.2" + } + }, + "@img/sharp-linux-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.4.tgz", + "integrity": "sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-x64": "1.0.2" + } + }, + "@img/sharp-linuxmusl-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.4.tgz", + "integrity": "sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==", + "optional": true, + "requires": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.2" + } + }, + "@img/sharp-linuxmusl-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.4.tgz", + "integrity": "sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==", + "optional": true, + "requires": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.2" + } + }, + "@img/sharp-wasm32": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.4.tgz", + "integrity": "sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==", + "optional": true, + "requires": { + "@emnapi/runtime": "^1.1.1" + } + }, + "@img/sharp-win32-ia32": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.4.tgz", + "integrity": "sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==", + "optional": true + }, + "@img/sharp-win32-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.4.tgz", + "integrity": "sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==", + "optional": true + }, "@ljharb/through": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.11.tgz", @@ -7161,6 +7985,11 @@ "call-bind": "^1.0.2" } }, + "@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==" + }, "@manypkg/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz", @@ -7214,6 +8043,16 @@ } } }, + "@nestjs/common": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.3.10.tgz", + "integrity": "sha512-H8k0jZtxk1IdtErGDmxFRy0PfcOAUg41Prrqpx76DQusGGJjsaovs1zjXVD1rZWaVYchfT1uczJ6L4Kio10VNg==", + "requires": { + "iterare": "1.2.1", + "tslib": "2.6.3", + "uid": "2.0.2" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -7476,6 +8315,11 @@ "tslib": "^2.0.1" } }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "atomically": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/atomically/-/atomically-2.0.2.tgz", @@ -7490,6 +8334,16 @@ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" }, + "axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "requires": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -7826,6 +8680,30 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" }, + "color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "requires": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "dependencies": { + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -7839,12 +8717,29 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", @@ -8091,11 +8986,21 @@ "esprima": "^4.0.1" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, "detect-indent": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==" }, + "detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==" + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -8629,6 +9534,11 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, + "follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -8637,6 +9547,16 @@ "is-callable": "^1.1.3" } }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "form-data-encoder": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", @@ -9488,6 +10408,11 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "iterare": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", + "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -9917,6 +10842,19 @@ "picomatch": "^2.3.1" } }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "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==", + "requires": { + "mime-db": "1.52.0" + } + }, "mimic-fn": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", @@ -10073,6 +11011,11 @@ "mimic-fn": "^4.0.0" } }, + "optional": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/optional/-/optional-0.1.4.tgz", + "integrity": "sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==" + }, "optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -10531,6 +11474,12 @@ "strip-indent": "^3.0.0" } }, + "reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "peer": true + }, "regenerator-runtime": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", @@ -10707,22 +11656,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - } - } + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==" }, "semver-diff": { "version": "4.0.0", @@ -10758,6 +11694,35 @@ "has-property-descriptors": "^1.0.0" } }, + "sharp": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.4.tgz", + "integrity": "sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==", + "requires": { + "@img/sharp-darwin-arm64": "0.33.4", + "@img/sharp-darwin-x64": "0.33.4", + "@img/sharp-libvips-darwin-arm64": "1.0.2", + "@img/sharp-libvips-darwin-x64": "1.0.2", + "@img/sharp-libvips-linux-arm": "1.0.2", + "@img/sharp-libvips-linux-arm64": "1.0.2", + "@img/sharp-libvips-linux-s390x": "1.0.2", + "@img/sharp-libvips-linux-x64": "1.0.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.2", + "@img/sharp-libvips-linuxmusl-x64": "1.0.2", + "@img/sharp-linux-arm": "0.33.4", + "@img/sharp-linux-arm64": "0.33.4", + "@img/sharp-linux-s390x": "0.33.4", + "@img/sharp-linux-x64": "0.33.4", + "@img/sharp-linuxmusl-arm64": "0.33.4", + "@img/sharp-linuxmusl-x64": "0.33.4", + "@img/sharp-wasm32": "0.33.4", + "@img/sharp-win32-ia32": "0.33.4", + "@img/sharp-win32-x64": "0.33.4", + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.0" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -10786,6 +11751,21 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==" }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -11148,9 +12128,9 @@ "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==" }, "tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "tty-table": { "version": "4.2.3", @@ -11325,6 +12305,14 @@ "is-typedarray": "^1.0.0" } }, + "uid": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", + "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", + "requires": { + "@lukeed/csprng": "^1.0.0" + } + }, "uint8array-extras": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-0.3.0.tgz", @@ -11576,11 +12564,6 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "yaml": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", diff --git a/package.json b/package.json index 69d51acc2..d7abccc17 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,8 @@ }, "dependencies": { "@changesets/cli": "^2.26.2", + "@nestjs/common": "^10.3.10", + "axios": "^1.7.2", "gitmoji-cli": "^9.0.0", "optional": "^0.1.4", "sharp": "^0.33.2", diff --git a/packages/api/src/ticketing/account/services/wrike/index.ts b/packages/api/src/ticketing/account/services/wrike/index.ts new file mode 100644 index 000000000..6347a8c49 --- /dev/null +++ b/packages/api/src/ticketing/account/services/wrike/index.ts @@ -0,0 +1,66 @@ +import { EncryptionService } from '@@core/encryption/encryption.service'; +import { LoggerService } from '@@core/logger/logger.service'; +import { PrismaService } from '@@core/prisma/prisma.service'; +import { Injectable } from '@nestjs/common'; +import { IAccountService } from '@ticketing/account/types'; +import { ServiceRegistry } from '../registry.service'; +import { TicketingObject } from '@ticketing/@lib/@types'; +import axios from 'axios'; +import { ApiResponse } from '@@core/utils/types'; +import { ActionType, handle3rdPartyServiceError } from '@@core/utils/errors'; +import { WrikeAccountOutput } from './types'; + + +@Injectable() +export class WrikeService implements IAccountService { + constructor( + private prisma: PrismaService, + private logger: LoggerService, + private cryptoService: EncryptionService, + private registry: ServiceRegistry, + ) { + this.logger.setContext( + TicketingObject.account.toUpperCase() + ':' + WrikeService.name, + ); + this.registry.registerService('wrike', this); + } + + async syncAccounts( + linkedUserId: string, + remote_account_id?: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'wrike', + vertical: 'ticketing', + }, + }); + + const resp = await axios.get(`${connection.account_url}/accounts`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }); + this.logger.log(`Synced wrike accounts !`); + + return { + data: resp.data._results, + message: 'Wrike accounts retrieved', + statusCode: 200, + }; + } catch (error) { + handle3rdPartyServiceError( + error, + this.logger, + 'wrike', + TicketingObject.account, + ActionType.GET, + ); + } + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/account/services/wrike/mappers.ts b/packages/api/src/ticketing/account/services/wrike/mappers.ts new file mode 100644 index 000000000..b131a6888 --- /dev/null +++ b/packages/api/src/ticketing/account/services/wrike/mappers.ts @@ -0,0 +1,60 @@ +import { MappersRegistry } from '@@core/utils/registry/mappings.registry'; +import { Utils } from '@ticketing/@lib/@utils'; +import { Injectable } from '@nestjs/common'; +import { IAccountMapper } from '@ticketing/account/types'; +import { UnifiedAccountInput, UnifiedAccountOutput } from '@ticketing/account/types/model.unified'; +import { WrikeAccountInput, WrikeAccountOutput } from './types'; + +@Injectable() +export class WrikeAccountMapper implements IAccountMapper { + constructor(private mappersRegistry: MappersRegistry, private utils: Utils) { + this.mappersRegistry.registerService('ticketing', 'account', 'wrike', this); + } + desunify( + source: UnifiedAccountInput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): WrikeAccountInput { + return; + } + + unify( + source: WrikeAccountOutput | WrikeAccountOutput[], + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedAccountOutput | UnifiedAccountOutput[] { + const sourcesArray = Array.isArray(source) ? source : [source]; + + return sourcesArray.map((account) => + this.mapSingleAccountToUnified(account, customFieldMappings), + ); + } + + private mapSingleAccountToUnified( + account: WrikeAccountOutput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedAccountOutput { + const field_mappings: { [key: string]: any } = {}; + if (customFieldMappings) { + for (const mapping of customFieldMappings) { + field_mappings[mapping.slug] = account.custom_fields[mapping.remote_id]; + } + } + + const unifiedAccount: UnifiedAccountOutput = { + remote_id: account.id, + name: account.name, + domains: account.domains.flat(), + field_mappings: field_mappings, + }; + + return unifiedAccount; + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/account/services/wrike/types.ts b/packages/api/src/ticketing/account/services/wrike/types.ts new file mode 100644 index 000000000..b59e60ec9 --- /dev/null +++ b/packages/api/src/ticketing/account/services/wrike/types.ts @@ -0,0 +1,25 @@ +export type WrikeAccountInput = { + id: string; + }; + + export type WrikeAccountOutput = { + _links: { + self: string; + related: { + contacts: string; + }; + }; + id: string; + name: string; + logo_url: string; + description: string; + domains: string[][]; + external_id: number; + custom_fields: { + employees: number; + headquarters: string; + }; + created_at: number; + updated_at: number; + }; + \ No newline at end of file diff --git a/packages/api/src/ticketing/attachment/services/wrike/mappers.ts b/packages/api/src/ticketing/attachment/services/wrike/mappers.ts new file mode 100644 index 000000000..e12e42354 --- /dev/null +++ b/packages/api/src/ticketing/attachment/services/wrike/mappers.ts @@ -0,0 +1,56 @@ +import { MappersRegistry } from "@@core/utils/registry/mappings.registry"; +import { Injectable } from "@nestjs/common"; +import { Utils } from "@ticketing/@lib/@utils"; +import { IAttachmentMapper } from "@ticketing/attachment/types"; +import { UnifiedAttachmentInput, UnifiedAttachmentOutput } from "@ticketing/attachment/types/model.unified"; +import { WrikeAttachmentOutput } from "./types"; + +@Injectable() +export class WrikeAttachmentMapper implements IAttachmentMapper { + constructor(private mappersRegistry: MappersRegistry, private utils: Utils) { + this.mappersRegistry.registerService( + 'ticketing', + 'attachment', + 'wrike', + this, + ); + } + async desunify( + source: UnifiedAttachmentInput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): Promise { + return; + } + + unify( + source: WrikeAttachmentOutput | WrikeAttachmentOutput[], + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedAttachmentOutput | UnifiedAttachmentOutput[] { + if (!Array.isArray(source)) { + return this.mapSingleAttachmentToUnified(source, customFieldMappings); + } + return source.map((attachment) => + this.mapSingleAttachmentToUnified(attachment, customFieldMappings), + ); + } + + private mapSingleAttachmentToUnified( + attachment: WrikeAttachmentOutput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedAttachmentOutput { + return { + remote_id: attachment.id, + file_name: attachment.filename, + file_url: attachment.url, + }; + } +} diff --git a/packages/api/src/ticketing/attachment/services/wrike/types.ts b/packages/api/src/ticketing/attachment/services/wrike/types.ts new file mode 100644 index 000000000..e8ff4c290 --- /dev/null +++ b/packages/api/src/ticketing/attachment/services/wrike/types.ts @@ -0,0 +1,13 @@ +export type WrikeAttachmentOutput = { + id: string; + filename: string; + url: string; + content_type: string; + size: number; + metadata: AttachmentMetadata; +}; + +type AttachmentMetadata = { + is_inline: boolean; + cid: string; +}; diff --git a/packages/api/src/ticketing/collection/services/wrike/index.ts b/packages/api/src/ticketing/collection/services/wrike/index.ts new file mode 100644 index 000000000..1c751c23a --- /dev/null +++ b/packages/api/src/ticketing/collection/services/wrike/index.ts @@ -0,0 +1,64 @@ +import { EncryptionService } from "@@core/encryption/encryption.service"; +import { LoggerService } from "@@core/logger/logger.service"; +import { PrismaService } from "@@core/prisma/prisma.service"; +import { Injectable } from "@nestjs/common"; +import { ICollectionService } from "@ticketing/collection/types"; +import { ServiceRegistry } from "../registry.service"; +import { TicketingObject } from "@ticketing/@lib/@types"; +import { ApiResponse } from "@@core/utils/types"; +import axios from "axios"; +import { ActionType, handle3rdPartyServiceError } from "@@core/utils/errors"; +import { WrikeCollectionOutput } from "./types"; + +@Injectable() +export class WrikeService implements ICollectionService { + constructor( + private prisma: PrismaService, + private logger: LoggerService, + private cryptoService: EncryptionService, + private registry: ServiceRegistry, + ) { + this.logger.setContext( + TicketingObject.collection.toUpperCase() + ':' + WrikeService.name, + ); + this.registry.registerService('wrike', this); + } + + async syncCollections( + linkedUserId: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'wrike', + vertical: 'ticketing', + }, + }); + + const resp = await axios.get(`${connection.account_url}/project/search`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }); + this.logger.log(`Synced wrike collections !`); + + return { + data: resp.data, + message: 'Wrike collections retrieved', + statusCode: 200, + }; + } catch (error) { + handle3rdPartyServiceError( + error, + this.logger, + 'wrike', + TicketingObject.collection, + ActionType.GET, + ); + } + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/collection/services/wrike/mappers.ts b/packages/api/src/ticketing/collection/services/wrike/mappers.ts new file mode 100644 index 000000000..aefff1565 --- /dev/null +++ b/packages/api/src/ticketing/collection/services/wrike/mappers.ts @@ -0,0 +1,58 @@ +import { MappersRegistry } from "@@core/utils/registry/mappings.registry"; +import { Injectable } from "@nestjs/common"; +import { Utils } from "@ticketing/@lib/@utils"; +import { ICollectionMapper } from "@ticketing/collection/types"; +import { UnifiedCollectionInput, UnifiedCollectionOutput } from "@ticketing/collection/types/model.unified"; +import { WrikeCollectionInput, WrikeCollectionOutput } from "./types"; + +@Injectable() +export class WrikeCollectionMapper implements ICollectionMapper { + constructor(private mappersRegistry: MappersRegistry, private utils: Utils) { + this.mappersRegistry.registerService( + 'ticketing', + 'collection', + 'wrike', + this, + ); + } + desunify( + source: UnifiedCollectionInput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): WrikeCollectionInput { + return; + } + + unify( + source: WrikeCollectionOutput | WrikeCollectionOutput[], + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedCollectionOutput | UnifiedCollectionOutput[] { + const sourcesArray = Array.isArray(source) ? source : [source]; + + return sourcesArray.map((collection) => + this.mapSingleCollectionToUnified(collection, customFieldMappings), + ); + } + + private mapSingleCollectionToUnified( + collection: WrikeCollectionOutput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedCollectionOutput { + const unifiedCollection: UnifiedCollectionOutput = { + remote_id: collection.id, + name: collection.name, + description: collection.name, + collection_type: 'PROJECT', + }; + + return unifiedCollection; + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/collection/services/wrike/types.ts b/packages/api/src/ticketing/collection/services/wrike/types.ts new file mode 100644 index 000000000..0cda6b82f --- /dev/null +++ b/packages/api/src/ticketing/collection/services/wrike/types.ts @@ -0,0 +1,33 @@ +export type WrikeCollectionOutput = { + avatarUrls: AvatarUrls; + id: string; + insight: Insight; + key: string; + name: string; + projectCategory: ProjectCategory; + self: string; + simplified: boolean; + style: string; + }; + + type AvatarUrls = { + '16x16': string; + '24x24': string; + '32x32': string; + '48x48': string; + }; + + type Insight = { + lastIssueUpdateTime: string; + totalIssueCount: number; + }; + + type ProjectCategory = { + description: string; + id: string; + name: string; + self: string; + }; + + export type WrikeCollectionInput = null; + \ No newline at end of file diff --git a/packages/api/src/ticketing/comment/services/wrike/index.ts b/packages/api/src/ticketing/comment/services/wrike/index.ts new file mode 100644 index 000000000..a5d31e23e --- /dev/null +++ b/packages/api/src/ticketing/comment/services/wrike/index.ts @@ -0,0 +1,174 @@ +import { EncryptionService } from "@@core/encryption/encryption.service"; +import { LoggerService } from "@@core/logger/logger.service"; +import { PrismaService } from "@@core/prisma/prisma.service"; +import { Injectable } from "@nestjs/common"; +import { ICommentService } from "@ticketing/comment/types"; +import { ServiceRegistry } from "../registry.service"; +import { Utils } from "@ticketing/@lib/@utils"; +import { TicketingObject } from "@ticketing/@lib/@types"; +import { ApiResponse } from "@@core/utils/types"; +import axios from "axios"; +import { ActionType, handle3rdPartyServiceError } from "@@core/utils/errors"; +import { WrikeCommentInput, WrikeCommentOutput } from "./types"; + +@Injectable() +export class WrikeService implements ICommentService { + constructor( + private prisma: PrismaService, + private logger: LoggerService, + private cryptoService: EncryptionService, + private registry: ServiceRegistry, + private utils: Utils, + ) { + this.logger.setContext( + TicketingObject.comment.toUpperCase() + ':' + WrikeService.name, + ); + this.registry.registerService('wrike', this); + } + + async addComment( + commentData: WrikeCommentInput, + linkedUserId: string, + remoteIdTicket: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'wrike', + vertical: 'ticketing', + }, + }); + + let dataBody = commentData; + + const author_id = commentData.author_id; + + if (author_id) { + dataBody = { ...dataBody, author_id: author_id }; + } + + let uploads = []; + const uuids = commentData.attachments; + if (uuids && uuids.length > 0) { + uploads = await Promise.all( + uuids.map(async (uuid) => { + const attachment = await this.prisma.tcg_attachments.findUnique({ + where: { + id_tcg_attachment: uuid, + }, + }); + if (!attachment) { + throw new ReferenceError( + `tcg_attachment not found for uuid ${uuid}`, + ); + } + + return await this.utils.fetchFileStreamFromURL(attachment.file_url); + }), + ); + } + + let resp; + if (uploads.length > 0) { + const formData = new FormData(); + if (author_id) { + formData.append('author_id', author_id); + } + formData.append('body', commentData.body); + uploads.forEach((fileStream, index) => { + formData.append(`attachments[${index}]`, fileStream); + }); + + resp = await axios.post( + `${connection.account_url}/conversations/${remoteIdTicket}/comments`, + formData, + { + headers: { + 'Content-Type': 'multipart/form-data', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }, + ); + } else { + resp = await axios.post( + `${connection.account_url}/conversations/${remoteIdTicket}/comments`, + JSON.stringify(dataBody), + { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }, + ); + } + + return { + data: resp.data, + message: 'Wrike comment created', + statusCode: 201, + }; + } catch (error) { + handle3rdPartyServiceError( + error, + this.logger, + 'wrike', + TicketingObject.comment, + ActionType.POST, + ); + } + } + async syncComments( + linkedUserId: string, + id_ticket: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'wrike', + vertical: 'ticketing', + }, + }); + + const ticket = await this.prisma.tcg_tickets.findUnique({ + where: { + id_tcg_ticket: id_ticket, + }, + select: { + remote_id: true, + }, + }); + + const resp = await axios.get( + `${connection.account_url}/conversations/${ticket.remote_id}/comments`, + { + headers: { + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }, + ); + this.logger.log(`Synced wrike comments !`); + + return { + data: resp.data._results, + message: 'Wrike comments retrieved', + statusCode: 200, + }; + } catch (error) { + handle3rdPartyServiceError( + error, + this.logger, + 'wrike', + TicketingObject.comment, + ActionType.GET, + ); + } + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/comment/services/wrike/mappers.ts b/packages/api/src/ticketing/comment/services/wrike/mappers.ts new file mode 100644 index 000000000..3c0d116dc --- /dev/null +++ b/packages/api/src/ticketing/comment/services/wrike/mappers.ts @@ -0,0 +1,97 @@ +import { MappersRegistry } from "@@core/utils/registry/mappings.registry"; +import { CoreUnification } from "@@core/utils/services/core.service"; +import { Injectable } from "@nestjs/common"; +import { Utils } from "@ticketing/@lib/@utils"; +import { ICommentMapper } from "@ticketing/comment/types"; +import { UnifiedCommentInput, UnifiedCommentOutput } from "@ticketing/comment/types/model.unified"; +import { WrikeCommentInput, WrikeCommentOutput } from "./types"; +import { OriginalAttachmentOutput } from '@@core/utils/types/original/original.ticketing'; +import { TicketingObject } from "@ticketing/@lib/@types"; +import { UnifiedAttachmentOutput } from "@ticketing/attachment/types/model.unified"; + +@Injectable() +export class WrikeCommentMapper implements ICommentMapper { + constructor( + private mappersRegistry: MappersRegistry, + private utils: Utils, + private coreUnification: CoreUnification, + ) { + this.mappersRegistry.registerService('ticketing', 'comment', 'wrike', this); + } + async desunify( + source: UnifiedCommentInput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): Promise { + const result: WrikeCommentInput = { + body: source.body, + author_id: await this.utils.getUserRemoteIdFromUuid(source.user_id), + attachments: source.attachments, + }; + return result; + } + + async unify( + source: WrikeCommentOutput | WrikeCommentOutput[], + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): Promise { + if (!Array.isArray(source)) { + return await this.mapSingleCommentToUnified(source, customFieldMappings); + } + return Promise.all( + source.map((comment) => + this.mapSingleCommentToUnified(comment, customFieldMappings), + ), + ); + } + + private async mapSingleCommentToUnified( + comment: WrikeCommentOutput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): Promise { + let opts; + + if (comment.attachments && comment.attachments.length > 0) { + const unifiedObject = (await this.coreUnification.unify< + OriginalAttachmentOutput[] + >({ + sourceObject: comment.attachments, + targetType: TicketingObject.attachment, + providerName: 'wrike', + vertical: 'ticketing', + customFieldMappings: [], + })) as UnifiedAttachmentOutput[]; + + opts = { ...opts, attachments: unifiedObject }; + } + + if (comment.author.id) { + const user_id = await this.utils.getUserUuidFromRemoteId( + String(comment.author.id), + 'wrike', + ); + + if (user_id) { + opts = { user_id: user_id, creator_type: 'USER' }; + } + } + + const res = { + body: comment.body, + ...opts, + }; + + return { + remote_id: comment.id, + ...res, + }; + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/comment/services/wrike/types.ts b/packages/api/src/ticketing/comment/services/wrike/types.ts new file mode 100644 index 000000000..5b7ab5f35 --- /dev/null +++ b/packages/api/src/ticketing/comment/services/wrike/types.ts @@ -0,0 +1,51 @@ +export type WrikeCommentInput = { + author_id?: string; + body: string; + attachments?: string[]; + }; + + export type WrikeCommentOutput = { + _links: Links; + id: string; + author?: Author; + body: string; + posted_at: number; + attachments?: Attachment[]; + }; + + type Links = { + self: string; + related?: Record; + }; + + type CustomFields = { + [key: string]: string | boolean | number; + }; + + type Author = { + _links: Links; + id: string; + email: string; + username: string; + first_name: string; + last_name: string; + is_admin: boolean; + is_available: boolean; + is_blocked: boolean; + custom_fields: CustomFields; + }; + + type AttachmentMetadata = { + is_inline: boolean; + cid: string; + }; + + type Attachment = { + id: string; + filename: string; + url: string; + content_type: string; + size: number; + metadata: AttachmentMetadata; + }; + \ No newline at end of file diff --git a/packages/api/src/ticketing/contact/services/wrike/index.ts b/packages/api/src/ticketing/contact/services/wrike/index.ts new file mode 100644 index 000000000..4fa6cc9cd --- /dev/null +++ b/packages/api/src/ticketing/contact/services/wrike/index.ts @@ -0,0 +1,72 @@ +import { Injectable } from '@nestjs/common'; +import { EncryptionService } from "@@core/encryption/encryption.service"; +import { LoggerService } from "@@core/logger/logger.service"; +import { PrismaService } from "@@core/prisma/prisma.service"; +import { ServiceRegistry } from "../registry.service"; +import { TicketingObject } from '@ticketing/@lib/@types'; +import { ApiResponse } from '@@core/utils/types'; +import { IContactService } from '@ticketing/contact/types'; +import axios from 'axios'; +import { WrikeContactOutput } from './types'; +import { ActionType, handle3rdPartyServiceError } from '@@core/utils/errors'; + +@Injectable() +export class WrikeService implements IContactService { + constructor( + private prisma: PrismaService, + private logger: LoggerService, + private cryptoService: EncryptionService, + private registry: ServiceRegistry, + ) { + this.logger.setContext( + TicketingObject.contact.toUpperCase() + ':' + WrikeService.name, + ); + this.registry.registerService('wrike', this); + } + + + async syncContacts( + linkedUserId: string, + remote_account_id: string, + ): Promise> { + try { + if (!remote_account_id) + throw new ReferenceError('remote account id not found'); + + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'wrike', + vertical: 'ticketing', + }, + }); + + const resp = await axios.get( + `${connection.account_url}/accounts/${remote_account_id}/contacts`, + { + headers: { + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }, + ); + this.logger.log(`Synced wrike contacts !`); + + return { + data: resp.data._results, + message: 'Wrike contacts retrieved', + statusCode: 200, + }; + } catch (error) { + throw error; + // handle3rdPartyServiceError( + // error, + // this.logger, + // 'wrike', + // TicketingObject.contact, + // ActionType.GET, + // ); + } + } +} diff --git a/packages/api/src/ticketing/contact/services/wrike/mappers.ts b/packages/api/src/ticketing/contact/services/wrike/mappers.ts new file mode 100644 index 000000000..9b382c60b --- /dev/null +++ b/packages/api/src/ticketing/contact/services/wrike/mappers.ts @@ -0,0 +1,68 @@ +import { IContactMapper } from '@ticketing/contact/types'; +import { Injectable } from '@nestjs/common'; +import { MappersRegistry } from '@@core/utils/registry/mappings.registry'; +import { WrikeContactInput, WrikeContactOutput } from './types'; +import { Utils } from '@ticketing/@lib/@utils'; +import { UnifiedContactInput, UnifiedContactOutput } from '@ticketing/contact/types/model.unified'; + + +@Injectable() +export class WrikeContactMapper implements IContactMapper { + constructor(private mappersRegistry: MappersRegistry, private utils: Utils) { + this.mappersRegistry.registerService('ticketing', 'contact', 'wrike', this); + } + desunify( + source: UnifiedContactInput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): WrikeContactInput { + return; + } + + unify( + source: WrikeContactOutput | WrikeContactOutput[], + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedContactOutput | UnifiedContactOutput[] { + const sourcesArray = Array.isArray(source) ? source : [source]; + + return sourcesArray.map((contact) => + this.mapSingleContactToUnified(contact, customFieldMappings), + ); + } + + private mapSingleContactToUnified( + contact: WrikeContactOutput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedContactOutput { + const field_mappings: { [key: string]: any } = {}; + if (customFieldMappings) { + for (const mapping of customFieldMappings) { + field_mappings[mapping.slug] = contact.custom_fields[mapping.remote_id]; + } + } + const emailHandle = contact.handles.find( + (handle) => handle.source === 'email', + ); + const phoneHandle = contact.handles.find( + (handle) => handle.source === 'phone', + ); + + const unifiedContact: UnifiedContactOutput = { + remote_id: contact.id, + name: contact.name, + email_address: emailHandle.handle || '', + phone_number: phoneHandle.handle || '', + field_mappings: field_mappings, + }; + + return unifiedContact; + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/contact/services/wrike/types.ts b/packages/api/src/ticketing/contact/services/wrike/types.ts new file mode 100644 index 000000000..7f726ebbe --- /dev/null +++ b/packages/api/src/ticketing/contact/services/wrike/types.ts @@ -0,0 +1,40 @@ +export type WrikeContactInput = { + id: string; +}; + +export type WrikeContactOutput = { + _links: ContactLink; + id: string; + name: string; + description: string; + avatar_url: string; + is_spammer: boolean; + links: string[][]; + groups: Group[]; + handles: Handle[]; + custom_fields: { + [key: string]: string | boolean; + }; + is_private: boolean; +} + +type ContactLink = { + self: string; + related: { + notes?: string; + conversations?: string; + owner?: string | null; + }; +}; + +type Group = { + _links: ContactLink; + id: string; + name: string; + is_private: boolean; +}; + +type Handle = { + handle: string; + source: string; +}; \ No newline at end of file diff --git a/packages/api/src/ticketing/tag/services/wrike/index.ts b/packages/api/src/ticketing/tag/services/wrike/index.ts new file mode 100644 index 000000000..2ecfa44aa --- /dev/null +++ b/packages/api/src/ticketing/tag/services/wrike/index.ts @@ -0,0 +1,78 @@ +import { EncryptionService } from "@@core/encryption/encryption.service"; +import { LoggerService } from "@@core/logger/logger.service"; +import { PrismaService } from "@@core/prisma/prisma.service"; +import { Injectable } from "@nestjs/common"; +import { ITagService } from "@ticketing/tag/types"; +import { ServiceRegistry } from "../registry.service"; +import { TicketingObject } from "@ticketing/@lib/@types"; +import { ApiResponse } from "@@core/utils/types"; +import axios from "axios"; +import { ActionType, handle3rdPartyServiceError } from "@@core/utils/errors"; +import { WrikeTagOutput } from "./types"; + +@Injectable() +export class WrikeService implements ITagService { + constructor( + private prisma: PrismaService, + private logger: LoggerService, + private cryptoService: EncryptionService, + private registry: ServiceRegistry, + ) { + this.logger.setContext( + TicketingObject.tag.toUpperCase() + ':' + WrikeService.name, + ); + this.registry.registerService('wrike', this); + } + + async syncTags( + linkedUserId: string, + id_ticket: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'wrike', + vertical: 'ticketing', + }, + }); + + const ticket = await this.prisma.tcg_tickets.findUnique({ + where: { + id_tcg_ticket: id_ticket, + }, + select: { + remote_id: true, + }, + }); + + const resp = await axios.get(`${connection.account_url}/conversations`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }); + this.logger.log(`Synced wrike tags !`); + + const conversation = resp.data._results.find( + (c) => c.id === ticket.remote_id, + ); + + return { + data: conversation.tags, + message: 'Wrike tags retrieved', + statusCode: 200, + }; + } catch (error) { + handle3rdPartyServiceError( + error, + this.logger, + 'wrike', + TicketingObject.tag, + ActionType.GET, + ); + } + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/tag/services/wrike/mappers.ts b/packages/api/src/ticketing/tag/services/wrike/mappers.ts new file mode 100644 index 000000000..a26b71378 --- /dev/null +++ b/packages/api/src/ticketing/tag/services/wrike/mappers.ts @@ -0,0 +1,52 @@ +import { MappersRegistry } from "@@core/utils/registry/mappings.registry"; +import { Injectable } from "@nestjs/common"; +import { Utils } from "@ticketing/@lib/@utils"; +import { ITagMapper } from "@ticketing/tag/types"; +import { UnifiedTagInput, UnifiedTagOutput } from "@ticketing/tag/types/model.unified"; +import { WrikeTagInput, WrikeTagOutput } from "./types"; + +@Injectable() +export class WrikeTagMapper implements ITagMapper { + constructor(private mappersRegistry: MappersRegistry, private utils: Utils) { + this.mappersRegistry.registerService('ticketing', 'tag', 'wrike', this); + } + desunify( + source: UnifiedTagInput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): WrikeTagInput { + return; + } + + unify( + source: WrikeTagOutput | WrikeTagOutput[], + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedTagOutput | UnifiedTagOutput[] { + // If the source is not an array, convert it to an array for mapping + const sourcesArray = Array.isArray(source) ? source : [source]; + + return sourcesArray.map((tag) => + this.mapSingleTagToUnified(tag, customFieldMappings), + ); + } + + private mapSingleTagToUnified( + tag: WrikeTagOutput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedTagOutput { + const unifiedTag: UnifiedTagOutput = { + remote_id: tag.id, + name: tag.name, + }; + + return unifiedTag; + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/tag/services/wrike/types.ts b/packages/api/src/ticketing/tag/services/wrike/types.ts new file mode 100644 index 000000000..a0a355fe8 --- /dev/null +++ b/packages/api/src/ticketing/tag/services/wrike/types.ts @@ -0,0 +1,26 @@ +export type WrikeTagInput = { + id: string; + }; + + export type WrikeTagOutput = { + _links: TagLink; + id: string; + name: string; + description: string; + highlight: string | null; + is_private: boolean; + is_visible_in_conversation_lists: boolean; + created_at: number; + updated_at: number; + }; + + interface TagLink { + self: string; + related: { + conversations: string; + owner: string; + parent_tag: string; + children: string; + }; + } + \ No newline at end of file diff --git a/packages/api/src/ticketing/team/services/wrike/index.ts b/packages/api/src/ticketing/team/services/wrike/index.ts new file mode 100644 index 000000000..77ac42c63 --- /dev/null +++ b/packages/api/src/ticketing/team/services/wrike/index.ts @@ -0,0 +1,64 @@ +import { EncryptionService } from "@@core/encryption/encryption.service"; +import { LoggerService } from "@@core/logger/logger.service"; +import { PrismaService } from "@@core/prisma/prisma.service"; +import { Injectable } from "@nestjs/common"; +import { ITeamService } from "@ticketing/team/types"; +import { ServiceRegistry } from "../registry.service"; +import { TicketingObject } from "@ticketing/@lib/@types"; +import { ApiResponse } from "@@core/utils/types"; +import axios from "axios"; +import { ActionType, handle3rdPartyServiceError } from "@@core/utils/errors"; +import { WrikeTeamOutput } from "./types"; + +@Injectable() +export class WrikeService implements ITeamService { + constructor( + private prisma: PrismaService, + private logger: LoggerService, + private cryptoService: EncryptionService, + private registry: ServiceRegistry, + ) { + this.logger.setContext( + TicketingObject.team.toUpperCase() + ':' + WrikeService.name, + ); + this.registry.registerService('wrike', this); + } + + async syncTeams( + linkedUserId: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'wrike', + vertical: 'ticketing', + }, + }); + + const resp = await axios.get(`${connection.account_url}/teams`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }); + this.logger.log(`Synced wrike teams !`); + + return { + data: resp.data._results, + message: 'Wrike teams retrieved', + statusCode: 200, + }; + } catch (error) { + handle3rdPartyServiceError( + error, + this.logger, + 'wrike', + TicketingObject.team, + ActionType.GET, + ); + } + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/team/services/wrike/mappers.ts b/packages/api/src/ticketing/team/services/wrike/mappers.ts new file mode 100644 index 000000000..9b36bf763 --- /dev/null +++ b/packages/api/src/ticketing/team/services/wrike/mappers.ts @@ -0,0 +1,51 @@ +import { MappersRegistry } from "@@core/utils/registry/mappings.registry"; +import { Injectable } from "@nestjs/common"; +import { Utils } from "@ticketing/@lib/@utils"; +import { ITeamMapper } from "@ticketing/team/types"; +import { UnifiedTeamInput, UnifiedTeamOutput } from "@ticketing/team/types/model.unified"; +import { WrikeTeamInput, WrikeTeamOutput } from "./types"; + +@Injectable() +export class WrikeTeamMapper implements ITeamMapper { + constructor(private mappersRegistry: MappersRegistry, private utils: Utils) { + this.mappersRegistry.registerService('ticketing', 'team', 'wrike', this); + } + desunify( + source: UnifiedTeamInput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): WrikeTeamInput { + return; + } + + unify( + source: WrikeTeamOutput | WrikeTeamOutput[], + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedTeamOutput | UnifiedTeamOutput[] { + const sourcesArray = Array.isArray(source) ? source : [source]; + + return sourcesArray.map((team) => + this.mapSingleTeamToUnified(team, customFieldMappings), + ); + } + + private mapSingleTeamToUnified( + team: WrikeTeamOutput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedTeamOutput { + const unifiedTeam: UnifiedTeamOutput = { + remote_id: team.id, + name: team.name, + }; + + return unifiedTeam; + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/team/services/wrike/types.ts b/packages/api/src/ticketing/team/services/wrike/types.ts new file mode 100644 index 000000000..5c8aaf748 --- /dev/null +++ b/packages/api/src/ticketing/team/services/wrike/types.ts @@ -0,0 +1,47 @@ +export type WrikeTeamInput = { + id: string; + }; + + export type WrikeTeamOutput = { + _links: TeamLink; + id: string; + name: string; + inboxes: Inbox[]; + members: TeamMember[]; + }; + + type TeamLink = { + self: string; + related?: { + teammates?: string; + conversations?: string; + channels?: string; + owner?: string; + }; + }; + + type CustomFields = { + [key: string]: string | boolean | number | null; + }; + + type Inbox = { + _links: TeamLink; + id: string; + name: string; + is_private: boolean; + custom_fields: CustomFields; + }; + + type TeamMember = { + _links: TeamLink; + id: string; + email: string; + username: string; + first_name: string; + last_name: string; + is_admin: boolean; + is_available: boolean; + is_blocked: boolean; + custom_fields: CustomFields; + }; + \ No newline at end of file diff --git a/packages/api/src/ticketing/ticket/services/wrike/index.ts b/packages/api/src/ticketing/ticket/services/wrike/index.ts new file mode 100644 index 000000000..e6766fceb --- /dev/null +++ b/packages/api/src/ticketing/ticket/services/wrike/index.ts @@ -0,0 +1,197 @@ +import { EncryptionService } from "@@core/encryption/encryption.service"; +import { LoggerService } from "@@core/logger/logger.service"; +import { PrismaService } from "@@core/prisma/prisma.service"; +import { Injectable } from "@nestjs/common"; +import { ITicketService } from "@ticketing/ticket/types"; +import { ServiceRegistry } from "../registry.service"; +import { Utils } from "@ticketing/@lib/@utils"; +import { TicketingObject } from "@ticketing/@lib/@types"; +import axios from "axios"; +import { ApiResponse } from "@@core/utils/types"; +import { ActionType, handle3rdPartyServiceError } from "@@core/utils/errors"; +import { WrikeTicketInput, WrikeTicketOutput } from "./types"; + +@Injectable() +export class WrikeService implements ITicketService { + constructor( + private prisma: PrismaService, + private logger: LoggerService, + private cryptoService: EncryptionService, + private registry: ServiceRegistry, + private utils: Utils, + ) { + this.logger.setContext( + TicketingObject.ticket.toUpperCase() + ':' + WrikeService.name, + ); + this.registry.registerService('wrike', this); + } + + async addTicket( + ticketData: WrikeTicketInput, + linkedUserId: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'wrike', + vertical: 'ticketing', + }, + }); + + const { tags, custom_fields, ...restOfTicketData } = ticketData; + + let uploads = []; + const uuids = restOfTicketData.comment.attachments; + if (uuids && uuids.length > 0) { + for (const uuid of uuids) { + const res = await this.prisma.tcg_attachments.findUnique({ + where: { + id_tcg_attachment: uuid, + }, + }); + if (!res) + throw new ReferenceError( + `tcg_attachment not found for uuid ${uuid}`, + ); + + const fileStream = await this.utils.fetchFileStreamFromURL( + res.file_url, + ); + + uploads = [...uploads, fileStream]; + } + } + + let resp; + if (uploads.length > 0) { + const dataBody = { + ...restOfTicketData, + comment: { ...restOfTicketData.comment, attachments: uploads }, + }; + const formData = new FormData(); + + formData.append('type', dataBody.type); + + if (dataBody.inbox_id) { + formData.append('inbox_id', dataBody.inbox_id); + } + if (dataBody.teammate_ids && dataBody.teammate_ids.length > 0) { + for (let i = 0; i < dataBody.teammate_ids.length; i++) { + const item = dataBody.teammate_ids[i]; + formData.append(`teammate_ids[${i}]`, item); + } + } + if (dataBody.comment.author_id) { + formData.append('comment[author_id]', dataBody.comment.author_id); + } + formData.append('comment[body]', dataBody.comment.body); + + for (let i = 0; i < uploads.length; i++) { + const up = uploads[i]; + formData.append(`comment[attachments][${i}]`, up); + } + + resp = await axios.post( + `${connection.account_url}/conversations`, + formData, + { + headers: { + 'Content-Type': 'multipart/form-data', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }, + ); + } else { + resp = await axios.post( + `${connection.account_url}/conversations`, + JSON.stringify(restOfTicketData), + { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }, + ); + } + + if (tags && tags.length > 0) { + let final: any = { + tag_ids: tags, + }; + if (custom_fields) { + final = { ...final, custom_fields: custom_fields }; + } + const tag_resp = await axios.patch( + `${connection.account_url}/conversations/${resp.data.id}`, + JSON.stringify(final), + { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }, + ); + } + + return { + data: resp.data, + message: 'Wrike ticket created', + statusCode: 201, + }; + } catch (error) { + throw error; + // handle3rdPartyServiceError( + // error, + // this.logger, + // 'wrike', + // TicketingObject.ticket, + // ActionType.POST, + // ); + } + } + async syncTickets( + linkedUserId: string, + remote_ticket_id?: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'wrike', + vertical: 'ticketing', + }, + }); + + const resp = await axios.get(`${connection.account_url}/conversations`, { + headers: { + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }); + this.logger.log(`Synced wrike tickets !`); + + return { + data: resp.data._results, + message: 'Wrike tickets retrieved', + statusCode: 200, + }; + } catch (error) { + throw error; + // handle3rdPartyServiceError( + // error, + // this.logger, + // 'wrike', + // TicketingObject.ticket, + // ActionType.GET, + // ); + } + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/ticket/services/wrike/mappers.ts b/packages/api/src/ticketing/ticket/services/wrike/mappers.ts new file mode 100644 index 000000000..e2a1d9eed --- /dev/null +++ b/packages/api/src/ticketing/ticket/services/wrike/mappers.ts @@ -0,0 +1,123 @@ +import { MappersRegistry } from "@@core/utils/registry/mappings.registry"; +import { Injectable } from "@nestjs/common"; +import { Utils } from "@ticketing/@lib/@utils"; +import { ITicketMapper } from "@ticketing/ticket/types"; +import { UnifiedTicketInput, UnifiedTicketOutput } from "@ticketing/ticket/types/model.unified"; +import { WrikeTicketInput, WrikeTicketOutput } from "./types"; + +@Injectable() +export class WrikeTicketMapper implements ITicketMapper { + constructor(private mappersRegistry: MappersRegistry, private utils: Utils) { + this.mappersRegistry.registerService('ticketing', 'ticket', 'wrike', this); + } + async desunify( + source: UnifiedTicketInput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): Promise { + const body_: any = {}; + + if (source.comment.creator_type === 'user') { + body_.author_id = await this.utils.getAsigneeRemoteIdFromUserUuid( + source.comment.user_id, + ); + } + if (source.comment.attachments) { + body_.attachments = source.comment.attachments; + } + const result: WrikeTicketInput = { + type: 'discussion', + subject: source.name, + comment: { + body: source.comment.body, + ...body_, + }, + }; + + if (source.assigned_to && source.assigned_to.length > 0) { + const res: string[] = []; + for (const assignee of source.assigned_to) { + const data = await this.utils.getAsigneeRemoteIdFromUserUuid(assignee); + if (data) { + res.push(data); + } + } + result.teammate_ids = res; + } + + if (source.tags) { + result.tags = source.tags; + } + + if (customFieldMappings && source.field_mappings) { + for (const [k, v] of Object.entries(source.field_mappings)) { + const mapping = customFieldMappings.find( + (mapping) => mapping.slug === k, + ); + if (mapping) { + result[mapping.remote_id] = v; + } + } + } + + return result; + } + + async unify( + source: WrikeTicketOutput | WrikeTicketOutput[], + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): Promise { + const sourcesArray = Array.isArray(source) ? source : [source]; + + return Promise.all( + sourcesArray.map((ticket) => + this.mapSingleTicketToUnified(ticket, customFieldMappings), + ), + ); + } + + private async mapSingleTicketToUnified( + ticket: WrikeTicketOutput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): Promise { + const field_mappings: { [key: string]: any } = {}; + if (customFieldMappings) { + for (const mapping of customFieldMappings) { + field_mappings[mapping.slug] = ticket.custom_fields[mapping.remote_id]; + } + } + + let opts: any; + + if (ticket.assignee) { + const user_id = await this.utils.getUserUuidFromRemoteId( + String(ticket.assignee.id), + 'wrike', + ); + if (user_id) { + opts = { assigned_to: [user_id] }; + } + } + + const unifiedTicket: UnifiedTicketOutput = { + remote_id: ticket.id, + name: ticket.subject, + status: ticket.status, + description: ticket.subject, + due_date: new Date(ticket.created_at), + tags: ticket.tags?.map((tag) => tag.name), + field_mappings: field_mappings, + ...opts, + }; + + return unifiedTicket; + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/ticket/services/wrike/types.ts b/packages/api/src/ticketing/ticket/services/wrike/types.ts new file mode 100644 index 000000000..9c2c269c3 --- /dev/null +++ b/packages/api/src/ticketing/ticket/services/wrike/types.ts @@ -0,0 +1,104 @@ +export type WrikeTicketInput = { + type: 'discussion'; + inbox_id?: string; + teammate_ids?: string[]; + subject: string; + comment: Comment; + custom_fields?: CustomFields; + tags?: string[]; +}; + +export type Comment = { + author_id?: string; + body: string; + attachments?: string[]; +}; + +export type WrikeTicketOutput = Partial; + +type Conversation = { + _links: Link; + id: string; + subject: string; + status: string; + assignee: Assignee; + recipient: Recipient; + tags: Tag[]; + links: LinkItem[]; + custom_fields: CustomFields; + created_at: number; + is_private: boolean; + scheduled_reminders: ScheduledReminder[]; + metadata: Metadata; +}; + +type Link = { + self: string; + related?: { + [key: string]: string; + }; +}; + +type CustomFields = { + [key: string]: string | boolean | number | null; +}; + +type Assignee = { + _links: Link; + id: string; + email: string; + username: string; + first_name: string; + last_name: string; + is_admin: boolean; + is_available: boolean; + is_blocked: boolean; + custom_fields: CustomFields; +}; + +type Recipient = { + _links: { + related: { + contact: string; + }; + }; + name: string; + handle: string; + role: string; +}; + +type Tag = { + _links: Link; + id: string; + name: string; + description: string; + highlight: null | string; + is_private: boolean; + is_visible_in_conversation_lists: boolean; + created_at: number; + updated_at: number; +}; + +type LinkItem = { + _links: Link; + id: string; + name: string; + type: string; + external_url: string; + custom_fields: CustomFields; +}; + +type ScheduledReminder = { + _links: { + related: { + owner: string; + }; + }; + created_at: number; + scheduled_at: number; + updated_at: number; +}; + +type Metadata = { + external_conversation_ids: string[]; +}; diff --git a/packages/api/src/ticketing/user/services/wrike/index.ts b/packages/api/src/ticketing/user/services/wrike/index.ts new file mode 100644 index 000000000..3dd6522d2 --- /dev/null +++ b/packages/api/src/ticketing/user/services/wrike/index.ts @@ -0,0 +1,65 @@ +import { EncryptionService } from "@@core/encryption/encryption.service"; +import { LoggerService } from "@@core/logger/logger.service"; +import { PrismaService } from "@@core/prisma/prisma.service"; +import { ActionType, handle3rdPartyServiceError } from "@@core/utils/errors"; +import { Injectable } from "@nestjs/common"; +import { TicketingObject } from "@ticketing/@lib/@types"; +import { IUserService } from "@ticketing/user/types"; +import { ServiceRegistry } from "../registry.service"; +import { ApiResponse } from "@@core/utils/types"; +import axios from "axios"; +import { WrikeUserOutput } from "./types"; + +@Injectable() +export class WrikeService implements IUserService { + constructor( + private prisma: PrismaService, + private logger: LoggerService, + private cryptoService: EncryptionService, + private registry: ServiceRegistry, + ) { + this.logger.setContext( + TicketingObject.user.toUpperCase() + ':' + WrikeService.name, + ); + this.registry.registerService('wrike', this); + } + + async syncUsers( + linkedUserId: string, + remote_user_id?: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'wrike', + vertical: 'ticketing', + }, + }); + + const resp = await axios.get(`${connection.account_url}/teammates`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }); + this.logger.log(`Synced wrike users !`); + + return { + data: resp.data._results, + message: 'Wrike users retrieved', + statusCode: 200, + }; + } catch (error) { + handle3rdPartyServiceError( + error, + this.logger, + 'wrike', + TicketingObject.user, + ActionType.GET, + ); + } + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/user/services/wrike/mappers.ts b/packages/api/src/ticketing/user/services/wrike/mappers.ts new file mode 100644 index 000000000..a7b3fdff9 --- /dev/null +++ b/packages/api/src/ticketing/user/services/wrike/mappers.ts @@ -0,0 +1,60 @@ +import { MappersRegistry } from "@@core/utils/registry/mappings.registry"; +import { Injectable } from "@nestjs/common"; +import { Utils } from "@ticketing/@lib/@utils"; +import { IUserMapper } from "@ticketing/user/types"; +import { UnifiedUserInput, UnifiedUserOutput } from "@ticketing/user/types/model.unified"; +import { WrikeUserInput, WrikeUserOutput } from "./types"; + +@Injectable() +export class WrikeUserMapper implements IUserMapper { + constructor(private mappersRegistry: MappersRegistry, private utils: Utils) { + this.mappersRegistry.registerService('ticketing', 'user', 'wrike', this); + } + desunify( + source: UnifiedUserInput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): WrikeUserInput { + return; + } + + unify( + source: WrikeUserOutput | WrikeUserOutput[], + customFieldMappings?: { + slug: string; + remote_id: string + }[], + ): UnifiedUserOutput | UnifiedUserOutput[] { + const sourcesArray = Array.isArray(source) ? source : [source]; + + return sourcesArray.map((user) => + this.mapSingleUserToUnified(user, customFieldMappings), + ); + } + + private mapSingleUserToUnified( + user: WrikeUserOutput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedUserOutput { + const field_mappings: { [key: string]: any } = {}; + if (customFieldMappings) { + for (const mapping of customFieldMappings) { + field_mappings[mapping.slug] = user.custom_fields[mapping.remote_id]; + } + } + + const unifiedUser: UnifiedUserOutput = { + remote_id: user.id, + name: `${user.last_name} ${user.last_name}`, + email_address: user.email, + field_mappings: field_mappings, + }; + + return unifiedUser; + } +} \ No newline at end of file diff --git a/packages/api/src/ticketing/user/services/wrike/types.ts b/packages/api/src/ticketing/user/services/wrike/types.ts new file mode 100644 index 000000000..e831cf906 --- /dev/null +++ b/packages/api/src/ticketing/user/services/wrike/types.ts @@ -0,0 +1,28 @@ +export type WrikeUserInput = { + id: string; + }; + + export type WrikeUserOutput = { + _links: TeammateLink; + id: string; + email: string; + username: string; + first_name: string; + last_name: string; + is_admin: boolean; + is_available: boolean; + is_blocked: boolean; + custom_fields: CustomFields; + }; + + type TeammateLink = { + self: string; + related: { + inboxes: string; + conversations: string; + }; + }; + + type CustomFields = { + [key: string]: string | boolean | number | null; + }; \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e151cced4..a77d62b37 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,12 @@ importers: '@changesets/cli': specifier: ^2.26.2 version: 2.27.1 + '@nestjs/common': + specifier: ^10.3.10 + version: 10.3.10(reflect-metadata@0.1.14)(rxjs@7.8.1) + axios: + specifier: ^1.7.2 + version: 1.7.2 gitmoji-cli: specifier: ^9.0.0 version: 9.2.0 @@ -2579,6 +2585,26 @@ packages: - webpack-cli dev: true + /@nestjs/common@10.3.10(reflect-metadata@0.1.14)(rxjs@7.8.1): + resolution: {integrity: sha512-H8k0jZtxk1IdtErGDmxFRy0PfcOAUg41Prrqpx76DQusGGJjsaovs1zjXVD1rZWaVYchfT1uczJ6L4Kio10VNg==} + peerDependencies: + class-transformer: '*' + class-validator: '*' + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + class-transformer: + optional: true + class-validator: + optional: true + dependencies: + iterare: 1.2.1 + reflect-metadata: 0.1.14 + rxjs: 7.8.1 + tslib: 2.6.3 + uid: 2.0.2 + dev: false + /@nestjs/common@10.3.7(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1): resolution: {integrity: sha512-gKFtFzcJznrwsRYjtNZoPAvSOPYdNgxbTYoAyLTpoy393cIKgLmJTHu6ReH8/qIB9AaZLdGaFLkx98W/tFWFUw==} peerDependencies: @@ -5810,6 +5836,16 @@ packages: - debug dev: false + /axios@1.7.2: + resolution: {integrity: sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==} + dependencies: + follow-redirects: 1.15.6 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + /axobject-query@3.2.1: resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} dependencies: @@ -13360,6 +13396,10 @@ packages: /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + /tslib@2.6.3: + resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + dev: false + /tslint@5.16.0(typescript@5.4.4): resolution: {integrity: sha512-UxG2yNxJ5pgGwmMzPMYh/CCnCnh0HfPgtlVRDs1ykZklufFBL1ZoTlWFRz2NQjcoEiDoRp+JyT0lhBbbH/obyA==} engines: {node: '>=4.8.0'}