Repository navigation
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe PR replaces the legacy post/comment model with research spaces, adds access/refresh token authentication with rotation and revocation, updates API documentation and middleware, and configures Prisma, path aliases, linting, formatting, and build tooling. ChangesFolio API migration
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
Comment |
There was a problem hiding this comment.
Actionable comments posted: 18
🧹 Nitpick comments (7)
src/prisma/seeds/space.seed.ts (1)
53-65: 📐 Maintainability & Code Quality | 🔵 TrivialReseeding won't update existing space content.
update: {}means if the seed'sname/researchObjectivevalues change later, re-running the script against an already-seeded DB leaves stale rows untouched. Consider populatingupdatewith the same fields if idempotent refresh is desired.
[optional_refactor_low_reward_skip_consideration]🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/prisma/seeds/space.seed.ts` around lines 53 - 65, Update the researchSpace.upsert call so its update branch refreshes existing records with the seed-controlled name and researchObjective values, while preserving the current create fields and stable seed-space-${i} identity.src/prisma/migrations/20260730035148_add_token_version_field_to_user/migration.sql (1)
1-19: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winSame schema-churn concern as the init migration.
This migration drops
authRef(added one day earlier) and re-addspasswordasNOT NULLwithout a default — confirming these two migrations should be squashed together rather than shipped as sequential, self-reversing steps. See the comment on20260729070404_init_database/migration.sql.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/prisma/migrations/20260730035148_add_token_version_field_to_user/migration.sql` around lines 1 - 19, Squash the changes from migration 20260730035148_add_token_version_field_to_user into the preceding init migration instead of shipping sequential schema changes. Remove the standalone migration’s drop of User.authRef and re-addition of User.password, and ensure the consolidated migration creates the final User schema directly while preserving refreshToken uniqueness and tokenVersion’s default.src/prisma/migrations/20260729070404_init_database/migration.sql (1)
1-174: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winSquash the two User migrations before merging.
src/prisma/migrations/20260729070404_init_database/migration.sqlandsrc/prisma/migrations/20260730035148_add_token_version_field_to_user/migration.sqlimmediately undo each other onUser(authRef↔password), so combining them into one coherent migration will avoid churn and a fragile intermediate state.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/prisma/migrations/20260729070404_init_database/migration.sql` around lines 1 - 174, Consolidate the User changes from the adjacent add_token_version_field_to_user migration into the init_database migration so User is transformed directly to its final schema, without the intermediate authRef/password reversal. Update the User table alteration and related constraints/indexes to match the final model, then remove the redundant follow-up migration while preserving all non-User schema changes.Source: Linters/SAST tools
src/api/services/auth.service.ts (2)
224-235: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winCombine the revocation writes into one atomic update.
updateRefreshToken(userId, null)andincrementTokenVersion(userId)are two independent awaited writes. If the second call fails after the first succeeds, the session ends up in a partial state (refresh token cleared but version not bumped) and costs an extra DB round-trip. SinceUserRepository.updatealready accepts an arbitraryPrisma.UserUpdateInput, both fields can be set in a single call.♻️ Proposed fix
const logout = async (userId: string) => { try { - await UserRepository.updateRefreshToken(userId, null); - await UserRepository.incrementTokenVersion(userId); + await UserRepository.update(userId, { + refreshToken: null, + tokenVersion: { increment: 1 } + }); } catch {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/api/services/auth.service.ts` around lines 224 - 235, Update logout to replace the separate UserRepository.updateRefreshToken and UserRepository.incrementTokenVersion calls with one UserRepository.update invocation using a Prisma.UserUpdateInput that clears the refresh token and atomically increments the token version. Preserve the existing error handling and userId targeting.
88-117: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winMinor timing side-channel on login.
Returning immediately when
!user(before doing any bcrypt work) versus doing a bcrypt compare when the user exists creates a measurable timing difference between "no such email" and "wrong password" cases, which can aid email enumeration despite identical error messages. Running a dummybcrypt.compareagainst a static hash on the not-found path equalizes timing.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/api/services/auth.service.ts` around lines 88 - 117, Update the login function’s !user path to run bcrypt.compare with the supplied password and a static dummy hash before throwing the existing INVALID_CREDENTIALS AppError. Keep the existing user-password comparison for found users and preserve the same response and error behavior.src/api/services/user.service.ts (1)
14-20: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winNo not-found handling on update; a bad id will surface as a raw exception.
UserRepository.updatecallsprisma.user.update, which throws (PrismaP2025) if the record doesn't exist. UnlikegetOne, this path isn't wrapped into a structuredAppError, so callers get an unhandled/raw error instead of a consistent404 NOT_FOUNDresponse.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/api/services/user.service.ts` around lines 14 - 20, Update the update function to handle UserRepository.update failures consistently with getOne: detect Prisma’s record-not-found condition (P2025), convert it to the established AppError representing a 404 NOT_FOUND response, and preserve existing behavior for successful updates and unrelated errors.src/api/index.ts (1)
17-30: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider mounting
corsbefore the body parsers, and gating the docs endpoints.CORS still functions here, but bodies are parsed for requests from disallowed origins. Moving
cors(corsOptions)aboveexpress.json()avoids that work. Separately,/api-docsand/api-docs.jsonare publicly served in every environment — gate them behindenv.NODE_ENV !== 'production'(or auth) if the spec isn't meant to be public.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/api/index.ts` around lines 17 - 30, In the Express app setup, move cors(corsOptions) before express.json() and express.urlencoded() so disallowed requests are rejected before body parsing. Gate both the /api-docs.json route and the /api-docs Swagger middleware behind env.NODE_ENV !== 'production', preserving their current behavior in non-production environments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.gitignore:
- Around line 22-23: Update the package.json build/prebuild configuration so the
Prisma generation command runs before tsc and tsc-alias. Reuse the existing
db:generate script, ensuring a clean yarn build creates src/generated/prisma
before compilation.
In @.yarnrc.yml:
- Around line 1-8: Harden the Yarn settings by replacing the unrestricted
approvedGitRepositories pattern with trusted repository patterns, setting
enableScripts to false, and changing npmMinimalAgeGate to a nonzero duration.
Preserve nodeLinker: node-modules.
In `@package.json`:
- Line 7: Update the package.json lint script to quote the src/**/*.ts glob so
the shell passes it unchanged to ESLint, ensuring nested TypeScript files are
discovered consistently.
- Line 6: Update the build script’s tsc-alias invocation to enable full-path
resolution and configure the resolved extension as “.js”, ensuring emitted ESM
imports are compatible with Node’s resolver.
In `@src/api/controllers/user.controller.ts`:
- Around line 6-9: Restrict the getOne controller to self-only access: require
the requested id to be “me” (or otherwise match req.userId) and reject other
user IDs before calling UserService.getOne. Verify the user route is mounted
behind authentication middleware so req.userId is populated, and remove the
unsafe non-null assumption if the project’s auth pattern requires explicit
validation.
In `@src/api/middlewares/auth.middleware.ts`:
- Around line 11-62: Update the auth middleware around verifyAccessToken and
UserRepository.findById so only JWT verification errors are translated into
authentication responses; allow database lookup failures to propagate to the
generic error handler as server errors. Preserve the existing token-expired and
invalid-token handling, while keeping token revocation checks after a successful
user lookup.
In `@src/api/middlewares/request-logger.middleware.ts`:
- Around line 12-17: Update getRequestId to validate that a client-supplied
x-request-id is both within REQUEST_ID_MAX_LENGTH and composed only of a safe
permitted character set, rejecting values containing control or other unsafe
characters and falling back to randomUUID().
In `@src/api/services/auth.service.ts`:
- Around line 44-57: Update the catch around UserRepository.create in the
authentication service to handle only Prisma error code P2002 as
EMAIL_EXISTS/CONFLICT; rethrow all other errors so they propagate as
INTERNAL_ERROR instead of being misclassified as duplicate-email failures.
In `@src/api/services/space.service.ts`:
- Around line 12-29: Update create to rely on the ResearchSpace database
uniqueness constraint for ownerId and name, while retaining the pre-check if
desired. Catch Prisma P2002 unique-violation errors from SpaceRepository.create
and convert them to the same SPACE_NAME_EXISTS AppError with CONFLICT status;
rethrow all other errors unchanged.
In `@src/api/services/user.service.ts`:
- Around line 6-12: Update getOne to catch the not-found error from
UserRepository.findOne, which uses findFirstOrThrow, and translate it into the
existing AppError with StatusCodes.NOT_FOUND instead of relying on an
unreachable null check. Apply the same not-found mapping in update around
prisma.user.update, preserving other errors unchanged.
In `@src/api/utils/constants.ts`:
- Line 3: Update PASSWORD_MIN_LENGTH to 8 in the constants definition so signup
and login validation enforce the documented minimum password length.
In `@src/api/utils/token.util.ts`:
- Around line 63-69: Update verifyAccessToken and verifyRefreshToken to pass the
same issuer, audience, and TOKEN_CONFIG-aligned algorithms: ['HS256']
constraints used when signing tokens. Preserve each function’s existing secret
and payload return behavior while ensuring jwt.verify rejects tokens from other
contexts or using different algorithms.
In `@src/config/cors.ts`:
- Around line 4-12: Update the origin callback in corsOptions to trim each value
produced by env.CORS_ORIGIN.split(',') before comparing it with origin, and
reject disallowed origins via callback(null, false) instead of passing an Error.
Preserve the existing allow behavior for missing or configured origins.
In `@src/config/enviroment.ts`:
- Around line 24-28: Update the token-secret configuration around
JWT_TOKEN_SECRET and REFRESH_TOKEN_SECRET to reject missing or empty values
during startup instead of defaulting to ''. Preserve the existing expiration and
CORS defaults, and add startup validation that the two required secrets are
distinct before authentication proceeds.
In `@src/index.ts`:
- Line 16: Update the startup flow around startApiServer() to explicitly handle
rejected promises from api.server() or awaited initialization, logging the
failure and terminating with a non-zero exit status so the process cannot remain
alive without a listener.
In `@src/prisma/schema.prisma`:
- Around line 24-45: Update the ResearchSpace model to add a composite unique
constraint on ownerId and name, which also provides the needed lookup index for
owner-scoped queries and enforces duplicate-name prevention at the database
level.
In `@src/prisma/seeds/space.seed.ts`:
- Around line 13-16: Update the user creation and reuse log statements around
the seed flow to remove user.email from console output, retaining only the
non-sensitive user.id needed for identification.
In `@tsconfig.json`:
- Around line 3-15: Update the TypeScript module-resolution/build configuration
around module: Preserve so emitted dist files are directly executable by the
package’s Node ESM runtime. Add or configure the required full-path rewrite step
to append .js extensions to extensionless relative imports, or use an
established loader, while preserving the existing ~/* alias resolution.
---
Nitpick comments:
In `@src/api/index.ts`:
- Around line 17-30: In the Express app setup, move cors(corsOptions) before
express.json() and express.urlencoded() so disallowed requests are rejected
before body parsing. Gate both the /api-docs.json route and the /api-docs
Swagger middleware behind env.NODE_ENV !== 'production', preserving their
current behavior in non-production environments.
In `@src/api/services/auth.service.ts`:
- Around line 224-235: Update logout to replace the separate
UserRepository.updateRefreshToken and UserRepository.incrementTokenVersion calls
with one UserRepository.update invocation using a Prisma.UserUpdateInput that
clears the refresh token and atomically increments the token version. Preserve
the existing error handling and userId targeting.
- Around line 88-117: Update the login function’s !user path to run
bcrypt.compare with the supplied password and a static dummy hash before
throwing the existing INVALID_CREDENTIALS AppError. Keep the existing
user-password comparison for found users and preserve the same response and
error behavior.
In `@src/api/services/user.service.ts`:
- Around line 14-20: Update the update function to handle UserRepository.update
failures consistently with getOne: detect Prisma’s record-not-found condition
(P2025), convert it to the established AppError representing a 404 NOT_FOUND
response, and preserve existing behavior for successful updates and unrelated
errors.
In `@src/prisma/migrations/20260729070404_init_database/migration.sql`:
- Around line 1-174: Consolidate the User changes from the adjacent
add_token_version_field_to_user migration into the init_database migration so
User is transformed directly to its final schema, without the intermediate
authRef/password reversal. Update the User table alteration and related
constraints/indexes to match the final model, then remove the redundant
follow-up migration while preserving all non-User schema changes.
In
`@src/prisma/migrations/20260730035148_add_token_version_field_to_user/migration.sql`:
- Around line 1-19: Squash the changes from migration
20260730035148_add_token_version_field_to_user into the preceding init migration
instead of shipping sequential schema changes. Remove the standalone migration’s
drop of User.authRef and re-addition of User.password, and ensure the
consolidated migration creates the final User schema directly while preserving
refreshToken uniqueness and tokenVersion’s default.
In `@src/prisma/seeds/space.seed.ts`:
- Around line 53-65: Update the researchSpace.upsert call so its update branch
refreshes existing records with the seed-controlled name and researchObjective
values, while preserving the current create fields and stable seed-space-${i}
identity.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: bed3c7e8-8bd0-4b09-b003-da87e5f85dd2
⛔ Files ignored due to path filters (12)
src/generated/prisma/browser.tsis excluded by!**/generated/**src/generated/prisma/client.tsis excluded by!**/generated/**src/generated/prisma/commonInputTypes.tsis excluded by!**/generated/**src/generated/prisma/enums.tsis excluded by!**/generated/**src/generated/prisma/internal/class.tsis excluded by!**/generated/**src/generated/prisma/internal/prismaNamespace.tsis excluded by!**/generated/**src/generated/prisma/internal/prismaNamespaceBrowser.tsis excluded by!**/generated/**src/generated/prisma/models.tsis excluded by!**/generated/**src/generated/prisma/models/Comment.tsis excluded by!**/generated/**src/generated/prisma/models/Post.tsis excluded by!**/generated/**src/generated/prisma/models/User.tsis excluded by!**/generated/**yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (55)
.env.example.gitignore.prettierrc.json.yarnrc.ymleslint.config.jspackage.jsonsrc/api/controllers/auth.controller.tssrc/api/controllers/comment.controller.tssrc/api/controllers/post.controller.tssrc/api/controllers/space.controller.tssrc/api/controllers/user.controller.tssrc/api/docs/openapi.tssrc/api/errors/app.error.tssrc/api/errors/error-codes.tssrc/api/index.tssrc/api/middlewares/auth.middleware.tssrc/api/middlewares/error.middleware.tssrc/api/middlewares/request-logger.middleware.tssrc/api/middlewares/validation.middleware.tssrc/api/routes/auth.router.tssrc/api/routes/comment.router.tssrc/api/routes/index.tssrc/api/routes/post.router.tssrc/api/routes/response.tssrc/api/routes/space.router.tssrc/api/routes/user.router.tssrc/api/routes/validators/auth.validator.tssrc/api/routes/validators/comment.validator.tssrc/api/routes/validators/post.validator.tssrc/api/routes/validators/space.validator.tssrc/api/routes/validators/user.validator.tssrc/api/services/auth.service.tssrc/api/services/comment.service.tssrc/api/services/post.service.tssrc/api/services/space.service.tssrc/api/services/user.service.tssrc/api/types/space.tssrc/api/utils/constants.tssrc/api/utils/exclude.tssrc/api/utils/token.util.tssrc/config/cors.tssrc/config/enviroment.tssrc/config/logger.tssrc/custom.d.tssrc/index.tssrc/prisma/migrations/20260729070404_init_database/migration.sqlsrc/prisma/migrations/20260730035148_add_token_version_field_to_user/migration.sqlsrc/prisma/prisma.client.tssrc/prisma/repositories/comment.repository.tssrc/prisma/repositories/post.repository.tssrc/prisma/repositories/space.repository.tssrc/prisma/repositories/user.repository.tssrc/prisma/schema.prismasrc/prisma/seeds/space.seed.tstsconfig.json
💤 Files with no reviewable changes (10)
- src/api/controllers/post.controller.ts
- src/api/controllers/comment.controller.ts
- src/api/routes/post.router.ts
- src/api/routes/validators/comment.validator.ts
- src/api/services/post.service.ts
- src/prisma/repositories/comment.repository.ts
- src/api/routes/comment.router.ts
- src/api/routes/validators/post.validator.ts
- src/api/services/comment.service.ts
- src/prisma/repositories/post.repository.ts
|
|
||
| /src/generated/prisma |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
rg -n '"(build|postinstall|prepare|generate)"|prisma generate' package.json
fd -i 'schema.prisma|prisma.config.ts' -x rg -n 'generator client|output' {}Repository: nustechnology/Folio-BE
Length of output: 317
🏁 Script executed:
#!/bin/bash
set -eu
printf '\n## package.json\n'
cat -n package.json | sed -n '1,160p'
printf '\n## workflow / ci files\n'
find . -maxdepth 3 \( -path '*/.github/*' -o -name 'azure-pipelines.yml' -o -name 'Jenkinsfile' -o -name 'gitlab-ci.yml' \) -type f | sort | while read -r f; do
echo "\n### $f"
cat -n "$f" | sed -n '1,220p'
done
printf '\n## references to db:generate / prisma generate / tsc-alias\n'
rg -n 'db:generate|prisma generate|tsc-alias|generated/prisma|schema.prisma' . -g '!node_modules' -g '!.git'Repository: nustechnology/Folio-BE
Length of output: 4853
🏁 Script executed:
#!/bin/bash
set -eu
printf '\n## package.json\n'
cat -n package.json | sed -n '1,160p'
printf '\n## workflow / ci files\n'
find . -maxdepth 3 \( -path '*/.github/*' -o -name 'azure-pipelines.yml' -o -name 'Jenkinsfile' -o -name 'gitlab-ci.yml' \) -type f | sort | while read -r f; do
echo "\n### $f"
cat -n "$f" | sed -n '1,220p'
done
printf '\n## references to db:generate / prisma generate / tsc-alias / generated/prisma / schema.prisma\n'
rg -n 'db:generate|prisma generate|tsc-alias|generated/prisma|schema.prisma' . -g '!node_modules' -g '!.git'Repository: nustechnology/Folio-BE
Length of output: 4888
🏁 Script executed:
#!/bin/bash
set -eu
printf '\n## tsconfig files\n'
find . -maxdepth 2 \( -name 'tsconfig*.json' -o -name 'tsconfig.json' \) -type f | sort | while read -r f; do
echo "\n### $f"
cat -n "$f" | sed -n '1,220p'
done
printf '\n## generated Prisma files tracked in git\n'
git ls-files 'src/generated/prisma/**' 'dist/generated/prisma/**' 'generated/prisma/**'
printf '\n## source imports that depend on generated Prisma client\n'
rg -n "generated/prisma/client|~/generated/prisma/client" src -g '*.ts'Repository: nustechnology/Folio-BE
Length of output: 1270
Run Prisma generation before tsc.
src/generated/prisma is a build artifact, but package.json’s build script still goes straight to tsc && tsc-alias. A clean yarn build will fail unless yarn db:generate runs first; add it to the build/prebuild path.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.gitignore around lines 22 - 23, Update the package.json build/prebuild
configuration so the Prisma generation command runs before tsc and tsc-alias.
Reuse the existing db:generate script, ensuring a clean yarn build creates
src/generated/prisma before compilation.
| approvedGitRepositories: | ||
| - "**" | ||
|
|
||
| enableScripts: true | ||
|
|
||
| nodeLinker: node-modules | ||
|
|
||
| npmMinimalAgeGate: 0 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
set -euo pipefail
printf 'Repo files of interest:\n'
git ls-files .yarnrc.yml package.json yarn.lock .yarn/releases 2>/dev/null || true
printf '\n.yarnrc.yml:\n'
cat -n .yarnrc.yml
printf '\npackage.json (if present):\n'
if [ -f package.json ]; then cat -n package.json; fiRepository: nustechnology/Folio-BE
Length of output: 2339
🏁 Script executed:
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
for p in [Path('.yarnrc.yml'), Path('package.json')]:
if p.exists():
print(f'== {p} ==')
for i, line in enumerate(p.read_text().splitlines(), 1):
print(f'{i:4d}: {line}')
print()
PYRepository: nustechnology/Folio-BE
Length of output: 2217
🌐 Web query:
Yarn approvedGitRepositories enableScripts npmMinimalAgeGate configuration docs
💡 Result:
These three settings are security-focused configuration options in Yarn (Berry) designed to mitigate supply-chain risks and restrict the execution of arbitrary code [1][2][3]. approvedGitRepositories This setting accepts an array of git repository URL glob patterns [4][5][6]. It acts as an allow-list: Yarn will block any git dependency whose normalized repository URL does not match one of these patterns [4][7]. This is intended to prevent the fetching and installation of dependencies from untrusted or unverified git sources [1][8][3]. enableScripts This boolean setting determines whether Yarn executes lifecycle scripts (such as postinstall) for third-party packages [4][5][7]. When set to false (which is the default in recent versions), Yarn will not run these scripts by default, effectively reducing the risk of malicious code execution during installation [7][2][9]. You can override this behavior on a per-package basis using dependenciesMeta [4][5][10]. npmMinimalAgeGate This setting specifies a minimum age that a package version must reach before it is considered eligible for installation [5][7]. It accepts a duration string (e.g., "1d", "1w") [4][5]. Versions newer than this duration are rejected unless they are explicitly preapproved [5][7]. This mechanism is designed to reduce exposure to supply-chain attacks by delaying the use of newly-published packages until they have been available for a certain period [5][7]. Yarn automatically migrates existing projects to maintain their current configuration even as default security settings become more restrictive [2]. New projects created in recent versions often default to stricter settings for these parameters [1][2].
Citations:
- 1: Adds
approvedGitRepositoriesyarnpkg/berry#7091 - 2: Makes
enableScripts: falsethe default yarnpkg/berry#7089 - 3: yarnpkg/berry@4bd2b21
- 4: https://yarnpkg.com/configuration/yarnrc
- 5: https://v6.yarnpkg.com/configuration/yarnrc.html
- 6: https://yarnpkg.com/api/yarnpkg-core/interface/ConfigurationValueMap
- 7: https://catalog.lintel.tools/schemas/schemastore/yarn-config-yarnrc-yml/
- 8: https://yarnpkg.com/protocol/git
- 9: https://v6.yarnpkg.com/advanced/lifecycle-scripts.html
- 10: https://yarnpkg.com/configuration/manifest
🌐 Web query:
Yarn enableScripts default configuration docs npmMinimalAgeGate approvedGitRepositories
💡 Result:
As of July 30, 2026, the relevant Yarn (Berry) configurations are as follows: enableScripts The enableScripts setting determines whether postinstall scripts are executed during package installation [1][2]. The default value is false [1][2][3]. When disabled, Yarn does not execute postinstall scripts from third-party packages, although workspaces retain the ability to evaluate their own scripts as they are considered trusted [1][2]. You can re-enable scripts globally via.yarnrc.yml or on a per-package basis using dependenciesMeta [1][2]. npmMinimalAgeGate The npmMinimalAgeGate setting specifies the minimum age a package version must have on the npm registry to be considered for installation [4][5]. This acts as a security mechanism to reduce the risk of installing recently published, potentially malicious packages [6][5]. The default value is 0m (zero minutes), meaning the gate is effectively disabled by default unless explicitly configured [4][5]. The value accepts a duration string (e.g., "3d", "1w") or a number [5]. approvedGitRepositories The approvedGitRepositories setting is a security feature that restricts which git repositories Yarn is permitted to clone when resolving git dependencies [7][8]. The default configuration is an empty list ([]), meaning no repositories are allowed by default [7][8]. Projects must explicitly add patterns to this list to allow fetching from specific git repositories [7][8]. Existing projects are generally migrated to include a wildcard in this setting to maintain backward compatibility [3][7].
Citations:
- 1: https://v6.yarnpkg.com/configuration/yarnrc.html
- 2: https://yarnpkg.com/configuration/yarnrc
- 3: Makes
enableScripts: falsethe default yarnpkg/berry#7089 - 4: https://github.com/yarnpkg/berry/blob/b223e69f6b5eb899c2e1a140f883a9f15252df2f/packages/plugin-npm/sources/index.ts
- 5: yarnpkg/berry@33d2911
- 6: feat: implement
npmMinimalAgeGateandnpmPreapprovedPackagesconfig options yarnpkg/berry#6901 - 7: Adds
approvedGitRepositoriesyarnpkg/berry#7091 - 8: https://v6.yarnpkg.com/protocol/git.html
Tighten Yarn supply-chain controls.
approvedGitRepositories: "**" allows any git source, enableScripts: true runs third-party lifecycle scripts globally, and npmMinimalAgeGate: 0 disables the age gate for newly published packages. Restrict Git patterns to trusted repos, keep scripts disabled by default, and use a nonzero age threshold.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.yarnrc.yml around lines 1 - 8, Harden the Yarn settings by replacing the
unrestricted approvedGitRepositories pattern with trusted repository patterns,
setting enableScripts to false, and changing npmMinimalAgeGate to a nonzero
duration. Preserve nodeLinker: node-modules.
Source: MCP tools
| "scripts": { | ||
| "build": "tsc --build --clean && tsc", | ||
| "lint": "eslint src/**/*.ts", | ||
| "build": "tsc --build --clean && tsc && tsc-alias", |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
node -p "JSON.stringify({type: require('./package.json').type, build: require('./package.json').scripts?.build, start: require('./package.json').scripts?.start}, null, 2)"
rg -n 'from ["'\''](~|\.\.?/)' srcRepository: nustechnology/Folio-BE
Length of output: 7004
🏁 Script executed:
#!/bin/bash
set -eu
echo '--- package.json ---'
cat -n package.json
echo
echo '--- tsconfig.json ---'
cat -n tsconfig.json
echo
echo '--- tsconfig files ---'
fd -a 'tsconfig*.json' .
echo
echo '--- references to tsc-alias / resolveFullPaths / moduleResolution / bundler / nodenext ---'
rg -n 'tsc-alias|resolveFullPaths|resolveFullExtension|moduleResolution|nodenext|bundler|ts-node|tsx|node dist|dist/' .Repository: nustechnology/Folio-BE
Length of output: 5382
🌐 Web query:
tsc-alias resolveFullPaths default ESM .js extension Node loader
💡 Result:
The tsc-alias package provides the resolveFullPaths option to support ECMAScript Module (ESM) requirements in Node.js, specifically the necessity for explicit file extensions in import specifiers [1][2]. When resolveFullPaths is enabled, tsc-alias attempts to identify incomplete import paths (those not ending in a file extension) and replaces them with fully resolved paths (e.g., adding .js) [1][3]. By default, this appends the .js extension, though it can be configured via the resolveFullExtension option to use others like .mjs or .cjs [1][4]. To implement this, you typically configure tsc-alias in your tsconfig.json and update your build script to run tsc-alias after the TypeScript compiler (tsc): 1. Configure tsconfig.json: { "tsc-alias": { "resolveFullPaths": true } } 2. Update build scripts: "scripts": { "build": "tsc && tsc-alias" } Important considerations: - ESM Compatibility: Node.js ESM requires fully qualified paths. tsc-alias performs this transformation as a post-compilation step, making the output code ESM-ready [2][5]. - Not for Runtime: tsc-alias is designed as a build-time tool. It is not intended to be used as a Node.js loader or a runtime resolver (e.g., with ts-node) [6]. - Watch Mode: If you are using watch mode (-w), be aware that running tsc and tsc-alias concurrently can lead to race conditions where tsc-alias attempts to process files that have not yet been generated. A common pattern to resolve this is using a tool like concurrently or ensuring tsc completes before tsc-alias begins processing in a continuous loop [7].
Citations:
- 1: https://github.com/justkey007/tsc-alias
- 2: Add option to fully resolve paths, making compiled code ECMAScript Module-ready justkey007/tsc-alias#31
- 3: https://dev.to/vladimirvovk/use-absolute-path-imports-with-typescript-and-nodejs-53d6
- 4: https://www.npmjs.com/package/tsc-alias
- 5: https://stackoverflow.com/questions/62619058/appending-js-extension-on-relative-import-statements-during-typescript-compilat
- 6: use with ts-node justkey007/tsc-alias#81
- 7: Using
resolveFullPathswith watch mode cause the transpiled file not to have.jsextenstion justkey007/tsc-alias#117
Add .js extensions to tsc-alias rewrites. This package is ESM ("type": "module"), and production runs node dist/index.js, so alias rewrites need resolveFullPaths: true with resolveFullExtension: ".js"; otherwise emitted imports can stay extensionless and fail under Node’s resolver.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@package.json` at line 6, Update the build script’s tsc-alias invocation to
enable full-path resolution and configure the resolved extension as “.js”,
ensuring emitted ESM imports are compatible with Node’s resolver.
Source: MCP tools
| "build": "tsc --build --clean && tsc", | ||
| "lint": "eslint src/**/*.ts", | ||
| "build": "tsc --build --clean && tsc && tsc-alias", | ||
| "lint": "eslint src/**/*.ts --fix --no-warn-ignored", |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the script in context
git ls-files package.json
cat -n package.json
# Check whether the repo has any npm/yarn/pnpm script config that affects shell parsing
git ls-files | rg '^(package.json|pnpm-workspace\.yaml|yarn\.rc|\.npmrc|package-lock\.json|pnpm-lock\.yaml|yarn\.lock)$' || trueRepository: nustechnology/Folio-BE
Length of output: 2115
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Top-level and nested TypeScript files under src:"
git ls-files 'src/**/*.ts' | sed -n '1,200p'
echo
echo "Directory depths:"
python3 - <<'PY'
import subprocess, os
paths = subprocess.check_output(["git", "ls-files", "src/**/*.ts"], text=True).splitlines()
for p in paths:
depth = p.count("/")
print(f"{depth}\t{p}")
PY
echo
echo "Bash expansion without globstar (using repo files only):"
bash -lc 'shopt -u globstar; printf "%s\n" src/**/*.ts 2>/dev/null | sed -n "1,50p"'
echo
echo "Bash expansion with globstar:"
bash -lc 'shopt -s globstar; printf "%s\n" src/**/*.ts 2>/dev/null | sed -n "1,50p"'Repository: nustechnology/Folio-BE
Length of output: 4055
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Top-level and nested TypeScript files under src:"
git ls-files 'src/**/*.ts' | sed -n '1,200p'
echo
echo "Directory depths:"
python3 - <<'PY'
import subprocess
paths = subprocess.check_output(["git", "ls-files", "src/**/*.ts"], text=True).splitlines()
for p in paths:
print(f"{p.count('/')}\t{p}")
PY
echo
echo "Bash expansion without globstar:"
bash -lc 'shopt -u globstar; printf "%s\n" src/**/*.ts 2>/dev/null | sed -n "1,50p"'
echo
echo "Bash expansion with globstar:"
bash -lc 'shopt -s globstar; printf "%s\n" src/**/*.ts 2>/dev/null | sed -n "1,50p"'Repository: nustechnology/Folio-BE
Length of output: 4031
Quote the ESLint glob in package.json. Unquoted src/**/*.ts is expanded by the shell before ESLint runs, so nested files like src/api/routes/validators/*.ts can be skipped in environments where globstar isn’t enabled.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@package.json` at line 7, Update the package.json lint script to quote the
src/**/*.ts glob so the shell passes it unchanged to ESLint, ensuring nested
TypeScript files are discovered consistently.
Source: MCP tools
| const getOne = async (req: Request, res: Response) => { | ||
| const { id } = req.params; | ||
| const userId = id === 'me' ? req.userId! : Number(id); | ||
| const userId = id === 'me' ? req.userId! : id; | ||
| const user = await UserService.getOne(userId); |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Any authenticated user can read any other user by ID.
With Number(id) gone, the raw param is forwarded straight to UserService.getOne, so GET /api/v1/users/<other-uuid> returns another account's record (including email per the OpenAPI User schema). If this endpoint is meant to be self-only, restrict it; otherwise return a reduced public projection for non-self lookups.
🔒 Self-only variant
const getOne = async (req: Request, res: Response) => {
const { id } = req.params;
- const userId = id === 'me' ? req.userId! : id;
+ if (id !== 'me' && id !== req.userId) {
+ throw new AppError('Forbidden', StatusCodes.FORBIDDEN);
+ }
+ const userId = req.userId!;
const user = await UserService.getOne(userId);Also confirm the auth middleware is mounted on this route, since req.userId! would otherwise be undefined at runtime:
#!/bin/bash
fd -t f 'user.router.ts' -x cat -n
fd -t f 'user.service.ts' -x cat -n🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/api/controllers/user.controller.ts` around lines 6 - 9, Restrict the
getOne controller to self-only access: require the requested id to be “me” (or
otherwise match req.userId) and reject other user IDs before calling
UserService.getOne. Verify the user route is mounted behind authentication
middleware so req.userId is populated, and remove the unsafe non-null assumption
if the project’s auth pattern requires explicit validation.
| JWT_TOKEN_SECRET: process.env.JWT_TOKEN_SECRET || '', | ||
| REFRESH_TOKEN_SECRET: process.env.REFRESH_TOKEN_SECRET || '', | ||
| ACCESS_TOKEN_EXPIRATION: process.env.ACCESS_TOKEN_EXPIRATION || '15m', | ||
| REFRESH_TOKEN_EXPIRATION: process.env.REFRESH_TOKEN_EXPIRATION || '30d', | ||
| CORS_ORIGIN: process.env.CORS_ORIGIN || 'http://localhost:3000' |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Empty-string fallback for token secrets silently weakens auth.
If JWT_TOKEN_SECRET/REFRESH_TOKEN_SECRET are unset, signing/verification proceeds with an empty key instead of failing at boot — tokens become trivially forgeable in any misconfigured deployment. Validate required secrets at startup instead of defaulting them.
🛡️ Suggested fail-fast validation
+const required = (name: string): string => {
+ const value = process.env[name];
+ if (!value) {
+ throw new Error(`Missing required environment variable: ${name}`);
+ }
+ return value;
+};
+
...
- JWT_TOKEN_SECRET: process.env.JWT_TOKEN_SECRET || '',
- REFRESH_TOKEN_SECRET: process.env.REFRESH_TOKEN_SECRET || '',
+ JWT_TOKEN_SECRET: required('JWT_TOKEN_SECRET'),
+ REFRESH_TOKEN_SECRET: required('REFRESH_TOKEN_SECRET'),
ACCESS_TOKEN_EXPIRATION: process.env.ACCESS_TOKEN_EXPIRATION || '15m',
REFRESH_TOKEN_EXPIRATION: process.env.REFRESH_TOKEN_EXPIRATION || '30d',
CORS_ORIGIN: process.env.CORS_ORIGIN || 'http://localhost:3000'Also consider asserting the two secrets differ, so an access token can never be replayed as a refresh token.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| JWT_TOKEN_SECRET: process.env.JWT_TOKEN_SECRET || '', | |
| REFRESH_TOKEN_SECRET: process.env.REFRESH_TOKEN_SECRET || '', | |
| ACCESS_TOKEN_EXPIRATION: process.env.ACCESS_TOKEN_EXPIRATION || '15m', | |
| REFRESH_TOKEN_EXPIRATION: process.env.REFRESH_TOKEN_EXPIRATION || '30d', | |
| CORS_ORIGIN: process.env.CORS_ORIGIN || 'http://localhost:3000' | |
| const required = (name: string): string => { | |
| const value = process.env[name]; | |
| if (!value) { | |
| throw new Error(`Missing required environment variable: ${name}`); | |
| } | |
| return value; | |
| }; | |
| JWT_TOKEN_SECRET: required('JWT_TOKEN_SECRET'), | |
| REFRESH_TOKEN_SECRET: required('REFRESH_TOKEN_SECRET'), | |
| ACCESS_TOKEN_EXPIRATION: process.env.ACCESS_TOKEN_EXPIRATION || '15m', | |
| REFRESH_TOKEN_EXPIRATION: process.env.REFRESH_TOKEN_EXPIRATION || '30d', | |
| CORS_ORIGIN: process.env.CORS_ORIGIN || 'http://localhost:3000' |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/config/enviroment.ts` around lines 24 - 28, Update the token-secret
configuration around JWT_TOKEN_SECRET and REFRESH_TOKEN_SECRET to reject missing
or empty values during startup instead of defaulting to ''. Preserve the
existing expiration and CORS defaults, and add startup validation that the two
required secrets are distinct before authentication proceeds.
| }); | ||
| } | ||
|
|
||
| startApiServer(); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Unhandled rejection from startApiServer() leaves a zombie process.
If api.server() (or anything it awaits) rejects, the failure falls through to the unhandledRejection handler, which only logs — the process stays alive with no listener bound and no non-zero exit for the orchestrator to act on.
🛡️ Suggested fix
-startApiServer();
+startApiServer().catch((error: unknown) => {
+ logger.error('Failed to start API server', {
+ error: error instanceof Error ? error.message : String(error),
+ stack: error instanceof Error ? error.stack : undefined
+ });
+ process.exit(1);
+});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| startApiServer(); | |
| startApiServer().catch((error: unknown) => { | |
| logger.error('Failed to start API server', { | |
| error: error instanceof Error ? error.message : String(error), | |
| stack: error instanceof Error ? error.stack : undefined | |
| }); | |
| process.exit(1); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/index.ts` at line 16, Update the startup flow around startApiServer() to
explicitly handle rejected promises from api.server() or awaited initialization,
logging the failure and terminating with a non-zero exit status so the process
cannot remain alive without a listener.
| model ResearchSpace { | ||
| id String @id @default(uuid()) | ||
| ownerId String | ||
| owner User @relation(fields: [ownerId], references: [id]) | ||
| name String | ||
| researchObjective String | ||
| isArchived Boolean @default(false) | ||
| createdAt DateTime @default(now()) | ||
| updatedAt DateTime @updatedAt | ||
| lastOpenedAt DateTime @default(now()) | ||
|
|
||
| sources Source[] | ||
| conversations Conversation[] | ||
| notes Note[] | ||
| notebook Notebook? | ||
| } | ||
|
|
||
| enum OriginType { | ||
| UserCreated | ||
| SavedAssistantAnswer | ||
| } | ||
|
|
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Add an index (and ideally a unique constraint) for ResearchSpace.ownerId/name.
ownerId has no @@index, yet space.service.ts queries by owner on every list/create call (findManyByOwner, findByNameAndOwner) — this will full-scan as data grows. Additionally, since duplicate-name prevention is only enforced at the application layer (check-then-create in space.service.ts), a composite @@unique([ownerId, name]) would both fix the missing index and close the race condition where two concurrent create requests for the same name could both pass the existence check.
♻️ Suggested schema change
model ResearchSpace {
id String `@id` `@default`(uuid())
ownerId String
owner User `@relation`(fields: [ownerId], references: [id])
name String
researchObjective String
isArchived Boolean `@default`(false)
createdAt DateTime `@default`(now())
updatedAt DateTime `@updatedAt`
lastOpenedAt DateTime `@default`(now())
sources Source[]
conversations Conversation[]
notes Note[]
notebook Notebook?
+
+ @@unique([ownerId, name])
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| model ResearchSpace { | |
| id String @id @default(uuid()) | |
| ownerId String | |
| owner User @relation(fields: [ownerId], references: [id]) | |
| name String | |
| researchObjective String | |
| isArchived Boolean @default(false) | |
| createdAt DateTime @default(now()) | |
| updatedAt DateTime @updatedAt | |
| lastOpenedAt DateTime @default(now()) | |
| sources Source[] | |
| conversations Conversation[] | |
| notes Note[] | |
| notebook Notebook? | |
| } | |
| enum OriginType { | |
| UserCreated | |
| SavedAssistantAnswer | |
| } | |
| model ResearchSpace { | |
| id String `@id` `@default`(uuid()) | |
| ownerId String | |
| owner User `@relation`(fields: [ownerId], references: [id]) | |
| name String | |
| researchObjective String | |
| isArchived Boolean `@default`(false) | |
| createdAt DateTime `@default`(now()) | |
| updatedAt DateTime `@updatedAt` | |
| lastOpenedAt DateTime `@default`(now()) | |
| sources Source[] | |
| conversations Conversation[] | |
| notes Note[] | |
| notebook Notebook? | |
| @@unique([ownerId, name]) | |
| } | |
| enum OriginType { | |
| UserCreated | |
| SavedAssistantAnswer | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/prisma/schema.prisma` around lines 24 - 45, Update the ResearchSpace
model to add a composite unique constraint on ownerId and name, which also
provides the needed lookup index for owner-scoped queries and enforces
duplicate-name prevention at the database level.
| console.log(`Created user: ${user.email} (${user.id})`); | ||
| } else { | ||
| console.log(`Using existing user: ${user.email} (${user.id})`); | ||
| } |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
Avoid logging user email/PII to console.
Static analysis flags these as sensitive-data logging (CWE-532). Prefer logging the user ID alone, or a masked identifier.
🛡️ Suggested fix
- console.log(`Created user: ${user.email} (${user.id})`);
+ console.log(`Created user: ${user.id}`);
} else {
- console.log(`Using existing user: ${user.email} (${user.id})`);
+ console.log(`Using existing user: ${user.id}`);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| console.log(`Created user: ${user.email} (${user.id})`); | |
| } else { | |
| console.log(`Using existing user: ${user.email} (${user.id})`); | |
| } | |
| console.log(`Created user: ${user.id}`); | |
| } else { | |
| console.log(`Using existing user: ${user.id}`); | |
| } |
🧰 Tools
🪛 ast-grep (0.45.0)
[warning] 14-14: Avoid logging sensitive data
Context: console.log(Using existing user: ${user.email} (${user.id}))
Note: [CWE-532] Insertion of Sensitive Information into Log File.
(log-sensitive-data-typescript)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/prisma/seeds/space.seed.ts` around lines 13 - 16, Update the user
creation and reuse log statements around the seed flow to remove user.email from
console output, retaining only the non-sensitive user.id needed for
identification.
Source: Linters/SAST tools
| "module": "Preserve", | ||
| "esModuleInterop": true, | ||
| "skipLibCheck": true, | ||
| "target": "ES2023", | ||
| "emitDecoratorMetadata": true, | ||
| "experimentalDecorators": true, | ||
| "noImplicitAny": true, | ||
| "moduleResolution": "NodeNext", | ||
| "moduleResolution": "Bundler", | ||
| "resolveJsonModule": true, | ||
| "baseUrl": ".", | ||
| "paths": { | ||
| "~/*": ["src/*"] | ||
| }, |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
node -p "JSON.stringify({type: require('./package.json').type, build: require('./package.json').scripts?.build, start: require('./package.json').scripts?.start}, null, 2)"
rg -n 'from ["'\''](~|\.\.?/)' srcRepository: nustechnology/Folio-BE
Length of output: 7004
🏁 Script executed:
#!/bin/bash
set -eu
printf '\npackage.json:\n'
cat -n package.json | sed -n '1,220p'
printf '\ntsconfig.json:\n'
cat -n tsconfig.json | sed -n '1,220p'
printf '\nRelevant tsconfig/alias files:\n'
rg -n '"module"|"moduleResolution"|"paths"|"outDir"|"rootDir"|"allowImportingTsExtensions"|"rewriteRelativeImportExtensions"|"verbatimModuleSyntax"|"type"' tsconfig*.json package.jsonRepository: nustechnology/Folio-BE
Length of output: 3069
🌐 Web query:
tsc-alias default behavior add .js extensions rewrite relative imports path aliases
💡 Result:
By default, tsc-alias does not add.js extensions to import paths; its primary behavior is to replace TypeScript path aliases with valid relative paths in your compiled JavaScript files [1][2]. To add.js (or other) extensions to your imports—a requirement for some ECMAScript Module environments—you must explicitly enable the necessary configuration options [1][3]. Configuration Options: 1. resolveFullPaths: Set this to true to enable the replacement of incomplete import paths with fully resolved paths [1][4]. 2. resolveFullExtension: Use this to specify the desired extension (e.g., '.js', '.mjs', or '.cjs') to be appended to those incomplete paths [1][3]. You can configure these in your tsconfig.json under a dedicated tsc-alias section: { "compilerOptions": { // Standard TypeScript options }, "tsc-alias": { "resolveFullPaths": true, "resolveFullExtension": ".js" } } Alternatively, you can pass these as flags via the command line (e.g., --resolve-full-paths and --resolve-full-extension) [3][5]. When enabled, tsc-alias will attempt to append the specified extension to imports that do not already end in that extension [1][3].
Citations:
- 1: https://github.com/justkey007/tsc-alias
- 2: https://ajmani.dev/how-to-use-tsc-alias-in-typescript/
- 3: https://context7.com/justkey007/tsc-alias/llms.txt
- 4: https://npmx.dev/package/tsc-alias
- 5: https://github.com/justkey007/tsc-alias/releases
🏁 Script executed:
#!/bin/bash
set -eu
printf '\nSearching for tsc-alias configuration:\n'
rg -n '"tsc-alias"|resolveFullPaths|resolveFullExtension|addExtensions|replaceExtensions' . --glob '!node_modules' --glob '!dist'
printf '\nExtensionless relative imports in src:\n'
rg -n 'from\s+[\"\'](\.{1,2}/[^\"\']+)[\"\']' src
printf '\nFiles with only alias imports or bare imports in src (sample):\n'
rg -n 'from\s+[\"\'](\.{1,2}/[^\"\']+)[\"\']|from\s+[\"\']~/' src/api src/config src/prisma src/index.tsRepository: nustechnology/Folio-BE
Length of output: 338
module: Preserve is only safe here if the runtime uses a loader or path-rewrite step
The package is type: "module", the build emits ESM, and tsc-alias only rewrites path aliases by default — it does not add .js extensions. With the current extensionless relative imports, direct Node execution of dist will fail unless a full-path rewrite or loader is in place.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tsconfig.json` around lines 3 - 15, Update the TypeScript
module-resolution/build configuration around module: Preserve so emitted dist
files are directly executable by the package’s Node ESM runtime. Add or
configure the required full-path rewrite step to append .js extensions to
extensionless relative imports, or use an established loader, while preserving
the existing ~/* alias resolution.
Source: MCP tools
852731a to
88504dd
Compare
- Updated validation middleware to improve readability. - Refactored auth router for cleaner import statements and consistent formatting. - Improved response utility to use generics for better type safety. - Cleaned up space router imports and formatting. - Standardized user router imports and formatting. - Enhanced auth validator schemas for better readability and maintainability. - Refactored space validator schemas for improved clarity. - Cleaned up user validator schemas for consistency. - Refactored auth service for better error handling and code clarity. - Improved space service for better readability and maintainability. - Cleaned up user service for consistency and clarity. - Updated constants for better formatting. - Refactored token utility for improved readability. - Cleaned up CORS configuration for consistency. - Updated environment configuration for better formatting. - Refactored logger configuration for improved readability. - Cleaned up index file for better error handling. - Updated Prisma client configuration for consistency. - Refactored space repository for improved readability. - Cleaned up user repository for consistency and clarity. - Updated space seed data for better formatting. - Updated yarn.lock for new dependencies and versions. - Added Prettier configuration for consistent code formatting. - Created space type definitions for better type safety.
88504dd to
dbf4a6d
Compare
Summary by CodeRabbit
New Features
Bug Fixes
Changes