diff --git a/docs/superpowers/refactor-logs/2026-05-05-lazar-pattern-conformance.md b/docs/superpowers/refactor-logs/2026-05-05-lazar-pattern-conformance.md index 12a2c37..fa86f05 100644 --- a/docs/superpowers/refactor-logs/2026-05-05-lazar-pattern-conformance.md +++ b/docs/superpowers/refactor-logs/2026-05-05-lazar-pattern-conformance.md @@ -105,6 +105,13 @@ Entity model moves (git mv — history preserved): - `packages/blog/src/interface-adapters/controllers/get-article-by-slug.controller.ts` — factory controller; now delegates to `getArticleBySlugUseCase` (which throws `ArticleNotFoundError`) instead of calling repo directly - `packages/blog/src/interface-adapters/controllers/get-article-by-slug.controller.test.ts` — 3 tests (found, not found → ArticleNotFoundError, empty slug → InputParseError) +### Task 6: Marketing-pages factory refactor — new files + +- `packages/marketing-pages/src/interface-adapters/controllers/get-page-by-slug.controller.ts` — factory controller; replaces `getPageBySlugController` function from `pages.controller.ts`; exports `IGetPageBySlugController` type alias +- `packages/marketing-pages/src/interface-adapters/controllers/get-page-by-slug.controller.test.ts` — 3 tests (slug found, slug not found → undefined, missing slug → InputParseError) +- `packages/marketing-pages/src/interface-adapters/controllers/get-site-settings.controller.ts` — factory controller; replaces `getSiteSettingsController` function from `pages.controller.ts`; exports `IGetSiteSettingsController` type alias +- `packages/marketing-pages/src/interface-adapters/controllers/get-site-settings.controller.test.ts` — 1 test (returns site settings) + ### Task 2: Entities split — new error files - `packages/auth/src/entities/errors/auth.ts` — AuthenticationError, UnauthenticatedError, UnauthorizedError (split from errors.ts) @@ -123,6 +130,11 @@ Entity model moves (git mv — history preserved): - `packages/blog/src/interface-adapters/controllers/articles.controller.ts` — multi-method controller replaced by 3 single-responsibility factory files (`get-articles.controller.ts`, `create-article.controller.ts`, `get-article-by-slug.controller.ts`) - `packages/blog/src/interface-adapters/controllers/articles.controller.test.ts` — deleted with the controller; tests rewritten in the per-controller test files +### Task 6: Marketing-pages factory refactor — deleted files + +- `packages/marketing-pages/src/interface-adapters/controllers/pages.controller.ts` — multi-method controller replaced by 2 single-responsibility factory files (`get-page-by-slug.controller.ts`, `get-site-settings.controller.ts`) +- `packages/marketing-pages/src/interface-adapters/controllers/pages.controller.test.ts` — deleted with the controller; tests rewritten in the per-controller test files + ### Task 2: Entities split — old errors.ts files removed - `packages/auth/src/entities/errors.ts` — replaced by `errors/auth.ts` + `errors/common.ts` @@ -134,20 +146,22 @@ Entity model moves (git mv — history preserved): ### 4.1 Use cases — factory function pattern -Applied to all 3 auth use cases (`sign-in`, `sign-up`, `sign-out`) in Task 4, and all 3 blog use cases (`get-articles`, `create-article`, `get-article-by-slug` NEW) in Task 5: +Applied to all 3 auth use cases (`sign-in`, `sign-up`, `sign-out`) in Task 4, all 3 blog use cases (`get-articles`, `create-article`, `get-article-by-slug` NEW) in Task 5, and both marketing-pages use cases (`get-page-by-slug`, `get-site-settings`) in Task 6: - Use cases are now factory functions: `(deps) => async (input) => result` - Each file exports `export type I*UseCase = ReturnType` for DI typing - Use cases NO LONGER call `*Container.get()` inside their bodies — all dependencies are passed as factory arguments - Tests construct mocks directly: `const useCase = getArticlesUseCase(repo); await useCase({ status: "draft" });` - NEW `getArticleBySlugUseCase`: previously the slug lookup bypassed the use case layer (controller called repo directly); now the use case owns the `ArticleNotFoundError` throw +- marketing-pages: `getPageBySlugUseCase(pagesRepo) => async ({ slug }) => Page | undefined` and `getSiteSettingsUseCase(siteSettingsRepo) => async () => SiteSettings` ### 4.2 Controllers — one per use case -Applied to all 3 auth controllers (`sign-in`, `sign-up`, `sign-out`) in Task 4; blog controllers split in Task 5: +Applied to all 3 auth controllers (`sign-in`, `sign-up`, `sign-out`) in Task 4; blog controllers split in Task 5; marketing-pages controllers split in Task 6: - Controllers were already split for auth (one file per use case) — Task 4 refactors them to factory functions - Blog: the multi-method `articles.controller.ts` is deleted and replaced by 3 single-responsibility files +- Marketing-pages: the multi-method `pages.controller.ts` is deleted and replaced by 2 single-responsibility files (`get-page-by-slug.controller.ts`, `get-site-settings.controller.ts`) - Factory pattern: `(useCase: I*UseCase) => async (input) => result` - Each exports `export type I*Controller = ReturnType` - Validation (Zod `safeParse`) stays inside the controller factory; throws `InputParseError` on failure @@ -167,7 +181,7 @@ Pattern now in place across auth, blog, marketing-pages, navigation (media skipp ### 5.1 Inversify `.toDynamicValue` bindings -Applied to `packages/auth/src/di/module.ts` (Task 4) and `packages/blog/src/di/module.ts` (Task 5): +Applied to `packages/auth/src/di/module.ts` (Task 4), `packages/blog/src/di/module.ts` (Task 5), and `packages/marketing-pages/src/di/module.ts` (Task 6): **auth:** - `AUTH_SYMBOLS` expanded with 6 new keys: `ISignInUseCase`, `ISignUpUseCase`, `ISignOutUseCase`, `ISignInController`, `ISignUpController`, `ISignOutController` @@ -181,6 +195,12 @@ Applied to `packages/auth/src/di/module.ts` (Task 4) and `packages/blog/src/di/m - Repository binding remains `.to(MockArticlesRepository)` as the default - tRPC router (`integrations/api/router.ts`) updated to resolve controllers via `blogContainer.get(BLOG_SYMBOLS.IXController)` instead of importing controllers directly +**marketing-pages:** +- `MARKETING_PAGES_SYMBOLS` expanded with 4 new keys: `IGetPageBySlugUseCase`, `IGetSiteSettingsUseCase`, `IGetPageBySlugController`, `IGetSiteSettingsController` +- Both use cases and both controllers bound with `.toDynamicValue()` — each use case receives its own repository from the container; each controller receives its use case +- Repository bindings remain `.to(MockPagesRepository)` and `.to(MockSiteSettingsRepository)` as defaults +- tRPC router updated to resolve controllers via `marketingPagesContainer.get(MARKETING_PAGES_SYMBOLS.IXController)` + ### 5.2 Mock siblings registered as default bindings - `MockUsersRepository` and `MockAuthenticationService` remain the default bindings in `AuthModule` diff --git a/packages/marketing-pages/src/application/use-cases/get-page-by-slug.use-case.test.ts b/packages/marketing-pages/src/application/use-cases/get-page-by-slug.use-case.test.ts index a9a3f52..803899a 100644 --- a/packages/marketing-pages/src/application/use-cases/get-page-by-slug.use-case.test.ts +++ b/packages/marketing-pages/src/application/use-cases/get-page-by-slug.use-case.test.ts @@ -1,30 +1,19 @@ -import { beforeEach, describe, expect, it } from "vitest"; -import { marketingPagesContainer } from "@/di/container"; -import { MARKETING_PAGES_SYMBOLS } from "@/di/symbols"; +import { describe, it, expect } from "vitest"; +import { getPageBySlugUseCase } from "@/application/use-cases/get-page-by-slug.use-case"; import { MockPagesRepository } from "@/infrastructure/repositories/pages.repository.mock"; -import type { IPagesRepository } from "@/application/repositories/pages.repository.interface"; -import { getPageBySlugUseCase } from "./get-page-by-slug.use-case"; describe("getPageBySlugUseCase", () => { - let repo: MockPagesRepository; - - beforeEach(() => { - if (marketingPagesContainer.isBound(MARKETING_PAGES_SYMBOLS.IPagesRepository)) { - marketingPagesContainer.unbind(MARKETING_PAGES_SYMBOLS.IPagesRepository); - } - repo = new MockPagesRepository(); - marketingPagesContainer - .bind(MARKETING_PAGES_SYMBOLS.IPagesRepository) - .toConstantValue(repo); - }); - it("returns the page when found", async () => { - const result = await getPageBySlugUseCase("about"); + const repo = new MockPagesRepository(); + const useCase = getPageBySlugUseCase(repo); + const result = await useCase({ slug: "about" }); expect(result?.slug).toBe("about"); }); it("returns undefined when not found", async () => { - const result = await getPageBySlugUseCase("missing-page"); + const repo = new MockPagesRepository(); + const useCase = getPageBySlugUseCase(repo); + const result = await useCase({ slug: "missing-page" }); expect(result).toBeUndefined(); }); }); diff --git a/packages/marketing-pages/src/application/use-cases/get-page-by-slug.use-case.ts b/packages/marketing-pages/src/application/use-cases/get-page-by-slug.use-case.ts index 538391a..edc36e5 100644 --- a/packages/marketing-pages/src/application/use-cases/get-page-by-slug.use-case.ts +++ b/packages/marketing-pages/src/application/use-cases/get-page-by-slug.use-case.ts @@ -1,13 +1,10 @@ import type { Page } from "../../entities/models/page"; -import { marketingPagesContainer } from "../../di/container"; -import { MARKETING_PAGES_SYMBOLS } from "../../di/symbols"; import type { IPagesRepository } from "../repositories/pages.repository.interface"; -export async function getPageBySlugUseCase( - slug: string, -): Promise { - const repo = marketingPagesContainer.get( - MARKETING_PAGES_SYMBOLS.IPagesRepository, - ); - return repo.getPageBySlug(slug); -} +export type IGetPageBySlugUseCase = ReturnType; + +export const getPageBySlugUseCase = + (pagesRepository: IPagesRepository) => + async (input: { slug: string }): Promise => { + return pagesRepository.getPageBySlug(input.slug); + }; diff --git a/packages/marketing-pages/src/application/use-cases/get-site-settings.use-case.test.ts b/packages/marketing-pages/src/application/use-cases/get-site-settings.use-case.test.ts index dd9d407..5f1fb5b 100644 --- a/packages/marketing-pages/src/application/use-cases/get-site-settings.use-case.test.ts +++ b/packages/marketing-pages/src/application/use-cases/get-site-settings.use-case.test.ts @@ -1,25 +1,12 @@ -import { beforeEach, describe, expect, it } from "vitest"; -import { marketingPagesContainer } from "@/di/container"; -import { MARKETING_PAGES_SYMBOLS } from "@/di/symbols"; +import { describe, it, expect } from "vitest"; +import { getSiteSettingsUseCase } from "@/application/use-cases/get-site-settings.use-case"; import { MockSiteSettingsRepository } from "@/infrastructure/repositories/site-settings.repository.mock"; -import type { ISiteSettingsRepository } from "@/application/repositories/site-settings.repository.interface"; -import { getSiteSettingsUseCase } from "./get-site-settings.use-case"; describe("getSiteSettingsUseCase", () => { - let repo: MockSiteSettingsRepository; - - beforeEach(() => { - if (marketingPagesContainer.isBound(MARKETING_PAGES_SYMBOLS.ISiteSettingsRepository)) { - marketingPagesContainer.unbind(MARKETING_PAGES_SYMBOLS.ISiteSettingsRepository); - } - repo = new MockSiteSettingsRepository(); - marketingPagesContainer - .bind(MARKETING_PAGES_SYMBOLS.ISiteSettingsRepository) - .toConstantValue(repo); - }); - it("returns the seeded site settings", async () => { - const result = await getSiteSettingsUseCase(); + const repo = new MockSiteSettingsRepository(); + const useCase = getSiteSettingsUseCase(repo); + const result = await useCase(); expect(result.siteName).toBe("My App"); }); }); diff --git a/packages/marketing-pages/src/application/use-cases/get-site-settings.use-case.ts b/packages/marketing-pages/src/application/use-cases/get-site-settings.use-case.ts index bd4452d..db0f549 100644 --- a/packages/marketing-pages/src/application/use-cases/get-site-settings.use-case.ts +++ b/packages/marketing-pages/src/application/use-cases/get-site-settings.use-case.ts @@ -1,11 +1,10 @@ import type { SiteSettings } from "../../entities/models/site-settings"; -import { marketingPagesContainer } from "../../di/container"; -import { MARKETING_PAGES_SYMBOLS } from "../../di/symbols"; import type { ISiteSettingsRepository } from "../repositories/site-settings.repository.interface"; -export async function getSiteSettingsUseCase(): Promise { - const repo = marketingPagesContainer.get( - MARKETING_PAGES_SYMBOLS.ISiteSettingsRepository, - ); - return repo.getSiteSettings(); -} +export type IGetSiteSettingsUseCase = ReturnType; + +export const getSiteSettingsUseCase = + (siteSettingsRepository: ISiteSettingsRepository) => + async (): Promise => { + return siteSettingsRepository.getSiteSettings(); + }; diff --git a/packages/marketing-pages/src/di/module.ts b/packages/marketing-pages/src/di/module.ts index c821732..35c19e2 100644 --- a/packages/marketing-pages/src/di/module.ts +++ b/packages/marketing-pages/src/di/module.ts @@ -4,6 +4,22 @@ import type { IPagesRepository } from "../application/repositories/pages.reposit import type { ISiteSettingsRepository } from "../application/repositories/site-settings.repository.interface"; import { MockPagesRepository } from "../infrastructure/repositories/pages.repository.mock"; import { MockSiteSettingsRepository } from "../infrastructure/repositories/site-settings.repository.mock"; +import { + getPageBySlugUseCase, + type IGetPageBySlugUseCase, +} from "../application/use-cases/get-page-by-slug.use-case"; +import { + getSiteSettingsUseCase, + type IGetSiteSettingsUseCase, +} from "../application/use-cases/get-site-settings.use-case"; +import { + getPageBySlugController, + type IGetPageBySlugController, +} from "../interface-adapters/controllers/get-page-by-slug.controller"; +import { + getSiteSettingsController, + type IGetSiteSettingsController, +} from "../interface-adapters/controllers/get-site-settings.controller"; import { MARKETING_PAGES_SYMBOLS } from "./symbols"; export const MarketingPagesModule = new ContainerModule( @@ -14,5 +30,39 @@ export const MarketingPagesModule = new ContainerModule( bind( MARKETING_PAGES_SYMBOLS.ISiteSettingsRepository, ).to(MockSiteSettingsRepository); + + bind(MARKETING_PAGES_SYMBOLS.IGetPageBySlugUseCase).toDynamicValue( + (ctx) => + getPageBySlugUseCase( + ctx.container.get(MARKETING_PAGES_SYMBOLS.IPagesRepository), + ), + ); + + bind(MARKETING_PAGES_SYMBOLS.IGetSiteSettingsUseCase).toDynamicValue( + (ctx) => + getSiteSettingsUseCase( + ctx.container.get( + MARKETING_PAGES_SYMBOLS.ISiteSettingsRepository, + ), + ), + ); + + bind( + MARKETING_PAGES_SYMBOLS.IGetPageBySlugController, + ).toDynamicValue((ctx) => + getPageBySlugController( + ctx.container.get(MARKETING_PAGES_SYMBOLS.IGetPageBySlugUseCase), + ), + ); + + bind( + MARKETING_PAGES_SYMBOLS.IGetSiteSettingsController, + ).toDynamicValue((ctx) => + getSiteSettingsController( + ctx.container.get( + MARKETING_PAGES_SYMBOLS.IGetSiteSettingsUseCase, + ), + ), + ); }, ); diff --git a/packages/marketing-pages/src/di/symbols.ts b/packages/marketing-pages/src/di/symbols.ts index 7f82590..f666c97 100644 --- a/packages/marketing-pages/src/di/symbols.ts +++ b/packages/marketing-pages/src/di/symbols.ts @@ -1,4 +1,10 @@ export const MARKETING_PAGES_SYMBOLS = { IPagesRepository: Symbol.for("marketing-pages:IPagesRepository"), ISiteSettingsRepository: Symbol.for("marketing-pages:ISiteSettingsRepository"), + // Use cases + IGetPageBySlugUseCase: Symbol.for("marketing-pages:IGetPageBySlugUseCase"), + IGetSiteSettingsUseCase: Symbol.for("marketing-pages:IGetSiteSettingsUseCase"), + // Controllers + IGetPageBySlugController: Symbol.for("marketing-pages:IGetPageBySlugController"), + IGetSiteSettingsController: Symbol.for("marketing-pages:IGetSiteSettingsController"), } as const; diff --git a/packages/marketing-pages/src/integrations/api/router.test.ts b/packages/marketing-pages/src/integrations/api/router.test.ts index 74ac19a..2dda4b3 100644 --- a/packages/marketing-pages/src/integrations/api/router.test.ts +++ b/packages/marketing-pages/src/integrations/api/router.test.ts @@ -1,28 +1,7 @@ -import { beforeEach, describe, expect, it } from "vitest"; -import { marketingPagesContainer } from "@/di/container"; -import { MARKETING_PAGES_SYMBOLS } from "@/di/symbols"; -import { MockPagesRepository } from "@/infrastructure/repositories/pages.repository.mock"; -import { MockSiteSettingsRepository } from "@/infrastructure/repositories/site-settings.repository.mock"; -import type { IPagesRepository } from "@/application/repositories/pages.repository.interface"; -import type { ISiteSettingsRepository } from "@/application/repositories/site-settings.repository.interface"; +import { describe, it, expect } from "vitest"; import { marketingPagesRouter } from "./router"; describe("marketingPagesRouter", () => { - beforeEach(() => { - if (marketingPagesContainer.isBound(MARKETING_PAGES_SYMBOLS.IPagesRepository)) { - marketingPagesContainer.unbind(MARKETING_PAGES_SYMBOLS.IPagesRepository); - } - if (marketingPagesContainer.isBound(MARKETING_PAGES_SYMBOLS.ISiteSettingsRepository)) { - marketingPagesContainer.unbind(MARKETING_PAGES_SYMBOLS.ISiteSettingsRepository); - } - marketingPagesContainer - .bind(MARKETING_PAGES_SYMBOLS.IPagesRepository) - .toConstantValue(new MockPagesRepository()); - marketingPagesContainer - .bind(MARKETING_PAGES_SYMBOLS.ISiteSettingsRepository) - .toConstantValue(new MockSiteSettingsRepository()); - }); - it("exposes pageBySlug + siteSettings procedures", () => { const names = Object.keys(marketingPagesRouter._def.procedures); expect(names).toContain("pageBySlug"); diff --git a/packages/marketing-pages/src/integrations/api/router.ts b/packages/marketing-pages/src/integrations/api/router.ts index f4b086d..98848ed 100644 --- a/packages/marketing-pages/src/integrations/api/router.ts +++ b/packages/marketing-pages/src/integrations/api/router.ts @@ -1,16 +1,26 @@ import { z } from "zod"; import { router, publicProcedure } from "@repo/core-shared/trpc/init"; -import { - getPageBySlugController, - getSiteSettingsController, -} from "../../interface-adapters/controllers/pages.controller"; +import { marketingPagesContainer } from "../../di/container"; +import { MARKETING_PAGES_SYMBOLS } from "../../di/symbols"; +import type { IGetPageBySlugController } from "../../interface-adapters/controllers/get-page-by-slug.controller"; +import type { IGetSiteSettingsController } from "../../interface-adapters/controllers/get-site-settings.controller"; export const marketingPagesRouter = router({ pageBySlug: publicProcedure .input(z.object({ slug: z.string().min(1) })) - .query(({ input }) => getPageBySlugController(input)), + .query(({ input }) => { + const ctrl = marketingPagesContainer.get( + MARKETING_PAGES_SYMBOLS.IGetPageBySlugController, + ); + return ctrl(input); + }), - siteSettings: publicProcedure.query(() => getSiteSettingsController()), + siteSettings: publicProcedure.query(() => { + const ctrl = marketingPagesContainer.get( + MARKETING_PAGES_SYMBOLS.IGetSiteSettingsController, + ); + return ctrl(); + }), }); export type MarketingPagesRouter = typeof marketingPagesRouter; diff --git a/packages/marketing-pages/src/interface-adapters/controllers/get-page-by-slug.controller.test.ts b/packages/marketing-pages/src/interface-adapters/controllers/get-page-by-slug.controller.test.ts new file mode 100644 index 0000000..c582eea --- /dev/null +++ b/packages/marketing-pages/src/interface-adapters/controllers/get-page-by-slug.controller.test.ts @@ -0,0 +1,35 @@ +import { describe, it, expect } from "vitest"; +import { getPageBySlugController } from "@/interface-adapters/controllers/get-page-by-slug.controller"; +import { getPageBySlugUseCase } from "@/application/use-cases/get-page-by-slug.use-case"; +import { MockPagesRepository } from "@/infrastructure/repositories/pages.repository.mock"; +import { InputParseError } from "@/entities/errors/common"; + +describe("getPageBySlugController", () => { + it("returns the page when found", async () => { + const repo = new MockPagesRepository(); + const useCase = getPageBySlugUseCase(repo); + const controller = getPageBySlugController(useCase); + + const result = await controller({ slug: "about" }); + expect(result?.slug).toBe("about"); + }); + + it("throws InputParseError on missing slug", async () => { + const repo = new MockPagesRepository(); + const useCase = getPageBySlugUseCase(repo); + const controller = getPageBySlugController(useCase); + + await expect( + controller({} as { slug: string }), + ).rejects.toBeInstanceOf(InputParseError); + }); + + it("returns undefined when slug not found", async () => { + const repo = new MockPagesRepository(); + const useCase = getPageBySlugUseCase(repo); + const controller = getPageBySlugController(useCase); + + const result = await controller({ slug: "nonexistent" }); + expect(result).toBeUndefined(); + }); +}); diff --git a/packages/marketing-pages/src/interface-adapters/controllers/get-page-by-slug.controller.ts b/packages/marketing-pages/src/interface-adapters/controllers/get-page-by-slug.controller.ts new file mode 100644 index 0000000..6e057c0 --- /dev/null +++ b/packages/marketing-pages/src/interface-adapters/controllers/get-page-by-slug.controller.ts @@ -0,0 +1,23 @@ +import { z } from "zod"; + +import { InputParseError } from "../../entities/errors/common"; +import type { Page } from "../../entities/models/page"; +import type { IGetPageBySlugUseCase } from "../../application/use-cases/get-page-by-slug.use-case"; + +const inputSchema = z.object({ + slug: z.string().min(1), +}); + +export type IGetPageBySlugController = ReturnType; + +export const getPageBySlugController = + (getPageBySlugUseCase: IGetPageBySlugUseCase) => + async (input: Partial>): Promise => { + const parsed = inputSchema.safeParse(input); + if (!parsed.success) { + throw new InputParseError("Invalid get-page-by-slug input", { + cause: parsed.error, + }); + } + return getPageBySlugUseCase(parsed.data); + }; diff --git a/packages/marketing-pages/src/interface-adapters/controllers/get-site-settings.controller.test.ts b/packages/marketing-pages/src/interface-adapters/controllers/get-site-settings.controller.test.ts new file mode 100644 index 0000000..038095e --- /dev/null +++ b/packages/marketing-pages/src/interface-adapters/controllers/get-site-settings.controller.test.ts @@ -0,0 +1,15 @@ +import { describe, it, expect } from "vitest"; +import { getSiteSettingsController } from "@/interface-adapters/controllers/get-site-settings.controller"; +import { getSiteSettingsUseCase } from "@/application/use-cases/get-site-settings.use-case"; +import { MockSiteSettingsRepository } from "@/infrastructure/repositories/site-settings.repository.mock"; + +describe("getSiteSettingsController", () => { + it("returns site settings", async () => { + const repo = new MockSiteSettingsRepository(); + const useCase = getSiteSettingsUseCase(repo); + const controller = getSiteSettingsController(useCase); + + const result = await controller(); + expect(result.siteName).toBe("My App"); + }); +}); diff --git a/packages/marketing-pages/src/interface-adapters/controllers/get-site-settings.controller.ts b/packages/marketing-pages/src/interface-adapters/controllers/get-site-settings.controller.ts new file mode 100644 index 0000000..f6166d2 --- /dev/null +++ b/packages/marketing-pages/src/interface-adapters/controllers/get-site-settings.controller.ts @@ -0,0 +1,10 @@ +import type { SiteSettings } from "../../entities/models/site-settings"; +import type { IGetSiteSettingsUseCase } from "../../application/use-cases/get-site-settings.use-case"; + +export type IGetSiteSettingsController = ReturnType; + +export const getSiteSettingsController = + (getSiteSettingsUseCase: IGetSiteSettingsUseCase) => + async (): Promise => { + return getSiteSettingsUseCase(); + }; diff --git a/packages/marketing-pages/src/interface-adapters/controllers/pages.controller.test.ts b/packages/marketing-pages/src/interface-adapters/controllers/pages.controller.test.ts deleted file mode 100644 index ce7b071..0000000 --- a/packages/marketing-pages/src/interface-adapters/controllers/pages.controller.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { beforeEach, describe, expect, it } from "vitest"; -import { marketingPagesContainer } from "@/di/container"; -import { MARKETING_PAGES_SYMBOLS } from "@/di/symbols"; -import { MockPagesRepository } from "@/infrastructure/repositories/pages.repository.mock"; -import { MockSiteSettingsRepository } from "@/infrastructure/repositories/site-settings.repository.mock"; -import type { IPagesRepository } from "@/application/repositories/pages.repository.interface"; -import type { ISiteSettingsRepository } from "@/application/repositories/site-settings.repository.interface"; -import { InputParseError } from "@/entities/errors/common"; -import { - getPageBySlugController, - getSiteSettingsController, -} from "./pages.controller"; - -describe("pages controller", () => { - beforeEach(() => { - if (marketingPagesContainer.isBound(MARKETING_PAGES_SYMBOLS.IPagesRepository)) { - marketingPagesContainer.unbind(MARKETING_PAGES_SYMBOLS.IPagesRepository); - } - if (marketingPagesContainer.isBound(MARKETING_PAGES_SYMBOLS.ISiteSettingsRepository)) { - marketingPagesContainer.unbind(MARKETING_PAGES_SYMBOLS.ISiteSettingsRepository); - } - marketingPagesContainer - .bind(MARKETING_PAGES_SYMBOLS.IPagesRepository) - .toConstantValue(new MockPagesRepository()); - marketingPagesContainer - .bind(MARKETING_PAGES_SYMBOLS.ISiteSettingsRepository) - .toConstantValue(new MockSiteSettingsRepository()); - }); - - describe("getPageBySlugController", () => { - it("returns the page when found", async () => { - const result = await getPageBySlugController({ slug: "about" }); - expect(result?.slug).toBe("about"); - }); - - it("throws InputParseError on missing slug", async () => { - await expect( - getPageBySlugController({} as { slug: string }), - ).rejects.toBeInstanceOf(InputParseError); - }); - }); - - describe("getSiteSettingsController", () => { - it("returns site settings", async () => { - const result = await getSiteSettingsController(); - expect(result.siteName).toBe("My App"); - }); - }); -}); diff --git a/packages/marketing-pages/src/interface-adapters/controllers/pages.controller.ts b/packages/marketing-pages/src/interface-adapters/controllers/pages.controller.ts deleted file mode 100644 index c5d64f0..0000000 --- a/packages/marketing-pages/src/interface-adapters/controllers/pages.controller.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { z } from "zod"; - -import { InputParseError } from "../../entities/errors/common"; -import type { Page } from "../../entities/models/page"; -import type { SiteSettings } from "../../entities/models/site-settings"; -import { getPageBySlugUseCase } from "../../application/use-cases/get-page-by-slug.use-case"; -import { getSiteSettingsUseCase } from "../../application/use-cases/get-site-settings.use-case"; - -const getBySlugInputSchema = z.object({ - slug: z.string().min(1), -}); - -export async function getPageBySlugController(input: { - slug: string; -}): Promise { - const parsed = getBySlugInputSchema.safeParse(input); - if (!parsed.success) { - throw new InputParseError("Invalid get-page-by-slug input", { - cause: parsed.error, - }); - } - return getPageBySlugUseCase(parsed.data.slug); -} - -export async function getSiteSettingsController(): Promise { - return getSiteSettingsUseCase(); -}