Also folds in the spec correction noted in the plan's known follow-up
\#1: subscribe takes consumerFeature: string as a second arg between
descriptor and handler. § 3.3 and § 5.4 updated.
End-to-end proof-of-life. bindAllDevSeed wires InMemoryEventBus +
InMemoryJobQueue across all features. signUpController publishes
auth.user.signed-up; marketing-pages' handler enqueues
marketing-pages.send-welcome-email; the in-memory queue dispatches
the wrapped job which records on RecordingMailerService.
Adds ./di/container, ./di/symbols, ./services/mailer, and
./services/recording-mailer to auth + marketing-pages exports so
the e2e test can resolve from the per-feature containers without
deep-importing.
sendWelcomeEmailJob takes IMailerService, validates the typed input
(userId + email), and delegates to mailer.sendWelcome. The
onAuthUserSignedUpHandler now takes IJobQueue and enqueues
"marketing-pages.send-welcome-email" with the event payload.
Both binders bind a RecordingMailerService at the IMailerService
symbol (production placeholder until a real adapter ships) and pass
mailer / queue into the wrapped factories. Dev-seed additionally
queue.register()s the slug so the in-memory queue dispatches via
the wrapped job; production relies on the generated Payload event-task
to resolve the wrapped handler from the container.
Generated handler + Payload event-task via gen event consume,
threaded through symbols / both binders / cms re-export at the
configured anchors. bus.subscribe wires the in-memory delivery in
dev-seed; the __events.auth.user.signed-up.marketing-pages Payload
task closes the production-bus loop.
Also fixes two generator-level issues found during Phase 8:
- Drop publisher prompt's `when` clause so --args can supply the
4th positional argument (Plop limitation: --args cannot bypass
conditional prompts). Validate runs only in consume mode.
- Switch event-task.ts.hbs from TaskConfig<"slug-string"> to
TaskConfig<{ input: ...; output: object }> since runtime-generated
event slugs are not keys of TypedJobs['tasks'].
signUpUseCase now takes an IEventBus and publishes userSignedUpEvent
after creating the user (synthesizing email from username since auth
is username-based). Use case mocks-default in module.ts get a fresh
InMemoryEventBus per resolution; bind-production / bind-dev-seed wire
the shared bus passed by bindAll. Tests updated to inject
RecordingEventBus, including a new test that asserts publish on
success and silence on failure.
Adds `pnpm turbo gen job <feature> <slug> <void|typed>` which scaffolds
the factory + test + Payload TaskConfig, then modifies the feature's
job-symbol, job-bind, and cms job-task anchors to wire the wrapped
job into the per-feature container. Also registers a custom Handlebars
`eq` helper used by the void/typed branch in the job templates.
Adds consumeActions for the event generator: scaffolds the handler file
+ test, the Payload event-task that completes the production-bus loop,
modifies the consumer feature's symbols (// <gen:event-handler-symbols>),
both binders (// <gen:event-handlers>), and the cms re-export
(// <gen:job-tasks>). The bind block wraps the handler in span+capture,
binds it into the per-feature container, and subscribes it on the bus.
Wires `pnpm turbo gen event` with publish/consume mode prompt; publish
branch generates the contract file + test and threads it through the
feature's // <gen:events> anchor. Consume branch is a stub that throws
until Task 40 lands the handler-side templates and modify-blocks.
resolveEventsAndJobsProduction wires PayloadJobsEventBus + PayloadJobQueue
against the bootstrapped Payload instance; resolveEventsAndJobsDevSeed
wires InMemoryEventBus + InMemoryJobQueue. Each per-feature binder now
receives (bus, queue) so Phase 7 generators can subscribe handlers and
register job tasks at the <gen:event-handlers>/<gen:jobs> anchors.
Adds RecordingEventBus implementing IEventBus for use in unit tests.
Validates payloads via the descriptor schema, records all publish calls,
and delivers events to subscribed handlers synchronously in subscription order.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds RecordingJobQueue implementing IJobQueue for use in unit tests.
Records all enqueue calls with taskSlug/input/options and returns
synthetic incrementing jobIds.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Code-quality review nits: IEventBus.subscribe docstring said "debug
tag" but InMemoryEventBus actually ignores the param entirely. Also
add a comment to InMemoryEventBus.publish noting that under failFast
only the first rejection rethrows; other failures are intentionally
dropped.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Export EventDescriptor, defineEvent, IEventBus, EventHandler,
CORE_EVENTS_SYMBOLS, InMemoryEventBus, InMemoryEventBusOptions, and
PayloadJobsEventBus from src/index.ts. All typecheck, test (11 tests),
and lint checks pass. turbo boundaries: 454 files, no issues.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TDD: red (test-only), then green. PayloadJobsEventBus validates before
enqueueing, names tasks __events.<event>.<consumer> deterministically, and
enqueues one task per subscriber via Promise.all. 3 new tests (11 total).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TDD: red (test-only), then green. InMemoryEventBus validates payloads via
descriptor.schema before fanout, delivers to all handlers via Promise.allSettled,
swallows handler errors by default, and rethrows first error when failFast:true.
5 new tests (8 total passing).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TDD: red (test-only), then green. defineEvent(name, schema) returns a typed
EventDescriptor<TName, TSchema>. Also added @repo/core-testing to devDeps
(required for nodeVitestConfig's setupFiles). 3 tests passing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The existing turbo.json boundaries use tag names (not package names), and
the core-eslint boundaries config uses the packages/core-* glob. Both already
cover @repo/core-events through its turbo.json "tags": ["core"] declaration.
pnpm turbo boundaries confirms: 445 files in 18 packages, no issues found.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>