diff --git a/coverage/summary.json b/coverage/summary.json index fbb89e4..6444615 100644 --- a/coverage/summary.json +++ b/coverage/summary.json @@ -1,6 +1,6 @@ { - "generatedAt": "2026-05-13T18:08:34.469Z", - "commit": "57e9d98", + "generatedAt": "2026-05-13T18:36:10.133Z", + "commit": "9800fed", "repo": { "statements": 95.86, "branches": 88.91, diff --git a/turbo/generators/templates/feature/src/di/bind-dev-seed.test.ts.hbs b/turbo/generators/templates/feature/src/di/bind-dev-seed.test.ts.hbs index bf69822..a982dbd 100644 --- a/turbo/generators/templates/feature/src/di/bind-dev-seed.test.ts.hbs +++ b/turbo/generators/templates/feature/src/di/bind-dev-seed.test.ts.hbs @@ -29,7 +29,7 @@ describe("bindDevSeed{{pascalCase name}}", () => { }); it("populates the repository with the dev seed", async () => { - await bindDevSeed{{pascalCase name}}(noop.tracer, noop.logger); + await bindDevSeed{{pascalCase name}}(noop); const repo = {{camelCase name}}Container.get( {{constantCase name}}_SYMBOLS.I{{pascalCase entity}}Repository, @@ -41,12 +41,12 @@ describe("bindDevSeed{{pascalCase name}}", () => { }); it("is idempotent — calling twice rebuilds a fresh populated repo", async () => { - await bindDevSeed{{pascalCase name}}(noop.tracer, noop.logger); + await bindDevSeed{{pascalCase name}}(noop); const before = {{camelCase name}}Container.get( {{constantCase name}}_SYMBOLS.I{{pascalCase entity}}Repository, ); - await bindDevSeed{{pascalCase name}}(noop.tracer, noop.logger); + await bindDevSeed{{pascalCase name}}(noop); const after = {{camelCase name}}Container.get( {{constantCase name}}_SYMBOLS.I{{pascalCase entity}}Repository, ); diff --git a/turbo/generators/templates/feature/src/di/bind-dev-seed.ts.hbs b/turbo/generators/templates/feature/src/di/bind-dev-seed.ts.hbs index 5960f49..142c201 100644 --- a/turbo/generators/templates/feature/src/di/bind-dev-seed.ts.hbs +++ b/turbo/generators/templates/feature/src/di/bind-dev-seed.ts.hbs @@ -6,6 +6,11 @@ import { type ILogger, } from "@repo/core-shared/instrumentation"; import type { BindContext } from "@repo/core-shared/di"; +import { + assertFeatureConformance, + wireUseCase, +} from "@repo/core-shared/conformance"; +import { {{camelCase name}}Manifest } from "../feature.manifest.js"; import { {{camelCase name}}Container } from "./container.js"; import { {{constantCase name}}_SYMBOLS } from "./symbols.js"; import { Mock{{pascalCase entity}}Repository } from "../infrastructure/repositories/{{kebabCase entity}}.repository.mock.js"; @@ -26,7 +31,6 @@ import type { I{{pascalCase entity}}Repository } from "../application/repositori */ export async function bindDevSeed{{pascalCase name}}(ctx: BindContext): Promise { const { tracer, logger, bus, queue, realtime, realtimeRegistry } = ctx; - void bus; void queue; void realtime; void realtimeRegistry; // Bind shared instrumentation into feature container if ({{camelCase name}}Container.isBound(INSTRUMENTATION_SYMBOLS.TRACER)) { @@ -46,27 +50,22 @@ export async function bindDevSeed{{pascalCase name}}(ctx: BindContext): Promise< .bind({{constantCase name}}_SYMBOLS.I{{pascalCase entity}}Repository) .toConstantValue(repo); - // Wrap use case + controller identically to bind-production - const wrappedGet{{pascalCase entity}} = withSpan( + // Use case + const wrappedGet{{pascalCase entity}} = wireUseCase({ + container: {{camelCase name}}Container, + symbol: {{constantCase name}}_SYMBOLS.IGet{{pascalCase entity}}UseCase, + factory: get{{pascalCase entity}}UseCase, + deps: [repo], + feature: "{{kebabCase name}}", + layer: "use-case", + name: "get{{pascalCase entity}}", tracer, - { name: "{{camelCase name}}.get{{pascalCase entity}}", op: "use-case" }, - withCapture( - logger, - { feature: "{{kebabCase name}}", layer: "use-case", name: "{{camelCase name}}.get{{pascalCase entity}}" }, - get{{pascalCase entity}}UseCase(repo), - ), - ); + logger, + }); - for (const sym of [ - {{constantCase name}}_SYMBOLS.IGet{{pascalCase entity}}UseCase, - {{constantCase name}}_SYMBOLS.IGet{{pascalCase entity}}Controller, - ]) { - if ({{camelCase name}}Container.isBound(sym)) {{camelCase name}}Container.unbind(sym); + if ({{camelCase name}}Container.isBound({{constantCase name}}_SYMBOLS.IGet{{pascalCase entity}}Controller)) { + {{camelCase name}}Container.unbind({{constantCase name}}_SYMBOLS.IGet{{pascalCase entity}}Controller); } - {{camelCase name}}Container - .bind({{constantCase name}}_SYMBOLS.IGet{{pascalCase entity}}UseCase) - .toConstantValue(wrappedGet{{pascalCase entity}}); - {{camelCase name}}Container .bind({{constantCase name}}_SYMBOLS.IGet{{pascalCase entity}}Controller) .toConstantValue( @@ -80,7 +79,22 @@ export async function bindDevSeed{{pascalCase name}}(ctx: BindContext): Promise< ), ), ); + // bus + queue are passed through; generated handlers consume them at the anchors below. + void bus; + void queue; + void realtime; + void realtimeRegistry; // // // + + // Boot-time conformance check (dev-seed mode). + assertFeatureConformance( + {{camelCase name}}Container, + {{camelCase name}}Manifest, + { + get{{pascalCase entity}}: {{constantCase name}}_SYMBOLS.IGet{{pascalCase entity}}UseCase, + }, + ctx, + ); } diff --git a/turbo/generators/templates/feature/src/di/bind-production.ts.hbs b/turbo/generators/templates/feature/src/di/bind-production.ts.hbs index 6832e06..7ee3eeb 100644 --- a/turbo/generators/templates/feature/src/di/bind-production.ts.hbs +++ b/turbo/generators/templates/feature/src/di/bind-production.ts.hbs @@ -6,17 +6,19 @@ import { type ILogger, } from "@repo/core-shared/instrumentation"; import type { BindProductionContext } from "@repo/core-shared/di"; +import { + assertFeatureConformance, + wireUseCase, +} from "@repo/core-shared/conformance"; import { {{camelCase name}}Container } from "./container"; import { {{constantCase name}}_SYMBOLS } from "./symbols"; +import { {{camelCase name}}Manifest } from "../feature.manifest"; import { {{pascalCase entity}}Repository } from "../infrastructure/repositories/{{kebabCase entity}}.repository"; import { get{{pascalCase entity}}UseCase } from "../application/use-cases/get-{{kebabCase entity}}.use-case"; import { get{{pascalCase entity}}Controller } from "../interface-adapters/controllers/get-{{kebabCase entity}}.controller"; -import { assertFeatureConformance } from "@repo/core-shared/conformance"; -import { {{camelCase name}}Manifest } from "../feature.manifest"; export function bindProduction{{pascalCase name}}(ctx: BindProductionContext): void { const { config, tracer, logger, bus, queue, realtime, realtimeRegistry } = ctx; - void bus; void queue; void realtime; void realtimeRegistry; // Bind shared instrumentation into feature container if ({{camelCase name}}Container.isBound(INSTRUMENTATION_SYMBOLS.TRACER)) { @@ -37,23 +39,18 @@ export function bindProduction{{pascalCase name}}(ctx: BindProductionContext): v .bind({{constantCase name}}_SYMBOLS.I{{pascalCase entity}}Repository) .toConstantValue(repo); - // Use case — wrapped with span + capture at bind time - const wrappedGet{{pascalCase entity}} = withSpan( + // Use case + const wrappedGet{{pascalCase entity}} = wireUseCase({ + container: {{camelCase name}}Container, + symbol: {{constantCase name}}_SYMBOLS.IGet{{pascalCase entity}}UseCase, + factory: get{{pascalCase entity}}UseCase, + deps: [repo], + feature: "{{kebabCase name}}", + layer: "use-case", + name: "get{{pascalCase entity}}", tracer, - { name: "{{camelCase name}}.get{{pascalCase entity}}", op: "use-case" }, - withCapture( - logger, - { feature: "{{kebabCase name}}", layer: "use-case", name: "{{camelCase name}}.get{{pascalCase entity}}" }, - get{{pascalCase entity}}UseCase(repo), - ), - ); - - if ({{camelCase name}}Container.isBound({{constantCase name}}_SYMBOLS.IGet{{pascalCase entity}}UseCase)) { - {{camelCase name}}Container.unbind({{constantCase name}}_SYMBOLS.IGet{{pascalCase entity}}UseCase); - } - {{camelCase name}}Container - .bind({{constantCase name}}_SYMBOLS.IGet{{pascalCase entity}}UseCase) - .toConstantValue(wrappedGet{{pascalCase entity}}); + logger, + }); // Controller — wrapped with span at bind time if ({{camelCase name}}Container.isBound({{constantCase name}}_SYMBOLS.IGet{{pascalCase entity}}Controller)) { @@ -72,6 +69,11 @@ export function bindProduction{{pascalCase name}}(ctx: BindProductionContext): v ), ), ); + // bus + queue are passed through; generated handlers consume them at the anchors below. + void bus; + void queue; + void realtime; + void realtimeRegistry; // // //