Spaces:
Running
Running
push api
Browse files- package-lock.json +283 -0
- package.json +4 -0
- src/index.ts +182 -4
- src/routes/auth.ts +48 -0
- src/routes/profile.ts +27 -0
- src/routes/suggest.ts +34 -0
- src/routes/upload.ts +33 -0
package-lock.json
CHANGED
|
@@ -18,6 +18,8 @@
|
|
| 18 |
"jsonwebtoken": "^9.0.2",
|
| 19 |
"pg": "^8.16.3",
|
| 20 |
"reflect-metadata": "^0.2.2",
|
|
|
|
|
|
|
| 21 |
"typeorm": "^0.3.27"
|
| 22 |
},
|
| 23 |
"devDependencies": {
|
|
@@ -26,11 +28,53 @@
|
|
| 26 |
"@types/express": "^5.0.5",
|
| 27 |
"@types/jsonwebtoken": "^9.0.10",
|
| 28 |
"@types/node": "^24.9.2",
|
|
|
|
|
|
|
| 29 |
"nodemon": "^3.1.10",
|
| 30 |
"ts-node": "^10.9.2",
|
| 31 |
"typescript": "^5.9.3"
|
| 32 |
}
|
| 33 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
"node_modules/@cspotcode/source-map-support": {
|
| 35 |
"version": "0.8.1",
|
| 36 |
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
|
@@ -84,6 +128,11 @@
|
|
| 84 |
"@jridgewell/sourcemap-codec": "^1.4.10"
|
| 85 |
}
|
| 86 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
"node_modules/@mapbox/node-pre-gyp": {
|
| 88 |
"version": "1.0.11",
|
| 89 |
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
|
|
@@ -112,6 +161,12 @@
|
|
| 112 |
"node": ">=14"
|
| 113 |
}
|
| 114 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
"node_modules/@sqltools/formatter": {
|
| 116 |
"version": "1.2.5",
|
| 117 |
"resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz",
|
|
@@ -207,6 +262,11 @@
|
|
| 207 |
"integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
|
| 208 |
"dev": true
|
| 209 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
"node_modules/@types/jsonwebtoken": {
|
| 211 |
"version": "9.0.10",
|
| 212 |
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz",
|
|
@@ -280,6 +340,22 @@
|
|
| 280 |
"@types/node": "*"
|
| 281 |
}
|
| 282 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 283 |
"node_modules/abbrev": {
|
| 284 |
"version": "1.1.1",
|
| 285 |
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
|
@@ -407,6 +483,11 @@
|
|
| 407 |
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
| 408 |
"devOptional": true
|
| 409 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 410 |
"node_modules/asynckit": {
|
| 411 |
"version": "0.4.0",
|
| 412 |
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
|
@@ -604,6 +685,11 @@
|
|
| 604 |
"url": "https://github.com/sponsors/ljharb"
|
| 605 |
}
|
| 606 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 607 |
"node_modules/chokidar": {
|
| 608 |
"version": "3.6.0",
|
| 609 |
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
|
@@ -763,6 +849,14 @@
|
|
| 763 |
"node": ">= 0.8"
|
| 764 |
}
|
| 765 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 766 |
"node_modules/concat-map": {
|
| 767 |
"version": "0.0.1",
|
| 768 |
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
|
@@ -927,6 +1021,17 @@
|
|
| 927 |
"node": ">=0.3.1"
|
| 928 |
}
|
| 929 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 930 |
"node_modules/dotenv": {
|
| 931 |
"version": "17.2.3",
|
| 932 |
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
|
|
@@ -1036,6 +1141,14 @@
|
|
| 1036 |
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
| 1037 |
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
|
| 1038 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1039 |
"node_modules/etag": {
|
| 1040 |
"version": "1.8.1",
|
| 1041 |
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
|
@@ -1666,6 +1779,17 @@
|
|
| 1666 |
"@pkgjs/parseargs": "^0.11.0"
|
| 1667 |
}
|
| 1668 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1669 |
"node_modules/jsonwebtoken": {
|
| 1670 |
"version": "9.0.2",
|
| 1671 |
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
|
@@ -1711,6 +1835,12 @@
|
|
| 1711 |
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
| 1712 |
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
| 1713 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1714 |
"node_modules/lodash.includes": {
|
| 1715 |
"version": "4.3.0",
|
| 1716 |
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
|
@@ -1721,6 +1851,12 @@
|
|
| 1721 |
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
| 1722 |
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="
|
| 1723 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1724 |
"node_modules/lodash.isinteger": {
|
| 1725 |
"version": "4.0.4",
|
| 1726 |
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
|
@@ -1741,6 +1877,11 @@
|
|
| 1741 |
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
| 1742 |
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="
|
| 1743 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1744 |
"node_modules/lodash.once": {
|
| 1745 |
"version": "4.1.1",
|
| 1746 |
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
|
@@ -2041,6 +2182,12 @@
|
|
| 2041 |
"wrappy": "1"
|
| 2042 |
}
|
| 2043 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2044 |
"node_modules/package-json-from-dist": {
|
| 2045 |
"version": "1.0.1",
|
| 2046 |
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
|
@@ -2786,6 +2933,98 @@
|
|
| 2786 |
"node": ">=4"
|
| 2787 |
}
|
| 2788 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2789 |
"node_modules/tar": {
|
| 2790 |
"version": "6.2.1",
|
| 2791 |
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
|
@@ -3099,6 +3338,14 @@
|
|
| 3099 |
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
| 3100 |
"devOptional": true
|
| 3101 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3102 |
"node_modules/vary": {
|
| 3103 |
"version": "1.1.2",
|
| 3104 |
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
|
@@ -3310,6 +3557,14 @@
|
|
| 3310 |
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
| 3311 |
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
| 3312 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3313 |
"node_modules/yargs": {
|
| 3314 |
"version": "17.7.2",
|
| 3315 |
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
|
@@ -3380,6 +3635,34 @@
|
|
| 3380 |
"engines": {
|
| 3381 |
"node": ">=6"
|
| 3382 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3383 |
}
|
| 3384 |
}
|
| 3385 |
}
|
|
|
|
| 18 |
"jsonwebtoken": "^9.0.2",
|
| 19 |
"pg": "^8.16.3",
|
| 20 |
"reflect-metadata": "^0.2.2",
|
| 21 |
+
"swagger-jsdoc": "^6.2.8",
|
| 22 |
+
"swagger-ui-express": "^5.0.0",
|
| 23 |
"typeorm": "^0.3.27"
|
| 24 |
},
|
| 25 |
"devDependencies": {
|
|
|
|
| 28 |
"@types/express": "^5.0.5",
|
| 29 |
"@types/jsonwebtoken": "^9.0.10",
|
| 30 |
"@types/node": "^24.9.2",
|
| 31 |
+
"@types/swagger-jsdoc": "^6.0.4",
|
| 32 |
+
"@types/swagger-ui-express": "^4.1.6",
|
| 33 |
"nodemon": "^3.1.10",
|
| 34 |
"ts-node": "^10.9.2",
|
| 35 |
"typescript": "^5.9.3"
|
| 36 |
}
|
| 37 |
},
|
| 38 |
+
"node_modules/@apidevtools/json-schema-ref-parser": {
|
| 39 |
+
"version": "9.1.2",
|
| 40 |
+
"resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz",
|
| 41 |
+
"integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==",
|
| 42 |
+
"dependencies": {
|
| 43 |
+
"@jsdevtools/ono": "^7.1.3",
|
| 44 |
+
"@types/json-schema": "^7.0.6",
|
| 45 |
+
"call-me-maybe": "^1.0.1",
|
| 46 |
+
"js-yaml": "^4.1.0"
|
| 47 |
+
}
|
| 48 |
+
},
|
| 49 |
+
"node_modules/@apidevtools/openapi-schemas": {
|
| 50 |
+
"version": "2.1.0",
|
| 51 |
+
"resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz",
|
| 52 |
+
"integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==",
|
| 53 |
+
"engines": {
|
| 54 |
+
"node": ">=10"
|
| 55 |
+
}
|
| 56 |
+
},
|
| 57 |
+
"node_modules/@apidevtools/swagger-methods": {
|
| 58 |
+
"version": "3.0.2",
|
| 59 |
+
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz",
|
| 60 |
+
"integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg=="
|
| 61 |
+
},
|
| 62 |
+
"node_modules/@apidevtools/swagger-parser": {
|
| 63 |
+
"version": "10.0.3",
|
| 64 |
+
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz",
|
| 65 |
+
"integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==",
|
| 66 |
+
"dependencies": {
|
| 67 |
+
"@apidevtools/json-schema-ref-parser": "^9.0.6",
|
| 68 |
+
"@apidevtools/openapi-schemas": "^2.0.4",
|
| 69 |
+
"@apidevtools/swagger-methods": "^3.0.2",
|
| 70 |
+
"@jsdevtools/ono": "^7.1.3",
|
| 71 |
+
"call-me-maybe": "^1.0.1",
|
| 72 |
+
"z-schema": "^5.0.1"
|
| 73 |
+
},
|
| 74 |
+
"peerDependencies": {
|
| 75 |
+
"openapi-types": ">=7"
|
| 76 |
+
}
|
| 77 |
+
},
|
| 78 |
"node_modules/@cspotcode/source-map-support": {
|
| 79 |
"version": "0.8.1",
|
| 80 |
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
|
|
|
| 128 |
"@jridgewell/sourcemap-codec": "^1.4.10"
|
| 129 |
}
|
| 130 |
},
|
| 131 |
+
"node_modules/@jsdevtools/ono": {
|
| 132 |
+
"version": "7.1.3",
|
| 133 |
+
"resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
|
| 134 |
+
"integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="
|
| 135 |
+
},
|
| 136 |
"node_modules/@mapbox/node-pre-gyp": {
|
| 137 |
"version": "1.0.11",
|
| 138 |
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
|
|
|
|
| 161 |
"node": ">=14"
|
| 162 |
}
|
| 163 |
},
|
| 164 |
+
"node_modules/@scarf/scarf": {
|
| 165 |
+
"version": "1.4.0",
|
| 166 |
+
"resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz",
|
| 167 |
+
"integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==",
|
| 168 |
+
"hasInstallScript": true
|
| 169 |
+
},
|
| 170 |
"node_modules/@sqltools/formatter": {
|
| 171 |
"version": "1.2.5",
|
| 172 |
"resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz",
|
|
|
|
| 262 |
"integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
|
| 263 |
"dev": true
|
| 264 |
},
|
| 265 |
+
"node_modules/@types/json-schema": {
|
| 266 |
+
"version": "7.0.15",
|
| 267 |
+
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
| 268 |
+
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="
|
| 269 |
+
},
|
| 270 |
"node_modules/@types/jsonwebtoken": {
|
| 271 |
"version": "9.0.10",
|
| 272 |
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz",
|
|
|
|
| 340 |
"@types/node": "*"
|
| 341 |
}
|
| 342 |
},
|
| 343 |
+
"node_modules/@types/swagger-jsdoc": {
|
| 344 |
+
"version": "6.0.4",
|
| 345 |
+
"resolved": "https://registry.npmjs.org/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.4.tgz",
|
| 346 |
+
"integrity": "sha512-W+Xw5epcOZrF/AooUM/PccNMSAFOKWZA5dasNyMujTwsBkU74njSJBpvCCJhHAJ95XRMzQrrW844Btu0uoetwQ==",
|
| 347 |
+
"dev": true
|
| 348 |
+
},
|
| 349 |
+
"node_modules/@types/swagger-ui-express": {
|
| 350 |
+
"version": "4.1.8",
|
| 351 |
+
"resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.8.tgz",
|
| 352 |
+
"integrity": "sha512-AhZV8/EIreHFmBV5wAs0gzJUNq9JbbSXgJLQubCC0jtIo6prnI9MIRRxnU4MZX9RB9yXxF1V4R7jtLl/Wcj31g==",
|
| 353 |
+
"dev": true,
|
| 354 |
+
"dependencies": {
|
| 355 |
+
"@types/express": "*",
|
| 356 |
+
"@types/serve-static": "*"
|
| 357 |
+
}
|
| 358 |
+
},
|
| 359 |
"node_modules/abbrev": {
|
| 360 |
"version": "1.1.1",
|
| 361 |
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
|
|
|
| 483 |
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
| 484 |
"devOptional": true
|
| 485 |
},
|
| 486 |
+
"node_modules/argparse": {
|
| 487 |
+
"version": "2.0.1",
|
| 488 |
+
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
| 489 |
+
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
| 490 |
+
},
|
| 491 |
"node_modules/asynckit": {
|
| 492 |
"version": "0.4.0",
|
| 493 |
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
|
|
|
| 685 |
"url": "https://github.com/sponsors/ljharb"
|
| 686 |
}
|
| 687 |
},
|
| 688 |
+
"node_modules/call-me-maybe": {
|
| 689 |
+
"version": "1.0.2",
|
| 690 |
+
"resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
|
| 691 |
+
"integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ=="
|
| 692 |
+
},
|
| 693 |
"node_modules/chokidar": {
|
| 694 |
"version": "3.6.0",
|
| 695 |
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
|
|
|
| 849 |
"node": ">= 0.8"
|
| 850 |
}
|
| 851 |
},
|
| 852 |
+
"node_modules/commander": {
|
| 853 |
+
"version": "6.2.0",
|
| 854 |
+
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz",
|
| 855 |
+
"integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==",
|
| 856 |
+
"engines": {
|
| 857 |
+
"node": ">= 6"
|
| 858 |
+
}
|
| 859 |
+
},
|
| 860 |
"node_modules/concat-map": {
|
| 861 |
"version": "0.0.1",
|
| 862 |
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
|
|
|
| 1021 |
"node": ">=0.3.1"
|
| 1022 |
}
|
| 1023 |
},
|
| 1024 |
+
"node_modules/doctrine": {
|
| 1025 |
+
"version": "3.0.0",
|
| 1026 |
+
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
| 1027 |
+
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
|
| 1028 |
+
"dependencies": {
|
| 1029 |
+
"esutils": "^2.0.2"
|
| 1030 |
+
},
|
| 1031 |
+
"engines": {
|
| 1032 |
+
"node": ">=6.0.0"
|
| 1033 |
+
}
|
| 1034 |
+
},
|
| 1035 |
"node_modules/dotenv": {
|
| 1036 |
"version": "17.2.3",
|
| 1037 |
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
|
|
|
|
| 1141 |
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
| 1142 |
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
|
| 1143 |
},
|
| 1144 |
+
"node_modules/esutils": {
|
| 1145 |
+
"version": "2.0.3",
|
| 1146 |
+
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
| 1147 |
+
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
| 1148 |
+
"engines": {
|
| 1149 |
+
"node": ">=0.10.0"
|
| 1150 |
+
}
|
| 1151 |
+
},
|
| 1152 |
"node_modules/etag": {
|
| 1153 |
"version": "1.8.1",
|
| 1154 |
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
|
|
|
| 1779 |
"@pkgjs/parseargs": "^0.11.0"
|
| 1780 |
}
|
| 1781 |
},
|
| 1782 |
+
"node_modules/js-yaml": {
|
| 1783 |
+
"version": "4.1.0",
|
| 1784 |
+
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
| 1785 |
+
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
| 1786 |
+
"dependencies": {
|
| 1787 |
+
"argparse": "^2.0.1"
|
| 1788 |
+
},
|
| 1789 |
+
"bin": {
|
| 1790 |
+
"js-yaml": "bin/js-yaml.js"
|
| 1791 |
+
}
|
| 1792 |
+
},
|
| 1793 |
"node_modules/jsonwebtoken": {
|
| 1794 |
"version": "9.0.2",
|
| 1795 |
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
|
|
|
| 1835 |
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
| 1836 |
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
| 1837 |
},
|
| 1838 |
+
"node_modules/lodash.get": {
|
| 1839 |
+
"version": "4.4.2",
|
| 1840 |
+
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
| 1841 |
+
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
|
| 1842 |
+
"deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead."
|
| 1843 |
+
},
|
| 1844 |
"node_modules/lodash.includes": {
|
| 1845 |
"version": "4.3.0",
|
| 1846 |
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
|
|
|
| 1851 |
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
| 1852 |
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="
|
| 1853 |
},
|
| 1854 |
+
"node_modules/lodash.isequal": {
|
| 1855 |
+
"version": "4.5.0",
|
| 1856 |
+
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
| 1857 |
+
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
|
| 1858 |
+
"deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead."
|
| 1859 |
+
},
|
| 1860 |
"node_modules/lodash.isinteger": {
|
| 1861 |
"version": "4.0.4",
|
| 1862 |
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
|
|
|
| 1877 |
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
| 1878 |
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="
|
| 1879 |
},
|
| 1880 |
+
"node_modules/lodash.mergewith": {
|
| 1881 |
+
"version": "4.6.2",
|
| 1882 |
+
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
|
| 1883 |
+
"integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ=="
|
| 1884 |
+
},
|
| 1885 |
"node_modules/lodash.once": {
|
| 1886 |
"version": "4.1.1",
|
| 1887 |
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
|
|
|
| 2182 |
"wrappy": "1"
|
| 2183 |
}
|
| 2184 |
},
|
| 2185 |
+
"node_modules/openapi-types": {
|
| 2186 |
+
"version": "12.1.3",
|
| 2187 |
+
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz",
|
| 2188 |
+
"integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==",
|
| 2189 |
+
"peer": true
|
| 2190 |
+
},
|
| 2191 |
"node_modules/package-json-from-dist": {
|
| 2192 |
"version": "1.0.1",
|
| 2193 |
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
|
|
|
| 2933 |
"node": ">=4"
|
| 2934 |
}
|
| 2935 |
},
|
| 2936 |
+
"node_modules/swagger-jsdoc": {
|
| 2937 |
+
"version": "6.2.8",
|
| 2938 |
+
"resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz",
|
| 2939 |
+
"integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==",
|
| 2940 |
+
"dependencies": {
|
| 2941 |
+
"commander": "6.2.0",
|
| 2942 |
+
"doctrine": "3.0.0",
|
| 2943 |
+
"glob": "7.1.6",
|
| 2944 |
+
"lodash.mergewith": "^4.6.2",
|
| 2945 |
+
"swagger-parser": "^10.0.3",
|
| 2946 |
+
"yaml": "2.0.0-1"
|
| 2947 |
+
},
|
| 2948 |
+
"bin": {
|
| 2949 |
+
"swagger-jsdoc": "bin/swagger-jsdoc.js"
|
| 2950 |
+
},
|
| 2951 |
+
"engines": {
|
| 2952 |
+
"node": ">=12.0.0"
|
| 2953 |
+
}
|
| 2954 |
+
},
|
| 2955 |
+
"node_modules/swagger-jsdoc/node_modules/brace-expansion": {
|
| 2956 |
+
"version": "1.1.12",
|
| 2957 |
+
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
| 2958 |
+
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
| 2959 |
+
"dependencies": {
|
| 2960 |
+
"balanced-match": "^1.0.0",
|
| 2961 |
+
"concat-map": "0.0.1"
|
| 2962 |
+
}
|
| 2963 |
+
},
|
| 2964 |
+
"node_modules/swagger-jsdoc/node_modules/glob": {
|
| 2965 |
+
"version": "7.1.6",
|
| 2966 |
+
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
| 2967 |
+
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
| 2968 |
+
"deprecated": "Glob versions prior to v9 are no longer supported",
|
| 2969 |
+
"dependencies": {
|
| 2970 |
+
"fs.realpath": "^1.0.0",
|
| 2971 |
+
"inflight": "^1.0.4",
|
| 2972 |
+
"inherits": "2",
|
| 2973 |
+
"minimatch": "^3.0.4",
|
| 2974 |
+
"once": "^1.3.0",
|
| 2975 |
+
"path-is-absolute": "^1.0.0"
|
| 2976 |
+
},
|
| 2977 |
+
"engines": {
|
| 2978 |
+
"node": "*"
|
| 2979 |
+
},
|
| 2980 |
+
"funding": {
|
| 2981 |
+
"url": "https://github.com/sponsors/isaacs"
|
| 2982 |
+
}
|
| 2983 |
+
},
|
| 2984 |
+
"node_modules/swagger-jsdoc/node_modules/minimatch": {
|
| 2985 |
+
"version": "3.1.2",
|
| 2986 |
+
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
| 2987 |
+
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
| 2988 |
+
"dependencies": {
|
| 2989 |
+
"brace-expansion": "^1.1.7"
|
| 2990 |
+
},
|
| 2991 |
+
"engines": {
|
| 2992 |
+
"node": "*"
|
| 2993 |
+
}
|
| 2994 |
+
},
|
| 2995 |
+
"node_modules/swagger-parser": {
|
| 2996 |
+
"version": "10.0.3",
|
| 2997 |
+
"resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz",
|
| 2998 |
+
"integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==",
|
| 2999 |
+
"dependencies": {
|
| 3000 |
+
"@apidevtools/swagger-parser": "10.0.3"
|
| 3001 |
+
},
|
| 3002 |
+
"engines": {
|
| 3003 |
+
"node": ">=10"
|
| 3004 |
+
}
|
| 3005 |
+
},
|
| 3006 |
+
"node_modules/swagger-ui-dist": {
|
| 3007 |
+
"version": "5.30.1",
|
| 3008 |
+
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.30.1.tgz",
|
| 3009 |
+
"integrity": "sha512-4mNAUM31sr52K3JcK9qiGbfsFKNh/dm3PkEe+F9FAM31YY/NoRYUgsR/L6d7LLFn6PgZXtBG2ygp8+7UnpUIPg==",
|
| 3010 |
+
"dependencies": {
|
| 3011 |
+
"@scarf/scarf": "=1.4.0"
|
| 3012 |
+
}
|
| 3013 |
+
},
|
| 3014 |
+
"node_modules/swagger-ui-express": {
|
| 3015 |
+
"version": "5.0.1",
|
| 3016 |
+
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz",
|
| 3017 |
+
"integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==",
|
| 3018 |
+
"dependencies": {
|
| 3019 |
+
"swagger-ui-dist": ">=5.0.0"
|
| 3020 |
+
},
|
| 3021 |
+
"engines": {
|
| 3022 |
+
"node": ">= v0.10.32"
|
| 3023 |
+
},
|
| 3024 |
+
"peerDependencies": {
|
| 3025 |
+
"express": ">=4.0.0 || >=5.0.0-beta"
|
| 3026 |
+
}
|
| 3027 |
+
},
|
| 3028 |
"node_modules/tar": {
|
| 3029 |
"version": "6.2.1",
|
| 3030 |
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
|
|
|
| 3338 |
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
| 3339 |
"devOptional": true
|
| 3340 |
},
|
| 3341 |
+
"node_modules/validator": {
|
| 3342 |
+
"version": "13.15.20",
|
| 3343 |
+
"resolved": "https://registry.npmjs.org/validator/-/validator-13.15.20.tgz",
|
| 3344 |
+
"integrity": "sha512-KxPOq3V2LmfQPP4eqf3Mq/zrT0Dqp2Vmx2Bn285LwVahLc+CsxOM0crBHczm8ijlcjZ0Q5Xd6LW3z3odTPnlrw==",
|
| 3345 |
+
"engines": {
|
| 3346 |
+
"node": ">= 0.10"
|
| 3347 |
+
}
|
| 3348 |
+
},
|
| 3349 |
"node_modules/vary": {
|
| 3350 |
"version": "1.1.2",
|
| 3351 |
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
|
|
|
| 3557 |
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
| 3558 |
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
| 3559 |
},
|
| 3560 |
+
"node_modules/yaml": {
|
| 3561 |
+
"version": "2.0.0-1",
|
| 3562 |
+
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz",
|
| 3563 |
+
"integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==",
|
| 3564 |
+
"engines": {
|
| 3565 |
+
"node": ">= 6"
|
| 3566 |
+
}
|
| 3567 |
+
},
|
| 3568 |
"node_modules/yargs": {
|
| 3569 |
"version": "17.7.2",
|
| 3570 |
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
|
|
|
| 3635 |
"engines": {
|
| 3636 |
"node": ">=6"
|
| 3637 |
}
|
| 3638 |
+
},
|
| 3639 |
+
"node_modules/z-schema": {
|
| 3640 |
+
"version": "5.0.5",
|
| 3641 |
+
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz",
|
| 3642 |
+
"integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==",
|
| 3643 |
+
"dependencies": {
|
| 3644 |
+
"lodash.get": "^4.4.2",
|
| 3645 |
+
"lodash.isequal": "^4.5.0",
|
| 3646 |
+
"validator": "^13.7.0"
|
| 3647 |
+
},
|
| 3648 |
+
"bin": {
|
| 3649 |
+
"z-schema": "bin/z-schema"
|
| 3650 |
+
},
|
| 3651 |
+
"engines": {
|
| 3652 |
+
"node": ">=8.0.0"
|
| 3653 |
+
},
|
| 3654 |
+
"optionalDependencies": {
|
| 3655 |
+
"commander": "^9.4.1"
|
| 3656 |
+
}
|
| 3657 |
+
},
|
| 3658 |
+
"node_modules/z-schema/node_modules/commander": {
|
| 3659 |
+
"version": "9.5.0",
|
| 3660 |
+
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
|
| 3661 |
+
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
|
| 3662 |
+
"optional": true,
|
| 3663 |
+
"engines": {
|
| 3664 |
+
"node": "^12.20.0 || >=14"
|
| 3665 |
+
}
|
| 3666 |
}
|
| 3667 |
}
|
| 3668 |
}
|
package.json
CHANGED
|
@@ -27,6 +27,8 @@
|
|
| 27 |
"jsonwebtoken": "^9.0.2",
|
| 28 |
"pg": "^8.16.3",
|
| 29 |
"reflect-metadata": "^0.2.2",
|
|
|
|
|
|
|
| 30 |
"typeorm": "^0.3.27"
|
| 31 |
},
|
| 32 |
"devDependencies": {
|
|
@@ -35,6 +37,8 @@
|
|
| 35 |
"@types/express": "^5.0.5",
|
| 36 |
"@types/jsonwebtoken": "^9.0.10",
|
| 37 |
"@types/node": "^24.9.2",
|
|
|
|
|
|
|
| 38 |
"nodemon": "^3.1.10",
|
| 39 |
"ts-node": "^10.9.2",
|
| 40 |
"typescript": "^5.9.3"
|
|
|
|
| 27 |
"jsonwebtoken": "^9.0.2",
|
| 28 |
"pg": "^8.16.3",
|
| 29 |
"reflect-metadata": "^0.2.2",
|
| 30 |
+
"swagger-jsdoc": "^6.2.8",
|
| 31 |
+
"swagger-ui-express": "^5.0.0",
|
| 32 |
"typeorm": "^0.3.27"
|
| 33 |
},
|
| 34 |
"devDependencies": {
|
|
|
|
| 37 |
"@types/express": "^5.0.5",
|
| 38 |
"@types/jsonwebtoken": "^9.0.10",
|
| 39 |
"@types/node": "^24.9.2",
|
| 40 |
+
"@types/swagger-jsdoc": "^6.0.4",
|
| 41 |
+
"@types/swagger-ui-express": "^4.1.6",
|
| 42 |
"nodemon": "^3.1.10",
|
| 43 |
"ts-node": "^10.9.2",
|
| 44 |
"typescript": "^5.9.3"
|
src/index.ts
CHANGED
|
@@ -2,6 +2,8 @@ import "reflect-metadata";
|
|
| 2 |
import express from "express";
|
| 3 |
import cors from "cors";
|
| 4 |
import dotenv from "dotenv";
|
|
|
|
|
|
|
| 5 |
import { AppDataSource } from "./utils/dataSource";
|
| 6 |
import authRoute from "./routes/auth";
|
| 7 |
import uploadRoute from "./routes/upload";
|
|
@@ -14,15 +16,191 @@ const app = express();
|
|
| 14 |
app.use(cors());
|
| 15 |
app.use(express.json({ limit: "10mb" }));
|
| 16 |
|
| 17 |
-
|
| 18 |
-
app.
|
| 19 |
-
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
app.get("/health", (req, res) => {
|
| 23 |
res.json({ status: "healthy", database: AppDataSource.isInitialized });
|
| 24 |
});
|
| 25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
const PORT = process.env.PORT || 7860;
|
| 27 |
|
| 28 |
AppDataSource.initialize()
|
|
|
|
| 2 |
import express from "express";
|
| 3 |
import cors from "cors";
|
| 4 |
import dotenv from "dotenv";
|
| 5 |
+
import swaggerJsdoc from "swagger-jsdoc";
|
| 6 |
+
import swaggerUi from "swagger-ui-express";
|
| 7 |
import { AppDataSource } from "./utils/dataSource";
|
| 8 |
import authRoute from "./routes/auth";
|
| 9 |
import uploadRoute from "./routes/upload";
|
|
|
|
| 16 |
app.use(cors());
|
| 17 |
app.use(express.json({ limit: "10mb" }));
|
| 18 |
|
| 19 |
+
// Root endpoint with milestone information
|
| 20 |
+
app.get("/", (req, res) => {
|
| 21 |
+
res.json({
|
| 22 |
+
name: "StyleGPT Milestone 2",
|
| 23 |
+
version: "1.0.0",
|
| 24 |
+
description: "Visual Wardrobe Tagging & AI-Powered Outfit Suggestions",
|
| 25 |
+
milestone: 2,
|
| 26 |
+
features: [
|
| 27 |
+
"User Authentication (JWT-based)",
|
| 28 |
+
"Visual Wardrobe Management",
|
| 29 |
+
"AI-Powered Image Classification (Fashion-CLIP)",
|
| 30 |
+
"Smart Outfit Suggestions",
|
| 31 |
+
"User Profile Management"
|
| 32 |
+
],
|
| 33 |
+
endpoints: {
|
| 34 |
+
root: "/",
|
| 35 |
+
docs: "/docs",
|
| 36 |
+
health: "/health",
|
| 37 |
+
api: {
|
| 38 |
+
auth: "/api/auth",
|
| 39 |
+
profile: "/api/profile",
|
| 40 |
+
upload: "/api/upload",
|
| 41 |
+
suggest: "/api/suggest"
|
| 42 |
+
}
|
| 43 |
+
},
|
| 44 |
+
technologies: [
|
| 45 |
+
"Node.js",
|
| 46 |
+
"TypeScript",
|
| 47 |
+
"Express.js",
|
| 48 |
+
"PostgreSQL",
|
| 49 |
+
"TypeORM",
|
| 50 |
+
"Cloudinary",
|
| 51 |
+
"Hugging Face Fashion-CLIP",
|
| 52 |
+
"JWT Authentication"
|
| 53 |
+
]
|
| 54 |
+
});
|
| 55 |
+
});
|
| 56 |
+
|
| 57 |
+
// Swagger/OpenAPI configuration
|
| 58 |
+
const swaggerOptions: swaggerJsdoc.Options = {
|
| 59 |
+
definition: {
|
| 60 |
+
openapi: "3.0.0",
|
| 61 |
+
info: {
|
| 62 |
+
title: "StyleGPT Milestone 2 API",
|
| 63 |
+
version: "1.0.0",
|
| 64 |
+
description: "API documentation for StyleGPT Milestone 2 - Visual Wardrobe Tagging & AI-Powered Outfit Suggestions",
|
| 65 |
+
contact: {
|
| 66 |
+
name: "StyleGPT",
|
| 67 |
+
url: "https://huggingface.co/spaces/nexusbert/StyleGPT-milestone2"
|
| 68 |
+
}
|
| 69 |
+
},
|
| 70 |
+
servers: [
|
| 71 |
+
{
|
| 72 |
+
url: process.env.API_URL || `http://localhost:${process.env.PORT || 7860}`,
|
| 73 |
+
description: "API Server"
|
| 74 |
+
}
|
| 75 |
+
],
|
| 76 |
+
components: {
|
| 77 |
+
securitySchemes: {
|
| 78 |
+
bearerAuth: {
|
| 79 |
+
type: "http",
|
| 80 |
+
scheme: "bearer",
|
| 81 |
+
bearerFormat: "JWT"
|
| 82 |
+
}
|
| 83 |
+
},
|
| 84 |
+
schemas: {
|
| 85 |
+
User: {
|
| 86 |
+
type: "object",
|
| 87 |
+
properties: {
|
| 88 |
+
id: { type: "integer" },
|
| 89 |
+
name: { type: "string" },
|
| 90 |
+
email: { type: "string", format: "email" },
|
| 91 |
+
createdAt: { type: "string", format: "date-time" }
|
| 92 |
+
}
|
| 93 |
+
},
|
| 94 |
+
WardrobeItem: {
|
| 95 |
+
type: "object",
|
| 96 |
+
properties: {
|
| 97 |
+
id: { type: "integer" },
|
| 98 |
+
imageUrl: { type: "string", format: "uri" },
|
| 99 |
+
category: { type: "string" },
|
| 100 |
+
style: { type: "string", enum: ["formal", "casual", "streetwear"] },
|
| 101 |
+
userId: { type: "integer" },
|
| 102 |
+
createdAt: { type: "string", format: "date-time" }
|
| 103 |
+
}
|
| 104 |
+
},
|
| 105 |
+
RegisterRequest: {
|
| 106 |
+
type: "object",
|
| 107 |
+
required: ["name", "email", "password"],
|
| 108 |
+
properties: {
|
| 109 |
+
name: { type: "string" },
|
| 110 |
+
email: { type: "string", format: "email" },
|
| 111 |
+
password: { type: "string", minLength: 6 }
|
| 112 |
+
}
|
| 113 |
+
},
|
| 114 |
+
LoginRequest: {
|
| 115 |
+
type: "object",
|
| 116 |
+
required: ["email", "password"],
|
| 117 |
+
properties: {
|
| 118 |
+
email: { type: "string", format: "email" },
|
| 119 |
+
password: { type: "string" }
|
| 120 |
+
}
|
| 121 |
+
},
|
| 122 |
+
AuthResponse: {
|
| 123 |
+
type: "object",
|
| 124 |
+
properties: {
|
| 125 |
+
success: { type: "boolean" },
|
| 126 |
+
user: { $ref: "#/components/schemas/User" },
|
| 127 |
+
token: { type: "string" },
|
| 128 |
+
error: { type: "string" }
|
| 129 |
+
}
|
| 130 |
+
},
|
| 131 |
+
UploadRequest: {
|
| 132 |
+
type: "object",
|
| 133 |
+
required: ["imageUrl"],
|
| 134 |
+
properties: {
|
| 135 |
+
imageUrl: { type: "string", format: "uri" }
|
| 136 |
+
}
|
| 137 |
+
},
|
| 138 |
+
SuggestRequest: {
|
| 139 |
+
type: "object",
|
| 140 |
+
required: ["message"],
|
| 141 |
+
properties: {
|
| 142 |
+
message: { type: "string" },
|
| 143 |
+
session_id: { type: "string" }
|
| 144 |
+
}
|
| 145 |
+
}
|
| 146 |
+
}
|
| 147 |
+
},
|
| 148 |
+
tags: [
|
| 149 |
+
{ name: "Authentication", description: "User registration and login" },
|
| 150 |
+
{ name: "Profile", description: "User profile management" },
|
| 151 |
+
{ name: "Upload", description: "Wardrobe item upload and classification" },
|
| 152 |
+
{ name: "Suggest", description: "AI-powered outfit suggestions" },
|
| 153 |
+
{ name: "Health", description: "Health check endpoints" }
|
| 154 |
+
]
|
| 155 |
+
},
|
| 156 |
+
apis: ["./src/routes/*.ts", "./src/index.ts"]
|
| 157 |
+
};
|
| 158 |
+
|
| 159 |
+
const swaggerSpec = swaggerJsdoc(swaggerOptions);
|
| 160 |
+
|
| 161 |
+
// Swagger UI endpoint
|
| 162 |
+
app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec, {
|
| 163 |
+
customCss: ".swagger-ui .topbar { display: none }",
|
| 164 |
+
customSiteTitle: "StyleGPT Milestone 2 API Docs"
|
| 165 |
+
}));
|
| 166 |
|
| 167 |
+
// Swagger JSON endpoint
|
| 168 |
+
app.get("/docs.json", (req, res) => {
|
| 169 |
+
res.setHeader("Content-Type", "application/json");
|
| 170 |
+
res.send(swaggerSpec);
|
| 171 |
+
});
|
| 172 |
+
|
| 173 |
+
// Health check endpoint
|
| 174 |
+
/**
|
| 175 |
+
* @openapi
|
| 176 |
+
* /health:
|
| 177 |
+
* get:
|
| 178 |
+
* summary: Health check endpoint
|
| 179 |
+
* tags: [Health]
|
| 180 |
+
* responses:
|
| 181 |
+
* 200:
|
| 182 |
+
* description: Service is healthy
|
| 183 |
+
* content:
|
| 184 |
+
* application/json:
|
| 185 |
+
* schema:
|
| 186 |
+
* type: object
|
| 187 |
+
* properties:
|
| 188 |
+
* status:
|
| 189 |
+
* type: string
|
| 190 |
+
* example: healthy
|
| 191 |
+
* database:
|
| 192 |
+
* type: boolean
|
| 193 |
+
* example: true
|
| 194 |
+
*/
|
| 195 |
app.get("/health", (req, res) => {
|
| 196 |
res.json({ status: "healthy", database: AppDataSource.isInitialized });
|
| 197 |
});
|
| 198 |
|
| 199 |
+
app.use("/api/auth", authRoute);
|
| 200 |
+
app.use("/api/profile", profileRoute);
|
| 201 |
+
app.use("/api/upload", uploadRoute);
|
| 202 |
+
app.use("/api/suggest", suggestRoute);
|
| 203 |
+
|
| 204 |
const PORT = process.env.PORT || 7860;
|
| 205 |
|
| 206 |
AppDataSource.initialize()
|
src/routes/auth.ts
CHANGED
|
@@ -8,6 +8,30 @@ dotenv.config();
|
|
| 8 |
|
| 9 |
const router = express.Router();
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
router.post("/register", async (req, res) => {
|
| 12 |
try {
|
| 13 |
const { name, email, password } = req.body;
|
|
@@ -71,6 +95,30 @@ router.post("/register", async (req, res) => {
|
|
| 71 |
}
|
| 72 |
});
|
| 73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
router.post("/login", async (req, res) => {
|
| 75 |
try {
|
| 76 |
const { email, password } = req.body;
|
|
|
|
| 8 |
|
| 9 |
const router = express.Router();
|
| 10 |
|
| 11 |
+
/**
|
| 12 |
+
* @openapi
|
| 13 |
+
* /api/auth/register:
|
| 14 |
+
* post:
|
| 15 |
+
* summary: Register a new user
|
| 16 |
+
* tags: [Authentication]
|
| 17 |
+
* requestBody:
|
| 18 |
+
* required: true
|
| 19 |
+
* content:
|
| 20 |
+
* application/json:
|
| 21 |
+
* schema:
|
| 22 |
+
* $ref: "#/components/schemas/RegisterRequest"
|
| 23 |
+
* responses:
|
| 24 |
+
* 201:
|
| 25 |
+
* description: User registered successfully
|
| 26 |
+
* content:
|
| 27 |
+
* application/json:
|
| 28 |
+
* schema:
|
| 29 |
+
* $ref: "#/components/schemas/AuthResponse"
|
| 30 |
+
* 400:
|
| 31 |
+
* description: Bad request (missing fields, email exists, or weak password)
|
| 32 |
+
* 500:
|
| 33 |
+
* description: Server error
|
| 34 |
+
*/
|
| 35 |
router.post("/register", async (req, res) => {
|
| 36 |
try {
|
| 37 |
const { name, email, password } = req.body;
|
|
|
|
| 95 |
}
|
| 96 |
});
|
| 97 |
|
| 98 |
+
/**
|
| 99 |
+
* @openapi
|
| 100 |
+
* /api/auth/login:
|
| 101 |
+
* post:
|
| 102 |
+
* summary: Login user
|
| 103 |
+
* tags: [Authentication]
|
| 104 |
+
* requestBody:
|
| 105 |
+
* required: true
|
| 106 |
+
* content:
|
| 107 |
+
* application/json:
|
| 108 |
+
* schema:
|
| 109 |
+
* $ref: "#/components/schemas/LoginRequest"
|
| 110 |
+
* responses:
|
| 111 |
+
* 200:
|
| 112 |
+
* description: Login successful
|
| 113 |
+
* content:
|
| 114 |
+
* application/json:
|
| 115 |
+
* schema:
|
| 116 |
+
* $ref: "#/components/schemas/AuthResponse"
|
| 117 |
+
* 401:
|
| 118 |
+
* description: Invalid credentials
|
| 119 |
+
* 500:
|
| 120 |
+
* description: Server error
|
| 121 |
+
*/
|
| 122 |
router.post("/login", async (req, res) => {
|
| 123 |
try {
|
| 124 |
const { email, password } = req.body;
|
src/routes/profile.ts
CHANGED
|
@@ -5,6 +5,33 @@ import { authenticateToken, AuthRequest } from "../middleware/auth";
|
|
| 5 |
|
| 6 |
const router = express.Router();
|
| 7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
router.get("/", authenticateToken, async (req: AuthRequest, res) => {
|
| 9 |
try {
|
| 10 |
const userId = req.userId!;
|
|
|
|
| 5 |
|
| 6 |
const router = express.Router();
|
| 7 |
|
| 8 |
+
/**
|
| 9 |
+
* @openapi
|
| 10 |
+
* /api/profile:
|
| 11 |
+
* get:
|
| 12 |
+
* summary: Get user profile
|
| 13 |
+
* tags: [Profile]
|
| 14 |
+
* security:
|
| 15 |
+
* - bearerAuth: []
|
| 16 |
+
* responses:
|
| 17 |
+
* 200:
|
| 18 |
+
* description: Profile retrieved successfully
|
| 19 |
+
* content:
|
| 20 |
+
* application/json:
|
| 21 |
+
* schema:
|
| 22 |
+
* type: object
|
| 23 |
+
* properties:
|
| 24 |
+
* success:
|
| 25 |
+
* type: boolean
|
| 26 |
+
* user:
|
| 27 |
+
* $ref: "#/components/schemas/User"
|
| 28 |
+
* 401:
|
| 29 |
+
* description: Unauthorized
|
| 30 |
+
* 404:
|
| 31 |
+
* description: User not found
|
| 32 |
+
* 500:
|
| 33 |
+
* description: Server error
|
| 34 |
+
*/
|
| 35 |
router.get("/", authenticateToken, async (req: AuthRequest, res) => {
|
| 36 |
try {
|
| 37 |
const userId = req.userId!;
|
src/routes/suggest.ts
CHANGED
|
@@ -8,6 +8,40 @@ dotenv.config();
|
|
| 8 |
|
| 9 |
const router = express.Router();
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
router.post("/", authenticateToken, async (req: AuthRequest, res) => {
|
| 12 |
try {
|
| 13 |
const { message, session_id } = req.body;
|
|
|
|
| 8 |
|
| 9 |
const router = express.Router();
|
| 10 |
|
| 11 |
+
/**
|
| 12 |
+
* @openapi
|
| 13 |
+
* /api/suggest:
|
| 14 |
+
* post:
|
| 15 |
+
* summary: Get AI-powered outfit suggestions based on user's wardrobe
|
| 16 |
+
* tags: [Suggest]
|
| 17 |
+
* security:
|
| 18 |
+
* - bearerAuth: []
|
| 19 |
+
* requestBody:
|
| 20 |
+
* required: true
|
| 21 |
+
* content:
|
| 22 |
+
* application/json:
|
| 23 |
+
* schema:
|
| 24 |
+
* $ref: "#/components/schemas/SuggestRequest"
|
| 25 |
+
* responses:
|
| 26 |
+
* 200:
|
| 27 |
+
* description: Suggestions generated successfully
|
| 28 |
+
* content:
|
| 29 |
+
* application/json:
|
| 30 |
+
* schema:
|
| 31 |
+
* type: object
|
| 32 |
+
* properties:
|
| 33 |
+
* success:
|
| 34 |
+
* type: boolean
|
| 35 |
+
* suggestion:
|
| 36 |
+
* type: object
|
| 37 |
+
* description: AI-generated outfit suggestion from Milestone 1
|
| 38 |
+
* 400:
|
| 39 |
+
* description: Bad request (missing message)
|
| 40 |
+
* 401:
|
| 41 |
+
* description: Unauthorized
|
| 42 |
+
* 500:
|
| 43 |
+
* description: Server error
|
| 44 |
+
*/
|
| 45 |
router.post("/", authenticateToken, async (req: AuthRequest, res) => {
|
| 46 |
try {
|
| 47 |
const { message, session_id } = req.body;
|
src/routes/upload.ts
CHANGED
|
@@ -7,6 +7,39 @@ import { authenticateToken, AuthRequest } from "../middleware/auth";
|
|
| 7 |
|
| 8 |
const router = express.Router();
|
| 9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
router.post("/", authenticateToken, async (req: AuthRequest, res) => {
|
| 11 |
try {
|
| 12 |
const { imageUrl } = req.body;
|
|
|
|
| 7 |
|
| 8 |
const router = express.Router();
|
| 9 |
|
| 10 |
+
/**
|
| 11 |
+
* @openapi
|
| 12 |
+
* /api/upload:
|
| 13 |
+
* post:
|
| 14 |
+
* summary: Upload and classify a wardrobe item image
|
| 15 |
+
* tags: [Upload]
|
| 16 |
+
* security:
|
| 17 |
+
* - bearerAuth: []
|
| 18 |
+
* requestBody:
|
| 19 |
+
* required: true
|
| 20 |
+
* content:
|
| 21 |
+
* application/json:
|
| 22 |
+
* schema:
|
| 23 |
+
* $ref: "#/components/schemas/UploadRequest"
|
| 24 |
+
* responses:
|
| 25 |
+
* 200:
|
| 26 |
+
* description: Item uploaded and classified successfully
|
| 27 |
+
* content:
|
| 28 |
+
* application/json:
|
| 29 |
+
* schema:
|
| 30 |
+
* type: object
|
| 31 |
+
* properties:
|
| 32 |
+
* success:
|
| 33 |
+
* type: boolean
|
| 34 |
+
* item:
|
| 35 |
+
* $ref: "#/components/schemas/WardrobeItem"
|
| 36 |
+
* 400:
|
| 37 |
+
* description: Bad request (missing imageUrl)
|
| 38 |
+
* 401:
|
| 39 |
+
* description: Unauthorized
|
| 40 |
+
* 500:
|
| 41 |
+
* description: Server error
|
| 42 |
+
*/
|
| 43 |
router.post("/", authenticateToken, async (req: AuthRequest, res) => {
|
| 44 |
try {
|
| 45 |
const { imageUrl } = req.body;
|