Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"build": "nest build",
"format": "prettier --write \"**/*.{ts,sh}\" Dockerfile",
"dev": "NEST_DEBUG=true nest start --watch",
"health-check": "wait-on http://localhost:3000/health && echo 'API is ready!'",
"health-check": "wait-on http://localhost:3000/health/ping && echo 'API is ready!'",
"start": "nest start",
"start:debug": "nest start --debug --watch",
"start:prod": "NODE_ENV=production node dist/main.js",
Expand Down
3 changes: 2 additions & 1 deletion apps/api/src/app-router/app-router.module.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { AnalyticsModule } from "@/analytics/analytics.module";
import { AuthModule } from "@/auth/auth.module";
import { ExtensionModule } from "@/extension/extension.module";
import { HealthModule } from "@/health/health.module";
import { Module } from "@nestjs/common";

import { AppRouterRouter } from "./app-router.router";
import { appRouterProvider } from "./providers/app-router.provider";

@Module({
imports: [AuthModule, AnalyticsModule, ExtensionModule],
imports: [HealthModule, AuthModule, AnalyticsModule, ExtensionModule],

providers: [appRouterProvider, AppRouterRouter],
})
Expand Down
14 changes: 10 additions & 4 deletions apps/api/src/app-router/providers/app-router.provider.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { AnalyticsRouter } from "@/analytics/routers/analytics.router";
import { AuthRouter } from "@/auth/auth.router";
import { ExtensionRouter } from "@/extension/extension.router";
import { HealthRouter } from "@/health/health.router";
import { TrpcService } from "@/trpc/trpc.service";
import { Provider } from "@nestjs/common";

export const appRouterProvider = {
provide: "appRouter",
useFactory: (
trpcService: TrpcService,
healthRouter: HealthRouter,
authRouter: AuthRouter,
analyticsRouter: AnalyticsRouter,
extensionRouter: ExtensionRouter,
Expand All @@ -16,14 +18,18 @@ export const appRouterProvider = {
...authRouter.procedures(),
...extensionRouter.procedures(),
...analyticsRouter.procedures(),
health: {
ping: trpcService.publicProcedure().query(() => ({ status: "OK" })),
},
...healthRouter.procedures(),
});

return appRouter;
},
inject: [TrpcService, AuthRouter, AnalyticsRouter, ExtensionRouter],
inject: [
TrpcService,
HealthRouter,
AuthRouter,
AnalyticsRouter,
ExtensionRouter,
],
} satisfies Provider;

export type AppRouter = ReturnType<(typeof appRouterProvider)["useFactory"]>;
5 changes: 0 additions & 5 deletions apps/api/src/app.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,4 @@ export class AppController {
getHello(): string {
return this.appService.getHello();
}

@Get("/health")
health() {
return this.appService.health();
}
}
2 changes: 2 additions & 0 deletions apps/api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { EmailVerificationModule } from "./email-verifications/email-verificatio
import { EnvModule } from "./env/env.module";
import { ExtensionModule } from "./extension/extension.module";
import { FilesModule } from "./files/files.module";
import { HealthModule } from "./health/health.module";
import { LanguagesModule } from "./languages/languages.module";
import { PasswordResetsModule } from "./password-resets/password-resets.module";
import { ProjectsModule } from "./projects/projects.module";
Expand Down Expand Up @@ -56,6 +57,7 @@ import { UsersModule } from "./users/users.module";
ExtensionModule,
BranchesModule,
TelemetryModule,
HealthModule,
],
controllers: [AppController],
providers: [
Expand Down
4 changes: 0 additions & 4 deletions apps/api/src/app.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,4 @@ export class AppService {
getHello() {
return "Hello from the MoonCode API !";
}

health() {
return { status: "OK" };
}
}
41 changes: 41 additions & 0 deletions apps/api/src/health/health.controller.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { beforeEach, describe, expect, it, Mock, vi } from "vitest";

import { Test } from "@nestjs/testing";
import { Procedure } from "@vitest/spy";

import { HealthController } from "./health.controller";
import { HealthService } from "./health.service";

describe("HealthController", () => {
let healthController: HealthController;

let healthService: {
ping: Mock<Procedure>;
};

beforeEach(async () => {
vi.clearAllMocks();

healthService = { ping: vi.fn() };

const moduleRef = await Test.createTestingModule({
providers: [
HealthController,
{
provide: HealthService,
useValue: healthService,
},
],
}).compile();

healthController = moduleRef.get(HealthController);
});

describe("ping", () => {
it("should call the ping method of the healthService", () => {
healthController.ping();

expect(healthService.ping).toHaveBeenCalled();
});
});
});
13 changes: 13 additions & 0 deletions apps/api/src/health/health.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Controller, Get } from "@nestjs/common";

import { HealthService } from "./health.service";

@Controller("health")
export class HealthController {
constructor(private readonly healthService: HealthService) {}

@Get("ping")
ping() {
return this.healthService.ping();
}
}
12 changes: 12 additions & 0 deletions apps/api/src/health/health.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Module } from "@nestjs/common";

import { HealthController } from "./health.controller";
import { HealthRouter } from "./health.router";
import { HealthService } from "./health.service";

@Module({
controllers: [HealthController],
providers: [HealthService, HealthRouter],
exports: [HealthRouter],
})
export class HealthModule {}
92 changes: 92 additions & 0 deletions apps/api/src/health/health.router.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { Request, Response } from "express";
import { beforeEach, describe, expect, it, Mock, vi } from "vitest";

import { TrpcModule } from "@/trpc/trpc.module";
import { TrpcService } from "@/trpc/trpc.service";
import { Test } from "@nestjs/testing";
import { Procedure } from "@vitest/spy";

import { HealthRouter } from "./health.router";
import { HealthService } from "./health.service";

describe("HealthRouter", () => {
let healthRouter: HealthRouter;
let trpcService: TrpcService;

let healthService: {
ping: Mock<Procedure>;
};

const mockedCtx = {
req: {
headers: {
"x-forwarded-for": "",
} as Record<string, string>,
} as Request,

res: {
cookie: vi.fn() as Function,
clearCookie: vi.fn() as Function,
} as Response,
};

const mockedPayload = {
sub: "01kv1aqeffy49vc8bzq19nwvhh",
iat: 1780458967,
exp: 1782878167,
};

let caller: ReturnType<
ReturnType<HealthRouter["procedures"]>["health"]["createCaller"]
>;

beforeEach(async () => {
vi.clearAllMocks();

healthService = {
ping: vi.fn(),
};

const moduleRef = await Test.createTestingModule({
imports: [TrpcModule],
providers: [
HealthRouter,
{
provide: HealthService,
useValue: healthService,
},
],
}).compile();

healthRouter = moduleRef.get(HealthRouter);
trpcService = moduleRef.get(TrpcService);

caller = trpcService.trpc.createCallerFactory(
healthRouter.procedures().health,
)(mockedCtx);
vi.spyOn(trpcService, "getPayload").mockResolvedValue(mockedPayload);
});

describe("ping", () => {
const mockedOutput = {
status: "OK",
};

it("should call the ping method of the healthService", async () => {
healthService.ping.mockReturnValue(mockedOutput);

await caller.ping();

expect(healthService.ping).toHaveBeenCalled();
});

it("should return a status object", async () => {
healthService.ping.mockReturnValue(mockedOutput);

const statusObj = await caller.ping();

expect(statusObj).toBeDefined();
expect(statusObj).toEqual(mockedOutput);
});
});
});
22 changes: 22 additions & 0 deletions apps/api/src/health/health.router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { TrpcService } from "@/trpc/trpc.service";
import { Injectable } from "@nestjs/common";

import { HealthService } from "./health.service";

@Injectable()
export class HealthRouter {
constructor(
private readonly healthService: HealthService,
private readonly trpcService: TrpcService,
) {}

procedures() {
return {
health: this.trpcService.trpc.router({
ping: this.trpcService
.publicProcedure()
.query(() => this.healthService.ping()),
}),
};
}
}
27 changes: 27 additions & 0 deletions apps/api/src/health/health.service.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { beforeEach, describe, expect, it, vi } from "vitest";

import { Test } from "@nestjs/testing";

import { HealthService } from "./health.service";

describe("HealthService", () => {
let healthService: HealthService;

beforeEach(async () => {
vi.clearAllMocks();

const moduleRef = await Test.createTestingModule({
providers: [HealthService],
}).compile();

healthService = moduleRef.get(HealthService);
});

describe("ping", () => {
it("should return an OK status", () => {
const { status } = healthService.ping();
expect(status).toBeDefined();
expect(status).toEqual("OK");
});
});
});
8 changes: 8 additions & 0 deletions apps/api/src/health/health.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Injectable } from "@nestjs/common";

@Injectable()
export class HealthService {
ping() {
return { status: "OK" };
}
}
7 changes: 5 additions & 2 deletions apps/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,17 @@
},
"devDependencies": {
"@eslint/js": "^9.39.2",
"@rolldown/plugin-babel": "^0.2.3",
"@tailwindcss/vite": "^4.1.18",
"@types/babel__core": "^7.20.5",
"@types/d3": "^7.4.3",
"@types/node": "^22.19.9",
"@types/react": "^19.1.9",
"@types/react-dom": "^19.1.7",
"@types/recharts": "^1.8.29",
"@vitejs/plugin-react-swc": "^3.11.0",
"@vitejs/plugin-react": "^6.0.4",
"autoprefixer": "^10.4.24",
"babel-plugin-react-compiler": "^1.0.0",
"eslint": "^9.39.2",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-react-hooks": "^5.2.0",
Expand All @@ -57,7 +60,7 @@
"tailwindcss": "^4.1.17",
"typescript": "^5.9.3",
"typescript-eslint": "^8.54.0",
"vite": "^7.3.1",
"vite": "^8.1.5",
"vite-plugin-commonjs": "^0.10.4",
"vite-plugin-svgr": "^4.5.0"
}
Expand Down
7 changes: 7 additions & 0 deletions apps/dashboard/src/stores/period/types-schemas.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { z } from "zod";

import { IsoDateStringSchema } from "@repo/common/types-schemas";

import { PERIODS } from "./constants";

export const PeriodSchema = z.enum([...PERIODS]);

export const IsoDateSchema = IsoDateStringSchema.transform(
(dateStr) => new Date(dateStr),
);
Comment thread
Friedrich482 marked this conversation as resolved.

export type Period = z.infer<typeof PeriodSchema>;
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { z, ZodError } from "zod";

import { formatZodError } from "@repo/common/format-zod-error";
import { getLocaleDate } from "@repo/common/get-locale-date";
import { GroupBy, IsoDateSchema } from "@repo/common/types-schemas";
import { GroupBy } from "@repo/common/types-schemas";

import { PERIODS } from "../constants";
import { Period, PeriodSchema } from "../types-schemas";
import { IsoDateSchema, Period, PeriodSchema } from "../types-schemas";

type ReturnValues = {
period: Period;
Expand Down
Loading