import { withSpan, withCapture, INSTRUMENTATION_SYMBOLS, type ITracer, type ILogger, } from "@repo/core-shared/instrumentation"; import type { BindContext } from "@repo/core-shared/di"; import { authContainer } from "./container.js"; import { AUTH_SYMBOLS } from "./symbols.js"; import { MockUsersRepository } from "../infrastructure/repositories/users.repository.mock.js"; import { buildDevUsers } from "../__seeds__/dev.js"; import { signInUseCase } from "../application/use-cases/sign-in.use-case.js"; import { signUpUseCase } from "../application/use-cases/sign-up.use-case.js"; import { signOutUseCase } from "../application/use-cases/sign-out.use-case.js"; import { signInController } from "../interface-adapters/controllers/sign-in.controller.js"; import { signUpController } from "../interface-adapters/controllers/sign-up.controller.js"; import { signOutController } from "../interface-adapters/controllers/sign-out.controller.js"; import type { IUsersRepository } from "../application/repositories/users.repository.interface.js"; import type { IAuthenticationService } from "../application/services/authentication.service.interface.js"; /** * Replace the default mock with a populated one for dev mode + storybook. * * Call this from app boot when `USE_DEV_SEED=true`, mutually exclusive with * `bindProductionAuth(config)`. Tests must NOT call this — they construct * `new MockUsersRepository()` directly and seed via factories per-test. * * The `IAuthenticationService` binding is left untouched; it resolves users * through DI from the newly seeded repo. * * Idempotent: safe to call multiple times; each call rebuilds a fresh * populated repo and rebinds the symbol. */ export async function bindDevSeedAuth(ctx: BindContext): Promise { const { tracer, logger, bus, queue, realtime, realtimeRegistry } = ctx; // Bind shared instrumentation into feature container if (authContainer.isBound(INSTRUMENTATION_SYMBOLS.TRACER)) { authContainer.unbind(INSTRUMENTATION_SYMBOLS.TRACER); } if (authContainer.isBound(INSTRUMENTATION_SYMBOLS.LOGGER)) { authContainer.unbind(INSTRUMENTATION_SYMBOLS.LOGGER); } authContainer.bind(INSTRUMENTATION_SYMBOLS.TRACER).toConstantValue(tracer); authContainer.bind(INSTRUMENTATION_SYMBOLS.LOGGER).toConstantValue(logger); if (authContainer.isBound(AUTH_SYMBOLS.IUsersRepository)) { authContainer.unbind(AUTH_SYMBOLS.IUsersRepository); } const repo = new MockUsersRepository([], tracer, logger); for (const user of buildDevUsers()) { await repo.createUser(user); } authContainer .bind(AUTH_SYMBOLS.IUsersRepository) .toConstantValue(repo); // Need auth service from container for use cases const authService = authContainer.get(AUTH_SYMBOLS.IAuthenticationService); // Wrap use cases + controllers identically to bind-production const wrappedSignIn = withSpan( tracer, { name: "auth.signIn", op: "use-case" }, withCapture( logger, { feature: "auth", layer: "use-case", name: "auth.signIn" }, signInUseCase(repo, authService), ), ); const wrappedSignUp = withSpan( tracer, { name: "auth.signUp", op: "use-case" }, withCapture( logger, { feature: "auth", layer: "use-case", name: "auth.signUp" }, signUpUseCase(repo, authService, bus), ), ); const wrappedSignOut = withSpan( tracer, { name: "auth.signOut", op: "use-case" }, withCapture( logger, { feature: "auth", layer: "use-case", name: "auth.signOut" }, signOutUseCase(authService), ), ); for (const sym of [ AUTH_SYMBOLS.ISignInUseCase, AUTH_SYMBOLS.ISignUpUseCase, AUTH_SYMBOLS.ISignOutUseCase, AUTH_SYMBOLS.ISignInController, AUTH_SYMBOLS.ISignUpController, AUTH_SYMBOLS.ISignOutController, ]) { if (authContainer.isBound(sym)) authContainer.unbind(sym); } authContainer.bind(AUTH_SYMBOLS.ISignInUseCase).toConstantValue(wrappedSignIn); authContainer.bind(AUTH_SYMBOLS.ISignUpUseCase).toConstantValue(wrappedSignUp); authContainer.bind(AUTH_SYMBOLS.ISignOutUseCase).toConstantValue(wrappedSignOut); authContainer .bind(AUTH_SYMBOLS.ISignInController) .toConstantValue( withSpan( tracer, { name: "auth.signIn", op: "controller" }, withCapture( logger, { feature: "auth", layer: "controller", name: "auth.signIn" }, signInController(wrappedSignIn), ), ), ); authContainer .bind(AUTH_SYMBOLS.ISignUpController) .toConstantValue( withSpan( tracer, { name: "auth.signUp", op: "controller" }, withCapture( logger, { feature: "auth", layer: "controller", name: "auth.signUp" }, signUpController(wrappedSignUp), ), ), ); authContainer .bind(AUTH_SYMBOLS.ISignOutController) .toConstantValue( withSpan( tracer, { name: "auth.signOut", op: "controller" }, withCapture( logger, { feature: "auth", layer: "controller", name: "auth.signOut" }, signOutController(wrappedSignOut), ), ), ); // bus + queue are accept-and-forward in Phase 6; consumed by Phase 7 generator // output at the / anchors below. void bus; void queue; void realtime; void realtimeRegistry; // // // }