From 71275e335ec3601be4a86790ea751a6c197ff9e3 Mon Sep 17 00:00:00 2001 From: Tal Jacob Date: Mon, 21 Jul 2025 09:00:43 +0300 Subject: [PATCH 1/4] Explicitly Set Types To Models `toJSON` Transform Function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following error, when running `npm run dev` in the backend: ``` /home/tal/Code/NextStep/nextstep-backend/node_modules/ts-node/src/index.ts:859 return new TSError(diagnosticText, diagnosticCodes, diagnostics); ^ TSError: ⨯ Unable to compile TypeScript: src/models/user_model.ts:34:13 - error TS2322: Type 'unknown' is not assignable to type 'string'. 34 id: ret._id, ~~ src/types/user_types.ts:13:5 13 id: string; ~~ The expected type comes from property 'id' which is declared here on type 'UserData' src/models/user_model.ts:35:13 - error TS2322: Type 'unknown' is not assignable to type 'string'. 35 username: ret.username, ~~~~~~~~ src/types/user_types.ts:14:5 14 username: string; ~~~~~~~~ The expected type comes from property 'username' which is declared here on type 'UserData' src/models/user_model.ts:36:13 - error TS2322: Type 'unknown' is not assignable to type 'string'. 36 email: ret.email, ~~~~~ src/types/user_types.ts:15:5 15 email: string; ~~~~~ The expected type comes from property 'email' which is declared here on type 'UserData' src/models/user_model.ts:37:13 - error TS2322: Type 'unknown' is not assignable to type 'string'. 37 password: ret.password, ~~~~~~~~ src/types/user_types.ts:16:5 16 password: string; ~~~~~~~~ The expected type comes from property 'password' which is declared here on type 'UserData' src/models/user_model.ts:38:13 - error TS2322: Type 'unknown' is not assignable to type 'string | undefined'. 38 imageFilename: ret?.imageFilename, ~~~~~~~~~~~~~ src/types/user_types.ts:17:5 17 imageFilename?: string; ~~~~~~~~~~~~~ The expected type comes from property 'imageFilename' which is declared here on type 'UserData' src/models/user_model.ts:39:13 - error TS2322: Type 'unknown' is not assignable to type 'string | undefined'. 39 createdAt: ret.createdAt, ~~~~~~~~~ src/types/user_types.ts:18:5 18 createdAt?: string, ~~~~~~~~~ The expected type comes from property 'createdAt' which is declared here on type 'UserData' src/models/user_model.ts:40:13 - error TS2322: Type 'unknown' is not assignable to type 'string | undefined'. 40 updatedAt: ret.updatedAt ~~~~~~~~~ src/types/user_types.ts:19:5 19 updatedAt?: string, ~~~~~~~~~ The expected type comes from property 'updatedAt' which is declared here on type 'UserData' at createTSError (/home/tal/Code/NextStep/nextstep-backend/node_modules/ts-node/src/index.ts:859:12) at reportTSError (/home/tal/Code/NextStep/nextstep-backend/node_modules/ts-node/src/index.ts:863:19) at getOutput (/home/tal/Code/NextStep/nextstep-backend/node_modules/ts-node/src/index.ts:1077:36) at Object.compile (/home/tal/Code/NextStep/nextstep-backend/node_modules/ts-node/src/index.ts:1433:41) at Module.m._compile (/home/tal/Code/NextStep/nextstep-backend/node_modules/ts-node/src/index.ts:1617:30) at node:internal/modules/cjs/loader:1895:10 at Object.require.extensions. [as .ts] (/home/tal/Code/NextStep/nextstep-backend/node_modules/ts-node/src/index.ts:1621:12) at Module.load (node:internal/modules/cjs/loader:1465:32) at Function._load (node:internal/modules/cjs/loader:1282:12) at TracingChannel.traceSync (node:diagnostics_channel:322:14) { diagnosticCodes: [ 2322, 2322, 2322, 2322, 2322, 2322, 2322 ] } [nodemon] app crashed - waiting for file changes before starting... ``` **Problem** In `user_model.ts`, the `transform` function is typed to return `UserData`, which expects all fields to be of type `string` (or `string | undefined` for some). However, the `ret` object passed to the transform function is not strongly typed—it is inferred as `any` or `unknown` by TypeScript, especially when using strict settings. This fixes all the models` `transform` function. Signed-off-by: Tal Jacob --- nextstep-backend/src/models/comments_model.ts | 12 ++++++------ nextstep-backend/src/models/company_model.ts | 8 ++++---- nextstep-backend/src/models/posts_model.ts | 7 +++---- nextstep-backend/src/models/user_model.ts | 14 +++++++------- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/nextstep-backend/src/models/comments_model.ts b/nextstep-backend/src/models/comments_model.ts index c5b2d6f..1b0749e 100644 --- a/nextstep-backend/src/models/comments_model.ts +++ b/nextstep-backend/src/models/comments_model.ts @@ -30,12 +30,12 @@ const commentSchema: Schema = new mongoose.Schema({ commentSchema.set('toJSON', { transform: (doc: Document, ret: Record) => { return { - id: ret._id, - postId: ret.postId, - content: ret.content, - owner: ret.owner, - createdAt: ret.createdAt, - updatedAt: ret.updatedAt, + id: ret._id.toString(), + postId: ret.postId.toString(), + content: ret.content as string, + owner: ret.owner.toString(), + createdAt: ret.createdAt ? ret.createdAt.toISOString() : undefined, + updatedAt: ret.updatedAt ? ret.updatedAt.toISOString() : undefined, }; } }); diff --git a/nextstep-backend/src/models/company_model.ts b/nextstep-backend/src/models/company_model.ts index 3abcd2e..b709b4c 100644 --- a/nextstep-backend/src/models/company_model.ts +++ b/nextstep-backend/src/models/company_model.ts @@ -46,10 +46,10 @@ const companySchema: Schema = new mongoose.Schema({ companySchema.set('toJSON', { transform: (doc: Document, ret: Record) => { return { - id: ret._id, - company: ret.company, - company_he: ret.company_he, - tags: ret.tags, + id: ret._id.toString(), + company: ret.company as string, + company_he: ret.company_he as string, + tags: ret.tags as string[], quizzes: ret.quizzes, } } diff --git a/nextstep-backend/src/models/posts_model.ts b/nextstep-backend/src/models/posts_model.ts index ef959be..c8a797a 100644 --- a/nextstep-backend/src/models/posts_model.ts +++ b/nextstep-backend/src/models/posts_model.ts @@ -25,13 +25,12 @@ const postSchema: Schema = new mongoose.Schema({ postSchema.set('toJSON', { transform: (doc: Document, ret: Record): PostData => { return { - id: ret._id, + id: ret._id.toString(), title: ret.title, content: ret.content, owner: ret.owner._id.toString(), - createdAt: ret.createdAt, - updatedAt: ret.updatedAt - + createdAt: ret.createdAt ? ret.createdAt.toISOString() : undefined, + updatedAt: ret.updatedAt ? ret.updatedAt.toISOString() : undefined }; } }); diff --git a/nextstep-backend/src/models/user_model.ts b/nextstep-backend/src/models/user_model.ts index 62c232e..fab91d5 100644 --- a/nextstep-backend/src/models/user_model.ts +++ b/nextstep-backend/src/models/user_model.ts @@ -31,13 +31,13 @@ const userSchema: Schema = new Schema({ userSchema.set('toJSON', { transform: (doc, ret): UserData => { return { - id: ret._id, - username: ret.username, - email: ret.email, - password: ret.password, - imageFilename: ret?.imageFilename, - createdAt: ret.createdAt, - updatedAt: ret.updatedAt + id: ret._id.toString(), + username: ret.username as string, + email: ret.email as string, + password: ret.password as string, + imageFilename: ret?.imageFilename as string | undefined, + createdAt: ret.createdAt ? ret.createdAt.toISOString() : undefined, + updatedAt: ret.updatedAt ? ret.updatedAt.toISOString() : undefined }; } }); From 83ce4c805a362a7ce5c8ce1b119b70bda3f78a5c Mon Sep 17 00:00:00 2001 From: Tal Jacob Date: Mon, 21 Jul 2025 09:09:15 +0300 Subject: [PATCH 2/4] Set Types For `toJSON` Transform Function Of `user_model.ts` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following error, when running the backend: ``` /home/tal/Code/NextStep/nextstep-backend/node_modules/ts-node/src/index.ts:859 return new TSError(diagnosticText, diagnosticCodes, diagnostics); ^ TSError: ⨯ Unable to compile TypeScript: src/models/user_model.ts:34:17 - error TS18046: 'ret._id' is of type 'unknown'. 34 id: ret._id.toString(), ~~~~~~~ src/models/user_model.ts:39:54 - error TS2339: Property 'toISOString' does not exist on type '{}'. 39 createdAt: ret.createdAt ? ret.createdAt.toISOString() : undefined, ~~~~~~~~~~~ src/models/user_model.ts:40:54 - error TS2339: Property 'toISOString' does not exist on type '{}'. 40 updatedAt: ret.updatedAt ? ret.updatedAt.toISOString() : undefined ~~~~~~~~~~~ at createTSError (/home/tal/Code/NextStep/nextstep-backend/node_modules/ts-node/src/index.ts:859:12) at reportTSError (/home/tal/Code/NextStep/nextstep-backend/node_modules/ts-node/src/index.ts:863:19) at getOutput (/home/tal/Code/NextStep/nextstep-backend/node_modules/ts-node/src/index.ts:1077:36) at Object.compile (/home/tal/Code/NextStep/nextstep-backend/node_modules/ts-node/src/index.ts:1433:41) at Module.m._compile (/home/tal/Code/NextStep/nextstep-backend/node_modules/ts-node/src/index.ts:1617:30) at node:internal/modules/cjs/loader:1895:10 at Object.require.extensions. [as .ts] (/home/tal/Code/NextStep/nextstep-backend/node_modules/ts-node/src/index.ts:1621:12) at Module.load (node:internal/modules/cjs/loader:1465:32) at Function._load (node:internal/modules/cjs/loader:1282:12) at TracingChannel.traceSync (node:diagnostics_channel:322:14) { diagnosticCodes: [ 18046, 2339, 2339 ] } [nodemon] app crashed - waiting for file changes before starting... ``` This tells TypeScript that `ret` is an object with string keys and any values, so you can safely access properties and call methods like `.toString()` and `.toISOString()`. The root cause of the error is that in the user_model.ts, the ret parameter in the transform function is not typed, so TypeScript infers it as unknown. This is why you get errors like 'ret._id' is of type 'unknown' and 'toISOString' does not exist on type '{}'. Other models (like posts, comments, company) fix this by typing ret as Record. The fix has been applied the ret parameter in the user_model.ts transform function is now typed as Record. This will resolve the TypeScript errors about unknown and {} types for ret._id and date fields. Signed-off-by: Tal Jacob --- nextstep-backend/src/models/user_model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nextstep-backend/src/models/user_model.ts b/nextstep-backend/src/models/user_model.ts index fab91d5..46dd15a 100644 --- a/nextstep-backend/src/models/user_model.ts +++ b/nextstep-backend/src/models/user_model.ts @@ -29,7 +29,7 @@ const userSchema: Schema = new Schema({ }, { timestamps: true, strict: true, versionKey: false }); userSchema.set('toJSON', { - transform: (doc, ret): UserData => { + transform: (doc: mongoose.Document, ret: Record): UserData => { return { id: ret._id.toString(), username: ret.username as string, From 84e9a3c0f1e51269ff762206b1573713b379734b Mon Sep 17 00:00:00 2001 From: Tal Jacob Date: Mon, 21 Jul 2025 09:41:42 +0300 Subject: [PATCH 3/4] Allow Frontend To Be Hosted On Other Domain Names The Vite configuration has been updated to use the `VITE_DOMAIN_NAME` environment variable for the host in both the server and preview sections. Now, if the `.env` file sets `VITE_DOMAIN_NAME=0.0.0.0`, the frontend will be exposed on all network interfaces. Signed-off-by: Tal Jacob --- nextstep-frontend/.env.template | 1 + nextstep-frontend/vite.config.ts | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/nextstep-frontend/.env.template b/nextstep-frontend/.env.template index 373be25..f004bde 100644 --- a/nextstep-frontend/.env.template +++ b/nextstep-frontend/.env.template @@ -2,6 +2,7 @@ VITE_PORT= VITE_BACKEND_URL= +VITE_DOMAIN_NAME= VITE_REACT_APP_FIREBASE_API_KEY= VITE_REACT_APP_FIREBASE_AUTH_DOMAIN= VITE_REACT_APP_FIREBASE_PROJECT_ID= diff --git a/nextstep-frontend/vite.config.ts b/nextstep-frontend/vite.config.ts index f68a9da..febbf60 100644 --- a/nextstep-frontend/vite.config.ts +++ b/nextstep-frontend/vite.config.ts @@ -9,7 +9,11 @@ dotenv.config(); export default defineConfig({ plugins: [react()], server: { - port: parseInt(process.env.VITE_PORT || '5000') + port: parseInt(process.env.VITE_PORT || '5000'), + host: process.env.VITE_DOMAIN_NAME || 'localhost' }, - preview: { port: parseInt(process.env.VITE_PORT || '5000') } + preview: { + port: parseInt(process.env.VITE_PORT || '5000'), + host: process.env.VITE_DOMAIN_NAME || 'localhost' + } }) From dab3a1bdfd442f99b38a5e0aa3befa2357e2994b Mon Sep 17 00:00:00 2001 From: Tal Jacob Date: Tue, 22 Jul 2025 11:14:06 +0300 Subject: [PATCH 4/4] Add Allowed Hosts Signed-off-by: Tal Jacob --- nextstep-frontend/.env.template | 1 + nextstep-frontend/vite.config.ts | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/nextstep-frontend/.env.template b/nextstep-frontend/.env.template index f004bde..59afee2 100644 --- a/nextstep-frontend/.env.template +++ b/nextstep-frontend/.env.template @@ -3,6 +3,7 @@ VITE_PORT= VITE_BACKEND_URL= VITE_DOMAIN_NAME= +VITE_ALLOWED_HOSTS= VITE_REACT_APP_FIREBASE_API_KEY= VITE_REACT_APP_FIREBASE_AUTH_DOMAIN= VITE_REACT_APP_FIREBASE_PROJECT_ID= diff --git a/nextstep-frontend/vite.config.ts b/nextstep-frontend/vite.config.ts index febbf60..c82bfd8 100644 --- a/nextstep-frontend/vite.config.ts +++ b/nextstep-frontend/vite.config.ts @@ -1,16 +1,21 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import dotenv from 'dotenv'; +import dotenv from 'dotenv' +dotenv.config() -dotenv.config(); +const allowedHosts = (process.env.VITE_ALLOWED_HOSTS || '') + .split(';') + .map(host => host.trim()) + .filter(Boolean) // remove empty strings // https://vite.dev/config/ export default defineConfig({ plugins: [react()], server: { port: parseInt(process.env.VITE_PORT || '5000'), - host: process.env.VITE_DOMAIN_NAME || 'localhost' + host: process.env.VITE_DOMAIN_NAME || 'localhost', + allowedHosts: allowedHosts.length > 0 ? allowedHosts : undefined }, preview: { port: parseInt(process.env.VITE_PORT || '5000'),