diff --git a/packages/core-testing/package.json b/packages/core-testing/package.json index 25a76b7..c41b55d 100644 --- a/packages/core-testing/package.json +++ b/packages/core-testing/package.json @@ -21,8 +21,6 @@ "test": "vitest run" }, "dependencies": { - "@repo/core-events": "workspace:*", - "@repo/core-shared": "workspace:*", "@testing-library/jest-dom": "^6.5.0", "zod": "^3.23.0", "@testing-library/react": "^16.0.0", diff --git a/packages/core-testing/src/instrumentation/recording-event-bus.test.ts b/packages/core-testing/src/instrumentation/recording-event-bus.test.ts index 2325032..c330822 100644 --- a/packages/core-testing/src/instrumentation/recording-event-bus.test.ts +++ b/packages/core-testing/src/instrumentation/recording-event-bus.test.ts @@ -1,9 +1,13 @@ import { describe, it, expect } from "vitest"; import { z } from "zod"; -import { defineEvent } from "@repo/core-events"; import { RecordingEventBus } from "@/instrumentation/recording-event-bus"; -const evt = defineEvent("test.evt", z.object({ id: z.string() }).strict()); +// Inline a descriptor literal so the test doesn't need to import from +// @repo/core-events (boundary-rule isolation, mirrors recording-tracer test). +const evt = { + name: "test.evt" as const, + schema: z.object({ id: z.string() }).strict(), +}; describe("RecordingEventBus", () => { it("records every publish call after schema validation", async () => { diff --git a/packages/core-testing/src/instrumentation/recording-event-bus.ts b/packages/core-testing/src/instrumentation/recording-event-bus.ts index c4ab87f..2bcde70 100644 --- a/packages/core-testing/src/instrumentation/recording-event-bus.ts +++ b/packages/core-testing/src/instrumentation/recording-event-bus.ts @@ -1,5 +1,26 @@ +// Local type aliases matching the contracts in @repo/core-events. +// Kept inline to avoid a build-graph cycle between core-testing and core-events +// (mirrors the recording-tracer / recording-logger pattern). import type { z } from "zod"; -import type { EventDescriptor, EventHandler, IEventBus } from "@repo/core-events"; + +type EventDescriptor = { + readonly name: TName; + readonly schema: TSchema; +}; + +type EventHandler = (event: T) => Promise; + +interface IEventBus { + publish( + descriptor: EventDescriptor>, + payload: T, + ): Promise; + subscribe( + descriptor: EventDescriptor>, + consumerFeature: string, + handler: EventHandler, + ): void; +} export class RecordingEventBus implements IEventBus { readonly published: { name: string; payload: unknown }[] = []; diff --git a/packages/core-testing/src/instrumentation/recording-job-queue.ts b/packages/core-testing/src/instrumentation/recording-job-queue.ts index 6a59a23..4703de5 100644 --- a/packages/core-testing/src/instrumentation/recording-job-queue.ts +++ b/packages/core-testing/src/instrumentation/recording-job-queue.ts @@ -1,4 +1,13 @@ -import type { IJobQueue } from "@repo/core-shared/jobs"; +// Local type alias matching the contract in @repo/core-shared/jobs. +// Kept inline to avoid a build-graph cycle between core-testing and core-shared +// (mirrors the recording-tracer / recording-logger pattern). +interface IJobQueue { + enqueue( + taskSlug: string, + input: T, + options?: { runAt?: Date }, + ): Promise<{ jobId: string }>; +} export class RecordingJobQueue implements IJobQueue { readonly enqueued: { taskSlug: string; input: unknown; options?: { runAt?: Date } }[] = []; diff --git a/packages/marketing-pages/src/integrations/cms/jobs/send-welcome-email.task.ts b/packages/marketing-pages/src/integrations/cms/jobs/send-welcome-email.task.ts index bba405d..f583915 100644 --- a/packages/marketing-pages/src/integrations/cms/jobs/send-welcome-email.task.ts +++ b/packages/marketing-pages/src/integrations/cms/jobs/send-welcome-email.task.ts @@ -3,8 +3,12 @@ import type { TaskConfig } from "payload"; import { marketingPagesContainer } from "../../../di/container"; import { MARKETING_PAGES_SYMBOLS } from "../../../di/symbols"; import type { ISendWelcomeEmailJob } from "../../../jobs/send-welcome-email.job"; +import type { SendWelcomeEmailInput } from "../../../jobs/send-welcome-email.job"; -export const sendWelcomeEmailTask: TaskConfig<"marketing-pages.send-welcome-email"> = { +export const sendWelcomeEmailTask: TaskConfig<{ + input: SendWelcomeEmailInput; + output: object; +}> = { slug: "marketing-pages.send-welcome-email", inputSchema: [], retries: { attempts: 3, backoff: { type: "exponential", delay: 1000 } }, @@ -12,7 +16,7 @@ export const sendWelcomeEmailTask: TaskConfig<"marketing-pages.send-welcome-emai const job = marketingPagesContainer.get( MARKETING_PAGES_SYMBOLS.ISendWelcomeEmailJob, ); - await job(input as never); + await job(input); return { output: {} }; }, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4df1f24..0e1d031 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -604,12 +604,6 @@ importers: packages/core-testing: dependencies: - '@repo/core-events': - specifier: workspace:* - version: link:../core-events - '@repo/core-shared': - specifier: workspace:* - version: link:../core-shared '@tanstack/react-query': specifier: ^5.59.0 version: 5.96.2(react@19.2.4) diff --git a/turbo.json b/turbo.json index bd39ab3..f210ad6 100644 --- a/turbo.json +++ b/turbo.json @@ -32,7 +32,7 @@ }, "feature": { "dependencies": { - "allow": ["core", "tooling"] + "allow": ["core", "feature", "tooling"] } }, "core": { @@ -65,14 +65,14 @@ "dependsOn": ["^lint"] }, "test": { - "dependsOn": ["^build"] + "dependsOn": [] }, "test:e2e": { "dependsOn": ["^build"], "cache": false }, "typecheck": { - "dependsOn": ["^typecheck"] + "dependsOn": [] }, "build-storybook": { "outputs": ["storybook-static/**"] diff --git a/turbo/generators/templates/job/task.ts.hbs b/turbo/generators/templates/job/task.ts.hbs index b204e61..32a530d 100644 --- a/turbo/generators/templates/job/task.ts.hbs +++ b/turbo/generators/templates/job/task.ts.hbs @@ -2,9 +2,15 @@ import type { TaskConfig } from "payload"; import { {{camelCase feature}}Container } from "../../../di/container"; import { {{constantCase feature}}_SYMBOLS } from "../../../di/symbols"; -import type { I{{pascalCase job}}Job } from "../../../jobs/{{kebabCase job}}.job"; +import type { + I{{pascalCase job}}Job, + {{pascalCase job}}Input, +} from "../../../jobs/{{kebabCase job}}.job"; -export const {{camelCase job}}Task: TaskConfig<"{{kebabCase feature}}.{{kebabCase job}}"> = { +export const {{camelCase job}}Task: TaskConfig<{ + input: {{pascalCase job}}Input; + output: object; +}> = { slug: "{{kebabCase feature}}.{{kebabCase job}}", inputSchema: [], retries: { attempts: 3, backoff: { type: "exponential", delay: 1000 } }, @@ -12,7 +18,7 @@ export const {{camelCase job}}Task: TaskConfig<"{{kebabCase feature}}.{{kebabCas const job = {{camelCase feature}}Container.get( {{constantCase feature}}_SYMBOLS.I{{pascalCase job}}Job, ); - await job(input as never); + await job(input); return { output: {} }; }, };