Initial commit

This commit is contained in:
2024-06-05 21:13:55 -04:00
parent 7c21aea7e3
commit 30e9a3efcb
27 changed files with 1131 additions and 88 deletions
+14
View File
@@ -0,0 +1,14 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"command": "npm run start:dev -b swc",
"name": "Start Nest",
"request": "launch",
"type": "node-terminal"
},
]
}
+2 -1
View File
@@ -3,6 +3,7 @@
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true
"deleteOutDir": true,
"plugins": ["@nestjs/swagger"]
}
}
+512 -84
View File
@@ -10,8 +10,14 @@
"license": "MIT",
"dependencies": {
"@nestjs/common": "^10.3.2",
"@nestjs/config": "^3.2.2",
"@nestjs/core": "^10.3.2",
"@nestjs/mapped-types": "^2.0.5",
"@nestjs/mongoose": "^10.0.6",
"@nestjs/platform-express": "^10.3.2",
"@nestjs/swagger": "^7.3.1",
"express-session": "^1.18.0",
"mongoose": "^8.4.1",
"reflect-metadata": "^0.2.1",
"rxjs": "^7.8.1"
},
@@ -22,6 +28,7 @@
"@swc/cli": "^0.3.9",
"@swc/core": "^1.4.0",
"@types/express": "^4.17.21",
"@types/express-session": "^1.18.0",
"@types/jest": "^29.5.12",
"@types/node": "^20.11.16",
"@types/supertest": "^6.0.2",
@@ -90,6 +97,30 @@
}
}
},
"node_modules/@angular-devkit/core/node_modules/ajv": {
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/@angular-devkit/core/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true,
"license": "MIT"
},
"node_modules/@angular-devkit/core/node_modules/picomatch": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz",
@@ -975,28 +1006,6 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@eslint/eslintrc/node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
"node_modules/@eslint/js": {
"version": "8.56.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz",
@@ -1599,6 +1608,12 @@
"node": ">=8"
}
},
"node_modules/@microsoft/tsdoc": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz",
"integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==",
"license": "MIT"
},
"node_modules/@mole-inc/bin-wrapper": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/@mole-inc/bin-wrapper/-/bin-wrapper-8.0.1.tgz",
@@ -1618,6 +1633,15 @@
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
}
},
"node_modules/@mongodb-js/saslprep": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.7.tgz",
"integrity": "sha512-dCHW/oEX0KJ4NjDULBo3JiOaK5+6axtpBbS+ao2ZInoAL9/YRQLhXzSNAFz7hP4nzLkIqsfYAK/PDE3+XHny0Q==",
"license": "MIT",
"dependencies": {
"sparse-bitfield": "^3.0.3"
}
},
"node_modules/@nestjs/cli": {
"version": "10.3.1",
"resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-10.3.1.tgz",
@@ -1749,6 +1773,22 @@
}
}
},
"node_modules/@nestjs/config": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/@nestjs/config/-/config-3.2.2.tgz",
"integrity": "sha512-vGICPOui5vE6kPz1iwQ7oCnp3qWgqxldPmBQ9onkVoKlBtyc83KJCr7CjuVtf4OdovMAVcux1d8Q6jglU2ZphA==",
"license": "MIT",
"dependencies": {
"dotenv": "16.4.5",
"dotenv-expand": "10.0.0",
"lodash": "4.17.21",
"uuid": "9.0.1"
},
"peerDependencies": {
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
"rxjs": "^7.1.0"
}
},
"node_modules/@nestjs/core": {
"version": "10.3.2",
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.3.2.tgz",
@@ -1786,6 +1826,38 @@
}
}
},
"node_modules/@nestjs/mapped-types": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.5.tgz",
"integrity": "sha512-bSJv4pd6EY99NX9CjBIyn4TVDoSit82DUZlL4I3bqNfy5Gt+gXTa86i3I/i0iIV9P4hntcGM5GyO+FhZAhxtyg==",
"license": "MIT",
"peerDependencies": {
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
"class-transformer": "^0.4.0 || ^0.5.0",
"class-validator": "^0.13.0 || ^0.14.0",
"reflect-metadata": "^0.1.12 || ^0.2.0"
},
"peerDependenciesMeta": {
"class-transformer": {
"optional": true
},
"class-validator": {
"optional": true
}
}
},
"node_modules/@nestjs/mongoose": {
"version": "10.0.6",
"resolved": "https://registry.npmjs.org/@nestjs/mongoose/-/mongoose-10.0.6.tgz",
"integrity": "sha512-J8jFgSvCDEKMXU57QAIdXIlWQsOFWK+x0PM1KI/0zHe3/4JrAtFGTFD08hRX3IHk+WJT9g/XQIpMSNM7/10Jlg==",
"license": "MIT",
"peerDependencies": {
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
"@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0",
"mongoose": "^6.0.2 || ^7.0.0 || ^8.0.0",
"rxjs": "^7.0.0"
}
},
"node_modules/@nestjs/platform-express": {
"version": "10.3.2",
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.3.2.tgz",
@@ -1867,6 +1939,30 @@
"yarn": ">= 1.13.0"
}
},
"node_modules/@nestjs/schematics/node_modules/ajv": {
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/@nestjs/schematics/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true,
"license": "MIT"
},
"node_modules/@nestjs/schematics/node_modules/picomatch": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz",
@@ -1879,6 +1975,39 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/@nestjs/swagger": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.3.1.tgz",
"integrity": "sha512-LUC4mr+5oAleEC/a2j8pNRh1S5xhKXJ1Gal5ZdRjt9XebQgbngXCdW7JTA9WOEcwGtFZN9EnKYdquzH971LZfw==",
"license": "MIT",
"dependencies": {
"@microsoft/tsdoc": "^0.14.2",
"@nestjs/mapped-types": "2.0.5",
"js-yaml": "4.1.0",
"lodash": "4.17.21",
"path-to-regexp": "3.2.0",
"swagger-ui-dist": "5.11.2"
},
"peerDependencies": {
"@fastify/static": "^6.0.0 || ^7.0.0",
"@nestjs/common": "^9.0.0 || ^10.0.0",
"@nestjs/core": "^9.0.0 || ^10.0.0",
"class-transformer": "*",
"class-validator": "*",
"reflect-metadata": "^0.1.12 || ^0.2.0"
},
"peerDependenciesMeta": {
"@fastify/static": {
"optional": true
},
"class-transformer": {
"optional": true
},
"class-validator": {
"optional": true
}
}
},
"node_modules/@nestjs/testing": {
"version": "10.3.2",
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.3.2.tgz",
@@ -2463,6 +2592,16 @@
"@types/send": "*"
}
},
"node_modules/@types/express-session": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.18.0.tgz",
"integrity": "sha512-27JdDRgor6PoYlURY+Y5kCakqp5ulC0kmf7y+QwaY+hv9jEFuQOThgkjyA53RP3jmKuBsH5GR6qEfFmvb8mwOA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/express": "*"
}
},
"node_modules/@types/graceful-fs": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.7.tgz",
@@ -2629,6 +2768,21 @@
"@types/superagent": "^8.1.0"
}
},
"node_modules/@types/webidl-conversions": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
"integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==",
"license": "MIT"
},
"node_modules/@types/whatwg-url": {
"version": "11.0.5",
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
"integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
"license": "MIT",
"dependencies": {
"@types/webidl-conversions": "*"
}
},
"node_modules/@types/yargs": {
"version": "17.0.25",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.25.tgz",
@@ -3074,14 +3228,15 @@
}
},
"node_modules/ajv": {
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
@@ -3106,6 +3261,30 @@
}
}
},
"node_modules/ajv-formats/node_modules/ajv": {
"version": "8.14.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.14.0.tgz",
"integrity": "sha512-oYs1UUtO97ZO2lJ4bwnWeQW8/zvOIQLGKcvPTsWmvc2SYgBb+upuNS5NxoLaMU4h8Ju3Nbj6Cq8mD2LQoqVKFA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.4.1"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ajv-formats/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true,
"license": "MIT"
},
"node_modules/ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
@@ -3221,8 +3400,7 @@
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"node_modules/array-flatten": {
"version": "1.1.1",
@@ -3648,6 +3826,15 @@
"node-int64": "^0.4.0"
}
},
"node_modules/bson": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/bson/-/bson-6.7.0.tgz",
"integrity": "sha512-w2IquM5mYzYZv6rs3uN2DZTOBe2a0zXLj53TGDqwF4l6Sz/XsISrisXOJihArF9+BZ6Cq/GjVht7Sjfmri7ytQ==",
"license": "Apache-2.0",
"engines": {
"node": ">=16.20.1"
}
},
"node_modules/buffer": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
@@ -4212,7 +4399,6 @@
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
},
@@ -4403,6 +4589,27 @@
"node": ">=6.0.0"
}
},
"node_modules/dotenv": {
"version": "16.4.5",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
"integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/dotenv-expand": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz",
"integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
}
},
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -4639,22 +4846,6 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint/node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/eslint/node_modules/eslint-scope": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
@@ -4692,12 +4883,6 @@
"node": ">=10.13.0"
}
},
"node_modules/eslint/node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
"node_modules/espree": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
@@ -4961,6 +5146,55 @@
"node": ">= 0.10.0"
}
},
"node_modules/express-session": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz",
"integrity": "sha512-m93QLWr0ju+rOwApSsyso838LQwgfs44QtOP/WBiwtAgPIo/SAh1a5c6nn2BR6mFNZehTpqKDESzP+fRHVbxwQ==",
"license": "MIT",
"dependencies": {
"cookie": "0.6.0",
"cookie-signature": "1.0.7",
"debug": "2.6.9",
"depd": "~2.0.0",
"on-headers": "~1.0.2",
"parseurl": "~1.3.3",
"safe-buffer": "5.2.1",
"uid-safe": "~2.1.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/express-session/node_modules/cookie": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/express-session/node_modules/cookie-signature": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
"license": "MIT"
},
"node_modules/express-session/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/express-session/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/express/node_modules/body-parser": {
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
@@ -6786,7 +7020,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"dependencies": {
"argparse": "^2.0.1"
},
@@ -6819,10 +7052,11 @@
"dev": true
},
"node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true,
"license": "MIT"
},
"node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1",
@@ -6860,6 +7094,15 @@
"graceful-fs": "^4.1.6"
}
},
"node_modules/kareem": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
"integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==",
"license": "Apache-2.0",
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/keyv": {
"version": "4.5.3",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz",
@@ -6933,8 +7176,7 @@
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash.memoize": {
"version": "4.1.2",
@@ -7044,6 +7286,12 @@
"node": ">= 4.0.0"
}
},
"node_modules/memory-pager": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
"license": "MIT"
},
"node_modules/merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@@ -7173,11 +7421,149 @@
"mkdirp": "bin/cmd.js"
}
},
"node_modules/mongodb": {
"version": "6.6.2",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.6.2.tgz",
"integrity": "sha512-ZF9Ugo2JCG/GfR7DEb4ypfyJJyiKbg5qBYKRintebj8+DNS33CyGMkWbrS9lara+u+h+yEOGSRiLhFO/g1s1aw==",
"license": "Apache-2.0",
"dependencies": {
"@mongodb-js/saslprep": "^1.1.5",
"bson": "^6.7.0",
"mongodb-connection-string-url": "^3.0.0"
},
"engines": {
"node": ">=16.20.1"
},
"peerDependencies": {
"@aws-sdk/credential-providers": "^3.188.0",
"@mongodb-js/zstd": "^1.1.0",
"gcp-metadata": "^5.2.0",
"kerberos": "^2.0.1",
"mongodb-client-encryption": ">=6.0.0 <7",
"snappy": "^7.2.2",
"socks": "^2.7.1"
},
"peerDependenciesMeta": {
"@aws-sdk/credential-providers": {
"optional": true
},
"@mongodb-js/zstd": {
"optional": true
},
"gcp-metadata": {
"optional": true
},
"kerberos": {
"optional": true
},
"mongodb-client-encryption": {
"optional": true
},
"snappy": {
"optional": true
},
"socks": {
"optional": true
}
}
},
"node_modules/mongodb-connection-string-url": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz",
"integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==",
"license": "Apache-2.0",
"dependencies": {
"@types/whatwg-url": "^11.0.2",
"whatwg-url": "^13.0.0"
}
},
"node_modules/mongodb-connection-string-url/node_modules/tr46": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
"integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
"license": "MIT",
"dependencies": {
"punycode": "^2.3.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
}
},
"node_modules/mongodb-connection-string-url/node_modules/whatwg-url": {
"version": "13.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz",
"integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==",
"license": "MIT",
"dependencies": {
"tr46": "^4.1.1",
"webidl-conversions": "^7.0.0"
},
"engines": {
"node": ">=16"
}
},
"node_modules/mongoose": {
"version": "8.4.1",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.4.1.tgz",
"integrity": "sha512-odQ2WEWGL3hb0Qex+QMN4eH6D34WdMEw7F1If2MGABApSDmG9cMmqv/G1H6WsXmuaH9mkuuadW/WbLE5+tHJwA==",
"license": "MIT",
"dependencies": {
"bson": "^6.7.0",
"kareem": "2.6.3",
"mongodb": "6.6.2",
"mpath": "0.9.0",
"mquery": "5.0.0",
"ms": "2.1.3",
"sift": "17.1.3"
},
"engines": {
"node": ">=16.20.1"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mongoose"
}
},
"node_modules/mongoose/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/mpath": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
"integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
"license": "MIT",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/mquery": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz",
"integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==",
"license": "MIT",
"dependencies": {
"debug": "4.x"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/multer": {
"version": "1.4.4-lts.1",
@@ -7371,6 +7757,15 @@
"node": ">= 0.8"
}
},
"node_modules/on-headers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -7875,7 +8270,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
"dev": true,
"engines": {
"node": ">=6"
}
@@ -7942,6 +8336,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/random-bytes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
"integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -8080,6 +8483,7 @@
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@@ -8323,28 +8727,6 @@
"url": "https://opencollective.com/webpack"
}
},
"node_modules/schema-utils/node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/schema-utils/node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
"node_modules/semver": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
@@ -8541,6 +8923,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/sift": {
"version": "17.1.3",
"resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz",
"integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==",
"license": "MIT"
},
"node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
@@ -8614,6 +9002,15 @@
"node": ">=0.10.0"
}
},
"node_modules/sparse-bitfield": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
"integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
"license": "MIT",
"dependencies": {
"memory-pager": "^1.0.2"
}
},
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -8874,6 +9271,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/swagger-ui-dist": {
"version": "5.11.2",
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.11.2.tgz",
"integrity": "sha512-jQG0cRgJNMZ7aCoiFofnoojeSaa/+KgWaDlfgs8QN+BXoGMpxeMVY5OEnjq4OlNvF3yjftO8c9GRAgcHlO+u7A==",
"license": "Apache-2.0"
},
"node_modules/symbol-observable": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz",
@@ -9357,6 +9760,18 @@
"node": ">=8"
}
},
"node_modules/uid-safe": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
"integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
"license": "MIT",
"dependencies": {
"random-bytes": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
@@ -9432,6 +9847,19 @@
"node": ">= 0.4.0"
}
},
"node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+7
View File
@@ -20,8 +20,14 @@
},
"dependencies": {
"@nestjs/common": "^10.3.2",
"@nestjs/config": "^3.2.2",
"@nestjs/core": "^10.3.2",
"@nestjs/mapped-types": "^2.0.5",
"@nestjs/mongoose": "^10.0.6",
"@nestjs/platform-express": "^10.3.2",
"@nestjs/swagger": "^7.3.1",
"express-session": "^1.18.0",
"mongoose": "^8.4.1",
"reflect-metadata": "^0.2.1",
"rxjs": "^7.8.1"
},
@@ -32,6 +38,7 @@
"@swc/cli": "^0.3.9",
"@swc/core": "^1.4.0",
"@types/express": "^4.17.21",
"@types/express-session": "^1.18.0",
"@types/jest": "^29.5.12",
"@types/node": "^20.11.16",
"@types/supertest": "^6.0.2",
+15 -2
View File
@@ -1,10 +1,23 @@
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GamesModule } from './games/games.module';
import { UsersModule } from './users/users.module';
import { CardsService } from './cards/cards.service';
@Module({
imports: [],
imports: [
ConfigModule.forRoot(),
MongooseModule.forRoot('mongodb://localhost:27017', {
auth: { password: 'example', username: 'root' },
dbName: 'heron',
}),
GamesModule,
UsersModule,
],
controllers: [AppController],
providers: [AppService],
providers: [AppService, CardsService],
})
export class AppModule {}
+13
View File
@@ -0,0 +1,13 @@
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { Card, CardSchema } from './schemas/cards.schema';
@Module({
imports: [
MongooseModule.forFeature([{ name: Card.name, schema: CardSchema }]),
],
exports: [MongooseModule],
})
export class CardsModule {
schema = CardSchema;
}
+18
View File
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { CardsService } from './cards.service';
describe('CardsService', () => {
let service: CardsService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [CardsService],
}).compile();
service = module.get<CardsService>(CardsService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
+26
View File
@@ -0,0 +1,26 @@
import { Injectable } from '@nestjs/common';
import path from 'node:path';
import fs from 'node:fs/promises';
@Injectable()
export class CardsService {
async loadCards(): Promise<void> {
const cardPath = path.join(path.resolve(), 'cards');
const files = await fs.readdir(cardPath);
const processed = await Promise.all(
files.map(async (f) => {
return [
path.parse(f).name,
(
await fs
.readFile(path.join(cardPath, f))
.then((e) => JSON.parse(e.toString()))
).cards,
];
}),
);
const packs = Object.fromEntries(processed);
console.log(packs);
}
}
+18
View File
@@ -0,0 +1,18 @@
import { Schema, SchemaFactory } from '@nestjs/mongoose';
import { CardFaction, CardRole, CardType, EffectParser } from './cards.types';
@Schema()
export class Card {
cardId: number;
role: CardRole;
cardType: CardType;
faction: CardFaction;
name: string;
initAmount: number;
cost?: number;
defense?: number;
guard?: boolean;
effects: EffectParser[];
}
export const CardSchema = SchemaFactory.createForClass(Card);
+102
View File
@@ -0,0 +1,102 @@
/**
*
*/
export enum CardRole {
PERSONAL = 'personal',
MARKET = 'market',
FIRE_GEM = 'fire_gem',
}
/**
* Playable card types
*/
export enum CardType {
HERO = 'hero',
HERO_ABILITY = 'hero_ability',
CURRENCY = 'currency',
WEAPON = 'weapon',
CHAMPION = 'champion',
ACTION = 'action',
ITEM = 'item',
}
/**
* Playable card factions
*/
export enum CardFaction {
BASE = 'base',
BLUE = 'blue',
RED = 'red',
GREEN = 'green',
YELLOW = 'yellow',
}
export enum CardEffects {
GOLD = 'gold',
DAMAGE = 'damage',
HEAL = 'heal',
PREPARE = 'prepare',
STUN = 'stun',
SACRIFICE = 'sacrifice',
DRAW = 'draw',
DRAW_AND_DISCARD = 'draw_and_discard',
MAKE_DISCARD = 'make_discard',
RESTACK_DISCARDED_CHAMPION = 'restack_discarded_champion',
RESTACK_DISCARDED_CARD = 'restack_discarded_card',
STACK_NEXT_ACTION_BOUGHT = 'stack_next_action_bought',
STACK_NEXT_CARD_BOUGHT = 'stack_next_card_bought',
PLAY_NEXT_CARD_BOUGHT = 'play_next_card_bought',
}
export enum Per {
CHAMPION = 'champion',
OTHER_CHAMPION = 'other_champion',
OTHER_GUARD = 'other_guard',
CARD_OF_SAME_FACTION = 'card_of_same_faction',
OTHER_CARD_OF_SAME_FACTION = 'other_card_of_same_faction',
}
export enum EffectType {
CHAMPION_ACTION = 'champion_action',
SUICIDE = 'suicide',
FACTION_COMBO = 'faction_combo',
}
export enum EffectTypeSpecial {
CHAMPION_AMOUNT = 'champion_amount',
TOTAL_DAMAGE = 'total_damage',
CARD_AMOUNT = 'card_amount',
ACTION_AMOUNT = 'action_amount',
}
export type EffectTypeVerbose = {
id: EffectType | EffectTypeSpecial;
faction?: string;
amount?: number;
card_id?: number;
};
export type EffectParser = {
effect: CardEffects;
amount: number;
times?: number;
sub_effects?: EffectParser[];
effect_type?: EffectType | EffectTypeVerbose;
per?: Per;
mutex?: number;
};
export type CardParser = {
id: number;
role: CardRole;
card_type: CardType;
faction: CardFaction;
name: string;
init_amount: number;
cost?: number;
amount: number;
defense?: number;
guard?: boolean;
effects: EffectParser[];
};
+1
View File
@@ -0,0 +1 @@
export class CreateGameDto {}
+4
View File
@@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreateGameDto } from './create-game.dto';
export class UpdateGameDto extends PartialType(CreateGameDto) {}
+20
View File
@@ -0,0 +1,20 @@
import { Test, TestingModule } from '@nestjs/testing';
import { GamesController } from './games.controller';
import { GamesService } from './games.service';
describe('GamesController', () => {
let controller: GamesController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [GamesController],
providers: [GamesService],
}).compile();
controller = module.get<GamesController>(GamesController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
+42
View File
@@ -0,0 +1,42 @@
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
} from '@nestjs/common';
import { GamesService } from './games.service';
import { CreateGameDto } from './dto/create-game.dto';
import { UpdateGameDto } from './dto/update-game.dto';
@Controller('games')
export class GamesController {
constructor(private readonly gamesService: GamesService) {}
@Post()
create() {
return this.gamesService.create();
}
@Get()
findAll() {
return this.gamesService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.gamesService.findOne(id);
}
// @Patch(':id')
// update(@Param('id') id: string, @Body() updateGameDto: UpdateGameDto) {
// return this.gamesService.update(+id, updateGameDto);
// }
@Delete(':id')
remove(@Param('id') id: string) {
return this.gamesService.remove(+id);
}
}
+18
View File
@@ -0,0 +1,18 @@
import { Module } from '@nestjs/common';
import { GamesService } from './games.service';
import { GamesController } from './games.controller';
import { Game, GameSchema } from './schemas/game.schema';
import { MongooseModule } from '@nestjs/mongoose';
import { UsersModule } from 'src/users/users.module';
import { CardsModule } from 'src/cards/cards.module';
@Module({
imports: [
CardsModule,
UsersModule,
MongooseModule.forFeature([{ name: Game.name, schema: GameSchema }]),
],
controllers: [GamesController],
providers: [GamesService],
})
export class GamesModule {}
+18
View File
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { GamesService } from './games.service';
describe('GamesService', () => {
let service: GamesService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [GamesService],
}).compile();
service = module.get<GamesService>(GamesService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
+31
View File
@@ -0,0 +1,31 @@
import { Injectable } from '@nestjs/common';
import { CreateGameDto } from './dto/create-game.dto';
import { UpdateGameDto } from './dto/update-game.dto';
import { InjectModel } from '@nestjs/mongoose';
import { Game } from './schemas/game.schema';
import { Model } from 'mongoose';
@Injectable()
export class GamesService {
constructor(@InjectModel(Game.name) private gameModel: Model<Game>) {}
async create(): Promise<Game> {
const createdGame = new this.gameModel();
return createdGame.save();
}
findAll() {
return this.gameModel.find();
}
findOne(id: string) {
return this.gameModel.find({ _id: id }).exec();
}
// update(id: number, updateGameDto: UpdateGameDto) {
// return `This action updates a #${id} game`;
// }
remove(id: number) {
return `This action removes a #${id} game`;
}
}
+51
View File
@@ -0,0 +1,51 @@
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import mongoose, { HydratedDocument } from 'mongoose';
import { Card } from 'src/cards/schemas/cards.schema';
import { User } from 'src/users/schemas/user.entity';
export type GameDocument = HydratedDocument<Game>;
@Schema()
class GameObject {}
@Schema()
export class Team extends GameObject {}
export const TeamSchema = SchemaFactory.createForClass(Team);
@Schema()
export class Container extends GameObject {
@Prop([{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }])
cards: Card[];
}
export const ContainerSchema = SchemaFactory.createForClass(Container);
@Schema()
export class Game extends GameObject {
@Prop([Team])
teams: Team[];
@Prop({ type: ContainerSchema, default: {} })
market: Container;
@Prop({ type: ContainerSchema, default: {} })
marketStack: Container;
@Prop({ type: ContainerSchema, default: {} })
fireGems: Container;
@Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'Game.teams' })
currentTurn?: Team;
@Prop({ default: false })
started: boolean;
@Prop({ default: false })
private ended: boolean;
@Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'User' })
owner: User;
}
export const GameSchema = SchemaFactory.createForClass(Game);
+21 -1
View File
@@ -1,8 +1,28 @@
import { NestFactory } from '@nestjs/core';
import * as session from 'express-session';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
const config = new DocumentBuilder()
.setTitle('Heron Game')
.setDescription('Heron')
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
app.use(
session({
secret: 'my-secret',
resave: false,
saveUninitialized: false,
name: 'heron.session',
}),
);
await app.listen(8765);
}
bootstrap();
+5
View File
@@ -0,0 +1,5 @@
export class CreateUserDto {
method: 'discord' | 'password';
username?: string;
password: string;
}
+20
View File
@@ -0,0 +1,20 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreateUserDto } from './create-user.dto';
import { ApiProperty } from '@nestjs/swagger';
export class LoginDto extends PartialType(CreateUserDto) {
constructor(id: string, global_name: string, avatar: string) {
super();
this.id = id;
this.global_name = global_name;
this.avatar = avatar;
}
@ApiProperty()
id: string;
@ApiProperty()
global_name: string;
@ApiProperty()
avatar: string;
}
+9
View File
@@ -0,0 +1,9 @@
import { Schema, SchemaFactory } from '@nestjs/mongoose';
import { HydratedDocument } from 'mongoose';
export type UserDocument = HydratedDocument<User>;
@Schema()
export class User {}
export const UserSchema = SchemaFactory.createForClass(User);
+20
View File
@@ -0,0 +1,20 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
describe('UsersController', () => {
let controller: UsersController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [UsersController],
providers: [UsersService],
}).compile();
controller = module.get<UsersController>(UsersController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
+46
View File
@@ -0,0 +1,46 @@
import {
Controller,
Get,
Query,
Session,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { UsersService } from './users.service';
import { LoginDto } from './dto/login.dto';
import { ApiTags } from '@nestjs/swagger';
@ApiTags('auth')
@Controller()
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get('/login')
async login(
@Query('code') code: string,
@Session() session: Record<string, any>,
) {
const tokenData = await this.usersService.saveDiscordToken(code);
session.tokenData = tokenData;
const user = await this.usersService.useDiscordToken(
tokenData.token_type,
tokenData.token,
);
return user;
}
@Get('/whoami')
async remove(@Session() session: Record<string, any>): Promise<LoginDto> {
if (!session.tokenData) {
throw new HttpException(
"Session doesn't contains auth information",
HttpStatus.UNAUTHORIZED,
);
}
const user = await this.usersService.useDiscordToken(
session.tokenData.token_type,
session.tokenData.token,
);
return user;
}
}
+17
View File
@@ -0,0 +1,17 @@
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { MongooseModule } from '@nestjs/mongoose';
import { User, UserSchema } from './schemas/user.entity';
@Module({
imports: [
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
],
controllers: [UsersController],
providers: [UsersService],
exports: [MongooseModule],
})
export class UsersModule {
schema = UserSchema;
}
+18
View File
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UsersService } from './users.service';
describe('UsersService', () => {
let service: UsersService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UsersService],
}).compile();
service = module.get<UsersService>(UsersService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
+63
View File
@@ -0,0 +1,63 @@
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { LoginDto } from './dto/login.dto';
import { URLSearchParams } from 'url';
@Injectable()
export class UsersService {
async saveDiscordToken(code: string) {
const req = await fetch('https://discord.com/api/oauth2/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
client_id: process.env.DISCORD_CLIENTID,
client_secret: process.env.DISCORD_CLIENTSECRET,
code: code,
grant_type: 'authorization_code',
redirect_uri: process.env.API_ENDPOINT + '/login',
scope: 'identify',
}),
});
if (!req.ok) {
console.error(await req.json());
throw new HttpException(
"Couldn't fetch Discord api",
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
const data = await req.json();
if (!data.token_type || !data.access_token) {
console.error(data);
throw new HttpException(
'Invalid Discord API response',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
const token_type = data.token_type;
const token = data.access_token;
return { token, token_type };
}
async useDiscordToken(token_type: string, token: string) {
const req2 = await fetch('https://discord.com/api/users/@me', {
headers: {
authorization: token_type + ' ' + token,
},
});
if (!req2.ok) {
throw new HttpException(
"Couldn't fetch Discord api",
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
const data2 = await req2.json();
return new LoginDto(data2.id, data2.global_name, data2.avatar);
}
remove(id: number) {
return `This action removes a #${id} user`;
}
}