Files
agentic-dev/packages/blog/src/di/bind-production.ts

142 lines
5.2 KiB
TypeScript

import {
withSpan,
withCapture,
INSTRUMENTATION_SYMBOLS,
type ITracer,
type ILogger,
} from "@repo/core-shared/instrumentation";
import type { BindProductionContext } from "@repo/core-shared/di";
import { blogContainer } from "./container";
import { BLOG_SYMBOLS } from "./symbols";
import { ArticlesRepository } from "../infrastructure/repositories/articles.repository";
import { getArticlesUseCase } from "../application/use-cases/get-articles.use-case";
import { getArticleBySlugUseCase } from "../application/use-cases/get-article-by-slug.use-case";
import { createArticleUseCase } from "../application/use-cases/create-article.use-case";
import { getArticlesController } from "../interface-adapters/controllers/get-articles.controller";
import { getArticleBySlugController } from "../interface-adapters/controllers/get-article-by-slug.controller";
import { createArticleController } from "../interface-adapters/controllers/create-article.controller";
export function bindProductionBlog(ctx: BindProductionContext): void {
const { config, tracer, logger, bus, queue, realtime, realtimeRegistry } = ctx;
// Bind shared instrumentation into feature container
if (blogContainer.isBound(INSTRUMENTATION_SYMBOLS.TRACER)) {
blogContainer.unbind(INSTRUMENTATION_SYMBOLS.TRACER);
}
if (blogContainer.isBound(INSTRUMENTATION_SYMBOLS.LOGGER)) {
blogContainer.unbind(INSTRUMENTATION_SYMBOLS.LOGGER);
}
blogContainer.bind<ITracer>(INSTRUMENTATION_SYMBOLS.TRACER).toConstantValue(tracer);
blogContainer.bind<ILogger>(INSTRUMENTATION_SYMBOLS.LOGGER).toConstantValue(logger);
// Real repository
if (blogContainer.isBound(BLOG_SYMBOLS.IArticlesRepository)) {
blogContainer.unbind(BLOG_SYMBOLS.IArticlesRepository);
}
const repo = new ArticlesRepository(config, tracer, logger);
blogContainer.bind(BLOG_SYMBOLS.IArticlesRepository).toConstantValue(repo);
// Use cases — wrapped with span + capture at bind time (R41, R44)
const wrappedGetArticles = withSpan(
tracer,
{ name: "blog.getArticles", op: "use-case" },
withCapture(
logger,
{ feature: "blog", layer: "use-case", name: "blog.getArticles" },
getArticlesUseCase(repo),
),
);
const wrappedGetArticleBySlug = withSpan(
tracer,
{ name: "blog.getArticleBySlug", op: "use-case" },
withCapture(
logger,
{ feature: "blog", layer: "use-case", name: "blog.getArticleBySlug" },
getArticleBySlugUseCase(repo),
),
);
const wrappedCreateArticle = withSpan(
tracer,
{ name: "blog.createArticle", op: "use-case" },
withCapture(
logger,
{ feature: "blog", layer: "use-case", name: "blog.createArticle" },
createArticleUseCase(repo),
),
);
if (blogContainer.isBound(BLOG_SYMBOLS.IGetArticlesUseCase)) {
blogContainer.unbind(BLOG_SYMBOLS.IGetArticlesUseCase);
}
if (blogContainer.isBound(BLOG_SYMBOLS.IGetArticleBySlugUseCase)) {
blogContainer.unbind(BLOG_SYMBOLS.IGetArticleBySlugUseCase);
}
if (blogContainer.isBound(BLOG_SYMBOLS.ICreateArticleUseCase)) {
blogContainer.unbind(BLOG_SYMBOLS.ICreateArticleUseCase);
}
blogContainer.bind(BLOG_SYMBOLS.IGetArticlesUseCase).toConstantValue(wrappedGetArticles);
blogContainer
.bind(BLOG_SYMBOLS.IGetArticleBySlugUseCase)
.toConstantValue(wrappedGetArticleBySlug);
blogContainer.bind(BLOG_SYMBOLS.ICreateArticleUseCase).toConstantValue(wrappedCreateArticle);
// Controllers — wrapped with span at bind time
if (blogContainer.isBound(BLOG_SYMBOLS.IGetArticlesController)) {
blogContainer.unbind(BLOG_SYMBOLS.IGetArticlesController);
}
if (blogContainer.isBound(BLOG_SYMBOLS.IGetArticleBySlugController)) {
blogContainer.unbind(BLOG_SYMBOLS.IGetArticleBySlugController);
}
if (blogContainer.isBound(BLOG_SYMBOLS.ICreateArticleController)) {
blogContainer.unbind(BLOG_SYMBOLS.ICreateArticleController);
}
blogContainer
.bind(BLOG_SYMBOLS.IGetArticlesController)
.toConstantValue(
withSpan(
tracer,
{ name: "blog.getArticles", op: "controller" },
withCapture(
logger,
{ feature: "blog", layer: "controller", name: "blog.getArticles" },
getArticlesController(wrappedGetArticles),
),
),
);
blogContainer
.bind(BLOG_SYMBOLS.IGetArticleBySlugController)
.toConstantValue(
withSpan(
tracer,
{ name: "blog.getArticleBySlug", op: "controller" },
withCapture(
logger,
{ feature: "blog", layer: "controller", name: "blog.getArticleBySlug" },
getArticleBySlugController(wrappedGetArticleBySlug),
),
),
);
blogContainer
.bind(BLOG_SYMBOLS.ICreateArticleController)
.toConstantValue(
withSpan(
tracer,
{ name: "blog.createArticle", op: "controller" },
withCapture(
logger,
{ feature: "blog", layer: "controller", name: "blog.createArticle" },
createArticleController(wrappedCreateArticle),
),
),
);
// bus + queue are accept-and-forward in Phase 6; consumed by Phase 7 generator
// output at the <gen:event-handlers> / <gen:jobs> anchors below.
void bus;
void queue;
void realtime;
void realtimeRegistry;
// <gen:event-handlers>
// <gen:jobs>
// <gen:realtime-handlers>
}