diff --git a/backend/jest.config.ts b/backend/jest.config.ts new file mode 100644 index 00000000..f05e4bc4 --- /dev/null +++ b/backend/jest.config.ts @@ -0,0 +1,15 @@ +import type { Config } from 'jest'; + +const config: Config = { + moduleFileExtensions: ['js', 'json', 'ts'], + rootDir: 'src', + testRegex: '.*\\.spec\\.ts$', + transform: { + '^.+\\.(t|j)s$': 'ts-jest', + }, + collectCoverageFrom: ['**/*.(t|j)s'], + coverageDirectory: '../coverage', + testEnvironment: 'node', // ✅ must be node for NestJS +}; + +export default config; \ No newline at end of file diff --git a/backend/output.txt b/backend/output.txt new file mode 100644 index 00000000..c6c588d7 --- /dev/null +++ b/backend/output.txt @@ -0,0 +1,570 @@ +C:\Users\USER\Desktop\KING\Clones\InsightArena\backend +├── data-source.ts +├── dist +| ├── data-source.d.ts +| ├── data-source.js +| ├── data-source.js.map +| ├── src +| └── tsconfig.build.tsbuildinfo +├── eslint.config.mjs +├── Makefile +├── nest-cli.json +├── node_modules +| ├── @angular-devkit +| ├── @babel +| ├── @bcoe +| ├── @borewit +| ├── @colors +| ├── @cspotcode +| ├── @emnapi +| ├── @eslint +| ├── @eslint-community +| ├── @humanfs +| ├── @humanwhocodes +| ├── @inquirer +| ├── @isaacs +| ├── @istanbuljs +| ├── @jest +| ├── @jridgewell +| ├── @lukeed +| ├── @microsoft +| ├── @napi-rs +| ├── @nestjs +| ├── @noble +| ├── @nuxt +| ├── @paralleldrive +| ├── @pkgjs +| ├── @pkgr +| ├── @scarf +| ├── @sinclair +| ├── @sinonjs +| ├── @sqltools +| ├── @stellar +| ├── @tokenizer +| ├── @tsconfig +| ├── @tybys +| ├── @types +| ├── @typescript-eslint +| ├── @ungap +| ├── @unrs +| ├── @webassemblyjs +| ├── @xtuc +| ├── accepts +| ├── acorn +| ├── acorn-import-phases +| ├── acorn-jsx +| ├── acorn-walk +| ├── ajv +| ├── ajv-formats +| ├── ajv-keywords +| ├── ansi-colors +| ├── ansi-escapes +| ├── ansi-regex +| ├── ansi-styles +| ├── ansis +| ├── anymatch +| ├── app-root-path +| ├── append-field +| ├── arg +| ├── argparse +| ├── array-timsort +| ├── asap +| ├── asynckit +| ├── available-typed-arrays +| ├── axios +| ├── babel-jest +| ├── babel-plugin-istanbul +| ├── babel-plugin-jest-hoist +| ├── babel-preset-current-node-syntax +| ├── babel-preset-jest +| ├── balanced-match +| ├── base32.js +| ├── base64-js +| ├── baseline-browser-mapping +| ├── bcrypt +| ├── bignumber.js +| ├── bl +| ├── body-parser +| ├── brace-expansion +| ├── braces +| ├── browserslist +| ├── bs-logger +| ├── bser +| ├── buffer +| ├── buffer-equal-constant-time +| ├── buffer-from +| ├── busboy +| ├── bytes +| ├── call-bind +| ├── call-bind-apply-helpers +| ├── call-bound +| ├── callsites +| ├── camelcase +| ├── caniuse-lite +| ├── chalk +| ├── char-regex +| ├── chardet +| ├── chokidar +| ├── chrome-trace-event +| ├── ci-info +| ├── cjs-module-lexer +| ├── class-transformer +| ├── class-validator +| ├── cli-cursor +| ├── cli-spinners +| ├── cli-table3 +| ├── cli-width +| ├── cliui +| ├── clone +| ├── co +| ├── collect-v8-coverage +| ├── color-convert +| ├── color-name +| ├── combined-stream +| ├── commander +| ├── comment-json +| ├── component-emitter +| ├── concat-map +| ├── concat-stream +| ├── consola +| ├── content-disposition +| ├── content-type +| ├── convert-source-map +| ├── cookie +| ├── cookie-signature +| ├── cookiejar +| ├── core-util-is +| ├── cors +| ├── cosmiconfig +| ├── create-require +| ├── cron +| ├── cross-spawn +| ├── dayjs +| ├── debug +| ├── dedent +| ├── deep-is +| ├── deepmerge +| ├── defaults +| ├── define-data-property +| ├── delayed-stream +| ├── depd +| ├── detect-newline +| ├── dezalgo +| ├── diff +| ├── dotenv +| ├── dotenv-expand +| ├── dunder-proto +| ├── eastasianwidth +| ├── ecdsa-sig-formatter +| ├── ee-first +| ├── electron-to-chromium +| ├── emittery +| ├── emoji-regex +| ├── encodeurl +| ├── enhanced-resolve +| ├── error-ex +| ├── es-define-property +| ├── es-errors +| ├── es-module-lexer +| ├── es-object-atoms +| ├── es-set-tostringtag +| ├── escalade +| ├── escape-html +| ├── escape-string-regexp +| ├── eslint +| ├── eslint-config-prettier +| ├── eslint-plugin-prettier +| ├── eslint-scope +| ├── eslint-visitor-keys +| ├── espree +| ├── esprima +| ├── esquery +| ├── esrecurse +| ├── estraverse +| ├── esutils +| ├── etag +| ├── events +| ├── eventsource +| ├── execa +| ├── exit-x +| ├── expect +| ├── express +| ├── fast-deep-equal +| ├── fast-diff +| ├── fast-json-stable-stringify +| ├── fast-levenshtein +| ├── fast-safe-stringify +| ├── fast-uri +| ├── fb-watchman +| ├── fdir +| ├── feaxios +| ├── file-entry-cache +| ├── file-type +| ├── fill-range +| ├── finalhandler +| ├── find-up +| ├── flat-cache +| ├── flatted +| ├── follow-redirects +| ├── for-each +| ├── foreground-child +| ├── fork-ts-checker-webpack-plugin +| ├── form-data +| ├── formidable +| ├── forwarded +| ├── fresh +| ├── fs-extra +| ├── fs-monkey +| ├── fs.realpath +| ├── function-bind +| ├── gensync +| ├── get-caller-file +| ├── get-intrinsic +| ├── get-package-type +| ├── get-proto +| ├── get-stream +| ├── glob +| ├── glob-parent +| ├── glob-to-regexp +| ├── globals +| ├── gopd +| ├── graceful-fs +| ├── handlebars +| ├── has-flag +| ├── has-property-descriptors +| ├── has-symbols +| ├── has-tostringtag +| ├── hasown +| ├── html-escaper +| ├── http-errors +| ├── human-signals +| ├── iconv-lite +| ├── ieee754 +| ├── ignore +| ├── import-fresh +| ├── import-local +| ├── imurmurhash +| ├── inflight +| ├── inherits +| ├── ipaddr.js +| ├── is-arrayish +| ├── is-callable +| ├── is-extglob +| ├── is-fullwidth-code-point +| ├── is-generator-fn +| ├── is-glob +| ├── is-interactive +| ├── is-number +| ├── is-promise +| ├── is-retry-allowed +| ├── is-stream +| ├── is-typed-array +| ├── is-unicode-supported +| ├── isarray +| ├── isexe +| ├── istanbul-lib-coverage +| ├── istanbul-lib-instrument +| ├── istanbul-lib-report +| ├── istanbul-lib-source-maps +| ├── istanbul-reports +| ├── iterare +| ├── jackspeak +| ├── jest +| ├── jest-changed-files +| ├── jest-circus +| ├── jest-cli +| ├── jest-config +| ├── jest-diff +| ├── jest-docblock +| ├── jest-each +| ├── jest-environment-node +| ├── jest-haste-map +| ├── jest-leak-detector +| ├── jest-matcher-utils +| ├── jest-message-util +| ├── jest-mock +| ├── jest-pnp-resolver +| ├── jest-regex-util +| ├── jest-resolve +| ├── jest-resolve-dependencies +| ├── jest-runner +| ├── jest-runtime +| ├── jest-snapshot +| ├── jest-util +| ├── jest-validate +| ├── jest-watcher +| ├── jest-worker +| ├── js-tokens +| ├── js-yaml +| ├── jsesc +| ├── json-buffer +| ├── json-parse-even-better-errors +| ├── json-schema-traverse +| ├── json-stable-stringify-without-jsonify +| ├── json5 +| ├── jsonc-parser +| ├── jsonfile +| ├── jsonwebtoken +| ├── jwa +| ├── jws +| ├── keyv +| ├── leven +| ├── levn +| ├── libphonenumber-js +| ├── lines-and-columns +| ├── load-esm +| ├── loader-runner +| ├── locate-path +| ├── lodash +| ├── lodash.includes +| ├── lodash.isboolean +| ├── lodash.isinteger +| ├── lodash.isnumber +| ├── lodash.isplainobject +| ├── lodash.isstring +| ├── lodash.memoize +| ├── lodash.merge +| ├── lodash.once +| ├── log-symbols +| ├── lru-cache +| ├── luxon +| ├── magic-string +| ├── make-dir +| ├── make-error +| ├── makeerror +| ├── math-intrinsics +| ├── media-typer +| ├── memfs +| ├── merge-descriptors +| ├── merge-stream +| ├── methods +| ├── micromatch +| ├── mime +| ├── mime-db +| ├── mime-types +| ├── mimic-fn +| ├── minimatch +| ├── minimist +| ├── minipass +| ├── ms +| ├── multer +| ├── mute-stream +| ├── napi-postinstall +| ├── natural-compare +| ├── negotiator +| ├── neo-async +| ├── node-abort-controller +| ├── node-addon-api +| ├── node-emoji +| ├── node-gyp-build +| ├── node-int64 +| ├── node-releases +| ├── normalize-path +| ├── npm-run-path +| ├── object-assign +| ├── object-inspect +| ├── on-finished +| ├── once +| ├── onetime +| ├── optionator +| ├── ora +| ├── p-limit +| ├── p-locate +| ├── p-try +| ├── package-json-from-dist +| ├── parent-module +| ├── parse-json +| ├── parseurl +| ├── passport +| ├── passport-jwt +| ├── passport-strategy +| ├── path-exists +| ├── path-is-absolute +| ├── path-key +| ├── path-scurry +| ├── path-to-regexp +| ├── path-type +| ├── pause +| ├── pg +| ├── pg-cloudflare +| ├── pg-connection-string +| ├── pg-int8 +| ├── pg-pool +| ├── pg-protocol +| ├── pg-types +| ├── pgpass +| ├── picocolors +| ├── picomatch +| ├── pirates +| ├── pkg-dir +| ├── pluralize +| ├── possible-typed-array-names +| ├── postgres-array +| ├── postgres-bytea +| ├── postgres-date +| ├── postgres-interval +| ├── prelude-ls +| ├── prettier +| ├── prettier-linter-helpers +| ├── pretty-format +| ├── proxy-addr +| ├── proxy-from-env +| ├── punycode +| ├── pure-rand +| ├── qs +| ├── randombytes +| ├── range-parser +| ├── raw-body +| ├── react-is +| ├── readable-stream +| ├── readdirp +| ├── reflect-metadata +| ├── require-directory +| ├── require-from-string +| ├── resolve-cwd +| ├── resolve-from +| ├── restore-cursor +| ├── router +| ├── rxjs +| ├── safe-buffer +| ├── safer-buffer +| ├── schema-utils +| ├── semver +| ├── send +| ├── serve-static +| ├── set-function-length +| ├── setprototypeof +| ├── sha.js +| ├── shebang-command +| ├── shebang-regex +| ├── side-channel +| ├── side-channel-list +| ├── side-channel-map +| ├── side-channel-weakmap +| ├── signal-exit +| ├── slash +| ├── source-map +| ├── source-map-support +| ├── split2 +| ├── sprintf-js +| ├── sql-highlight +| ├── stack-utils +| ├── statuses +| ├── streamsearch +| ├── string-length +| ├── string-width +| ├── string-width-cjs +| ├── string_decoder +| ├── strip-ansi +| ├── strip-ansi-cjs +| ├── strip-bom +| ├── strip-final-newline +| ├── strip-json-comments +| ├── strtok3 +| ├── superagent +| ├── supertest +| ├── supports-color +| ├── swagger-ui-dist +| ├── swagger-ui-express +| ├── symbol-observable +| ├── synckit +| ├── tapable +| ├── terser +| ├── terser-webpack-plugin +| ├── test-exclude +| ├── tinyglobby +| ├── tmpl +| ├── to-buffer +| ├── to-regex-range +| ├── toidentifier +| ├── token-types +| ├── toml +| ├── ts-api-utils +| ├── ts-jest +| ├── ts-loader +| ├── ts-node +| ├── tsconfig-paths +| ├── tsconfig-paths-webpack-plugin +| ├── tslib +| ├── type-check +| ├── type-detect +| ├── type-fest +| ├── type-is +| ├── typed-array-buffer +| ├── typedarray +| ├── typeorm +| ├── typescript +| ├── typescript-eslint +| ├── uglify-js +| ├── uid +| ├── uint8array-extras +| ├── undici-types +| ├── universalify +| ├── unpipe +| ├── unrs-resolver +| ├── update-browserslist-db +| ├── uri-js +| ├── urijs +| ├── util-deprecate +| ├── utils-merge +| ├── uuid +| ├── v8-compile-cache-lib +| ├── v8-to-istanbul +| ├── validator +| ├── vary +| ├── walker +| ├── watchpack +| ├── wcwidth +| ├── webpack +| ├── webpack-node-externals +| ├── webpack-sources +| ├── which +| ├── which-typed-array +| ├── word-wrap +| ├── wordwrap +| ├── wrap-ansi +| ├── wrap-ansi-cjs +| ├── wrappy +| ├── write-file-atomic +| ├── xtend +| ├── y18n +| ├── yallist +| ├── yargs +| ├── yargs-parser +| ├── yn +| ├── yocto-queue +| └── yoctocolors-cjs +├── output.txt +├── package-lock.json +├── package.json +├── pnpm-lock.yaml +├── README.md +├── src +| ├── app.controller.spec.ts +| ├── app.controller.ts +| ├── app.module.ts +| ├── app.service.ts +| ├── auth +| ├── common +| ├── competitions +| ├── config +| ├── health +| ├── leaderboard +| ├── main.ts +| ├── markets +| ├── migrations +| ├── notifications +| ├── predictions +| ├── soroban +| ├── types +| └── users +├── test +| ├── app.e2e-spec.ts +| ├── jest-e2e.json +| ├── markets.e2e-spec.ts +| └── users.e2e-spec.ts +├── tsconfig.build.json +└── tsconfig.json + +directory: 542 file: 24 + diff --git a/backend/package-lock.json b/backend/package-lock.json index 9f691ac3..41e3d058 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1796,9 +1796,9 @@ } }, "node_modules/@jest/reporters/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -2823,9 +2823,9 @@ "license": "Apache-2.0" }, "node_modules/@sinclair/typebox": { - "version": "0.34.48", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz", - "integrity": "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==", + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", "dev": true, "license": "MIT" }, @@ -3519,9 +3519,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4352,14 +4352,14 @@ } }, "node_modules/axios": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", - "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.14.0.tgz", + "integrity": "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", - "proxy-from-env": "^1.1.0" + "proxy-from-env": "^2.1.0" } }, "node_modules/babel-jest": { @@ -4497,9 +4497,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.10", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.10.tgz", - "integrity": "sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ==", + "version": "2.10.11", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.11.tgz", + "integrity": "sha512-DAKrHphkJyiGuau/cFieRYhcTFeK/lBuD++C7cZ6KZHbMhBrisoi+EvhQ5RZrIfV5qwsW8kgQ07JIC+MDJRAhg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4657,9 +4657,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -5577,9 +5577,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.321", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.321.tgz", - "integrity": "sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==", + "version": "1.5.328", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.328.tgz", + "integrity": "sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==", "dev": true, "license": "ISC" }, @@ -6601,9 +6601,9 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6662,9 +6662,9 @@ "license": "ISC" }, "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7323,9 +7323,9 @@ } }, "node_modules/jest-config/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -7728,9 +7728,9 @@ } }, "node_modules/jest-runtime/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "dev": true, "license": "MIT", "dependencies": { @@ -8637,9 +8637,9 @@ "license": "MIT" }, "node_modules/node-addon-api": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.6.0.tgz", - "integrity": "sha512-gBVjCaqDlRUk0EwoPNKzIr9KkS9041G/q31IBShPs1Xz6UTA+EXdZADbzqAJQrpDRq71CIMnOP5VMut3SL0z5Q==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", "license": "MIT", "engines": { "node": "^18 || ^20 || >= 21" @@ -9448,10 +9448,13 @@ } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/pump": { "version": "3.0.4", @@ -11005,9 +11008,9 @@ } }, "node_modules/typeorm/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" diff --git a/backend/package.json b/backend/package.json index f3e5df8d..d2e7c717 100644 --- a/backend/package.json +++ b/backend/package.json @@ -14,9 +14,9 @@ "swagger:export": "SWAGGER_EXPORT=true node dist/src/main", "start:prod": "node dist/src/main", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", - "test": "jest", - "test:watch": "jest --watch", - "test:cov": "jest --coverage", + "test": "jest --config jest.config.ts", + "test:watch": "jest --watch --config jest.config.ts", + "test:cov": "jest --coverage --config jest.config.ts", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:e2e": "jest --config ./test/jest-e2e.json", "migration:generate": "typeorm-ts-node-commonjs migration:generate -d data-source.ts", @@ -78,22 +78,5 @@ "tsconfig-paths": "^4.2.0", "typescript": "^5.7.3", "typescript-eslint": "^8.20.0" - }, - "jest": { - "moduleFileExtensions": [ - "js", - "json", - "ts" - ], - "rootDir": "src", - "testRegex": ".*\\.spec\\.ts$", - "transform": { - "^.+\\.(t|j)s$": "ts-jest" - }, - "collectCoverageFrom": [ - "**/*.(t|j)s" - ], - "coverageDirectory": "../coverage", - "testEnvironment": "node" } } diff --git a/backend/src/auth/auth.controller.ts b/backend/src/auth/auth.controller.ts index 239cfd8a..c5ed2b66 100644 --- a/backend/src/auth/auth.controller.ts +++ b/backend/src/auth/auth.controller.ts @@ -1,8 +1,12 @@ +import { Body, Controller, Get, HttpCode, HttpStatus, Post, UseGuards } from '@nestjs/common'; import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common'; import { Throttle } from '@nestjs/throttler'; import { AuthService } from './auth.service'; import { GenerateChallengeDto } from './dto/generate-challenge.dto'; import { VerifyChallengeDto } from './dto/verify-challenge.dto'; +import { JwtAuthGuard } from './guards/jwt-auth.guard'; +import { CurrentUser } from '../common/decorators/current-user.decorator'; +import { User } from '../users/entities/user.entity'; @Throttle({ default: { limit: 10, ttl: 60000 } }) @Controller('auth') @@ -26,4 +30,12 @@ export class AuthController { verifyChallengeDto.signed_challenge, ); } -} + + // Authenticated route using @CurrentUser + @UseGuards(JwtAuthGuard) + @Get('me') + @HttpCode(HttpStatus.OK) + getProfile(@CurrentUser() user: User) { + return user; + } +} \ No newline at end of file diff --git a/backend/src/auth/guards/jwt-auth.guard.ts b/backend/src/auth/guards/jwt-auth.guard.ts new file mode 100644 index 00000000..029da5c5 --- /dev/null +++ b/backend/src/auth/guards/jwt-auth.guard.ts @@ -0,0 +1,6 @@ + +import { Injectable } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; + +@Injectable() +export class JwtAuthGuard extends AuthGuard('jwt') {} \ No newline at end of file diff --git a/backend/src/common/decorators/current-user.decorator.spec.ts b/backend/src/common/decorators/current-user.decorator.spec.ts new file mode 100644 index 00000000..d92a5da7 --- /dev/null +++ b/backend/src/common/decorators/current-user.decorator.spec.ts @@ -0,0 +1,38 @@ +import { ExecutionContext, UnauthorizedException } from '@nestjs/common'; +import { CurrentUser } from './current-user.decorator'; +import { User } from '../../users/entities/user.entity'; + +describe('CurrentUser Decorator', () => { + /** + * Mock ExecutionContext + */ + const createMockExecutionContext = (user?: Partial): ExecutionContext => + ({ + switchToHttp: () => ({ + getRequest: () => ({ + user, + }), + }), + } as unknown as ExecutionContext); + + it('should return the user when request.user exists', () => { + const mockUser = { + id: '123', + email: 'test@example.com', + } as unknown as User; // ✅ FIX + + const ctx = createMockExecutionContext(mockUser); + + const result = (CurrentUser as any).factory(undefined, ctx); + + expect(result).toEqual(mockUser); + }); + + it('should throw UnauthorizedException when user is missing', () => { + const ctx = createMockExecutionContext(undefined); + + expect(() => + (CurrentUser as any).factory(undefined, ctx), + ).toThrow(UnauthorizedException); + }); +}); \ No newline at end of file diff --git a/backend/src/common/decorators/current-user.decorator.ts b/backend/src/common/decorators/current-user.decorator.ts index 00de4f82..9c5705c6 100644 --- a/backend/src/common/decorators/current-user.decorator.ts +++ b/backend/src/common/decorators/current-user.decorator.ts @@ -1,10 +1,18 @@ -import { createParamDecorator, ExecutionContext } from '@nestjs/common'; -import type { Request } from 'express'; +import { createParamDecorator, ExecutionContext, UnauthorizedException } from '@nestjs/common'; +import { Request } from 'express'; import { User } from '../../users/entities/user.entity'; export const CurrentUser = createParamDecorator( - (data: unknown, ctx: ExecutionContext): User => { - const request = ctx.switchToHttp().getRequest(); - return request.user; + (data: keyof User | undefined, ctx: ExecutionContext) => { + const request = ctx.switchToHttp().getRequest(); + const user = request.user as User | undefined; + + if (!user) { + throw new UnauthorizedException( + 'User not found on request. Make sure the route is protected by JwtAuthGuard and that the strategy returns the full User entity.', + ); + } + + return data ? user[data] : user; }, -); +); \ No newline at end of file diff --git a/backend/tsconfig.json b/backend/tsconfig.json index aba29b0e..8ced230f 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -20,6 +20,7 @@ "forceConsistentCasingInFileNames": true, "noImplicitAny": false, "strictBindCallApply": false, - "noFallthroughCasesInSwitch": false + "noFallthroughCasesInSwitch": false, + "typeRoots": ["./node_modules/@types", "./src/types"] } }