refactor(blog): migrate binders to wireUseCase for all 3 use cases

Replace inline withSpan + withCapture blocks for getArticles,
getArticleBySlug, and createArticle in both bind-production and
bind-dev-seed with wireUseCase calls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-13 17:55:43 +00:00
parent 7406171b0b
commit 43d88be4bd
2 changed files with 98 additions and 115 deletions

View File

@@ -6,7 +6,10 @@ import {
type ILogger, type ILogger,
} from "@repo/core-shared/instrumentation"; } from "@repo/core-shared/instrumentation";
import type { BindContext } from "@repo/core-shared/di"; import type { BindContext } from "@repo/core-shared/di";
import { assertFeatureConformance } from "@repo/core-shared/conformance"; import {
assertFeatureConformance,
wireUseCase,
} from "@repo/core-shared/conformance";
import { blogManifest } from "../feature.manifest.js"; import { blogManifest } from "../feature.manifest.js";
import { blogContainer } from "./container.js"; import { blogContainer } from "./container.js";
import { BLOG_SYMBOLS } from "./symbols.js"; import { BLOG_SYMBOLS } from "./symbols.js";
@@ -58,54 +61,48 @@ export async function bindDevSeedBlog(ctx: BindContext): Promise<void> {
.bind<IArticlesRepository>(BLOG_SYMBOLS.IArticlesRepository) .bind<IArticlesRepository>(BLOG_SYMBOLS.IArticlesRepository)
.toConstantValue(repo); .toConstantValue(repo);
// Wrap use cases + controllers identically to bind-production // Use cases
const wrappedGetArticles = withSpan( const wrappedGetArticles = wireUseCase({
container: blogContainer,
symbol: BLOG_SYMBOLS.IGetArticlesUseCase,
factory: getArticlesUseCase,
deps: [repo],
feature: "blog",
layer: "use-case",
name: "getArticles",
tracer, tracer,
{ name: "blog.getArticles", op: "use-case" }, logger,
withCapture( });
logger, const wrappedGetArticleBySlug = wireUseCase({
{ feature: "blog", layer: "use-case", name: "blog.getArticles" }, container: blogContainer,
getArticlesUseCase(repo), symbol: BLOG_SYMBOLS.IGetArticleBySlugUseCase,
), factory: getArticleBySlugUseCase,
); deps: [repo],
const wrappedGetArticleBySlug = withSpan( feature: "blog",
layer: "use-case",
name: "getArticleBySlug",
tracer, tracer,
{ name: "blog.getArticleBySlug", op: "use-case" }, logger,
withCapture( });
logger, const wrappedCreateArticle = wireUseCase({
{ feature: "blog", layer: "use-case", name: "blog.getArticleBySlug" }, container: blogContainer,
getArticleBySlugUseCase(repo), symbol: BLOG_SYMBOLS.ICreateArticleUseCase,
), factory: createArticleUseCase,
); deps: [repo],
const wrappedCreateArticle = withSpan( feature: "blog",
layer: "use-case",
name: "createArticle",
tracer, tracer,
{ name: "blog.createArticle", op: "use-case" }, logger,
withCapture( });
logger,
{ feature: "blog", layer: "use-case", name: "blog.createArticle" },
createArticleUseCase(repo),
),
);
for (const sym of [ for (const sym of [
BLOG_SYMBOLS.IGetArticlesUseCase,
BLOG_SYMBOLS.IGetArticleBySlugUseCase,
BLOG_SYMBOLS.ICreateArticleUseCase,
BLOG_SYMBOLS.IGetArticlesController, BLOG_SYMBOLS.IGetArticlesController,
BLOG_SYMBOLS.IGetArticleBySlugController, BLOG_SYMBOLS.IGetArticleBySlugController,
BLOG_SYMBOLS.ICreateArticleController, BLOG_SYMBOLS.ICreateArticleController,
]) { ]) {
if (blogContainer.isBound(sym)) blogContainer.unbind(sym); if (blogContainer.isBound(sym)) blogContainer.unbind(sym);
} }
blogContainer
.bind(BLOG_SYMBOLS.IGetArticlesUseCase)
.toConstantValue(wrappedGetArticles);
blogContainer
.bind(BLOG_SYMBOLS.IGetArticleBySlugUseCase)
.toConstantValue(wrappedGetArticleBySlug);
blogContainer
.bind(BLOG_SYMBOLS.ICreateArticleUseCase)
.toConstantValue(wrappedCreateArticle);
blogContainer blogContainer
.bind(BLOG_SYMBOLS.IGetArticlesController) .bind(BLOG_SYMBOLS.IGetArticlesController)
@@ -120,23 +117,21 @@ export async function bindDevSeedBlog(ctx: BindContext): Promise<void> {
), ),
), ),
); );
blogContainer blogContainer.bind(BLOG_SYMBOLS.IGetArticleBySlugController).toConstantValue(
.bind(BLOG_SYMBOLS.IGetArticleBySlugController) withSpan(
.toConstantValue( tracer,
withSpan( { name: "blog.getArticleBySlug", op: "controller" },
tracer, withCapture(
{ name: "blog.getArticleBySlug", op: "controller" }, logger,
withCapture( {
logger, feature: "blog",
{ layer: "controller",
feature: "blog", name: "blog.getArticleBySlug",
layer: "controller", },
name: "blog.getArticleBySlug", getArticleBySlugController(wrappedGetArticleBySlug),
},
getArticleBySlugController(wrappedGetArticleBySlug),
),
), ),
); ),
);
blogContainer blogContainer
.bind(BLOG_SYMBOLS.ICreateArticleController) .bind(BLOG_SYMBOLS.ICreateArticleController)
.toConstantValue( .toConstantValue(

View File

@@ -6,7 +6,10 @@ import {
type ILogger, type ILogger,
} from "@repo/core-shared/instrumentation"; } from "@repo/core-shared/instrumentation";
import type { BindProductionContext } from "@repo/core-shared/di"; import type { BindProductionContext } from "@repo/core-shared/di";
import { assertFeatureConformance } from "@repo/core-shared/conformance"; import {
assertFeatureConformance,
wireUseCase,
} from "@repo/core-shared/conformance";
import { blogContainer } from "./container"; import { blogContainer } from "./container";
import { BLOG_SYMBOLS } from "./symbols"; import { BLOG_SYMBOLS } from "./symbols";
import { blogManifest } from "../feature.manifest"; import { blogManifest } from "../feature.manifest";
@@ -43,53 +46,40 @@ export function bindProductionBlog(ctx: BindProductionContext): void {
const repo = new ArticlesRepository(config, tracer, logger); const repo = new ArticlesRepository(config, tracer, logger);
blogContainer.bind(BLOG_SYMBOLS.IArticlesRepository).toConstantValue(repo); blogContainer.bind(BLOG_SYMBOLS.IArticlesRepository).toConstantValue(repo);
// Use cases — wrapped with span + capture at bind time // Use cases
const wrappedGetArticles = withSpan( const wrappedGetArticles = wireUseCase({
container: blogContainer,
symbol: BLOG_SYMBOLS.IGetArticlesUseCase,
factory: getArticlesUseCase,
deps: [repo],
feature: "blog",
layer: "use-case",
name: "getArticles",
tracer, tracer,
{ name: "blog.getArticles", op: "use-case" }, logger,
withCapture( });
logger, const wrappedGetArticleBySlug = wireUseCase({
{ feature: "blog", layer: "use-case", name: "blog.getArticles" }, container: blogContainer,
getArticlesUseCase(repo), symbol: BLOG_SYMBOLS.IGetArticleBySlugUseCase,
), factory: getArticleBySlugUseCase,
); deps: [repo],
const wrappedGetArticleBySlug = withSpan( feature: "blog",
layer: "use-case",
name: "getArticleBySlug",
tracer, tracer,
{ name: "blog.getArticleBySlug", op: "use-case" }, logger,
withCapture( });
logger, const wrappedCreateArticle = wireUseCase({
{ feature: "blog", layer: "use-case", name: "blog.getArticleBySlug" }, container: blogContainer,
getArticleBySlugUseCase(repo), symbol: BLOG_SYMBOLS.ICreateArticleUseCase,
), factory: createArticleUseCase,
); deps: [repo],
const wrappedCreateArticle = withSpan( feature: "blog",
layer: "use-case",
name: "createArticle",
tracer, tracer,
{ name: "blog.createArticle", op: "use-case" }, logger,
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 // Controllers — wrapped with span at bind time
if (blogContainer.isBound(BLOG_SYMBOLS.IGetArticlesController)) { if (blogContainer.isBound(BLOG_SYMBOLS.IGetArticlesController)) {
@@ -114,23 +104,21 @@ export function bindProductionBlog(ctx: BindProductionContext): void {
), ),
), ),
); );
blogContainer blogContainer.bind(BLOG_SYMBOLS.IGetArticleBySlugController).toConstantValue(
.bind(BLOG_SYMBOLS.IGetArticleBySlugController) withSpan(
.toConstantValue( tracer,
withSpan( { name: "blog.getArticleBySlug", op: "controller" },
tracer, withCapture(
{ name: "blog.getArticleBySlug", op: "controller" }, logger,
withCapture( {
logger, feature: "blog",
{ layer: "controller",
feature: "blog", name: "blog.getArticleBySlug",
layer: "controller", },
name: "blog.getArticleBySlug", getArticleBySlugController(wrappedGetArticleBySlug),
},
getArticleBySlugController(wrappedGetArticleBySlug),
),
), ),
); ),
);
blogContainer blogContainer
.bind(BLOG_SYMBOLS.ICreateArticleController) .bind(BLOG_SYMBOLS.ICreateArticleController)
.toConstantValue( .toConstantValue(