- Type socket.data.user via AppSocketData/AppSocket generics (no more any)
- Wrap Gate 1 authenticator call in try/catch so exceptions reject the
connection with connect_error instead of being swallowed
- Fix Gate 3 userScoped channel authorize: derive params.userId from the
authenticated socket user so owner-inbound is accepted
- Await io.close(callback) in stop() to ensure full shutdown
- Remove unused httpServer field from constructor (io already holds the ref)
- Extract CHANNEL_ROOM_PREFIX/channelRoom helper to channel-room.ts;
replace three `ch:${name}` magic strings; re-export from index
- Add JSDoc to ChannelScope explaining userScoped params/template convention
- Fix "allows subscribe + invokes handler with ctx" test: hoist received
outside beforeEach and assert ctx shape
- New test: rejects connection when authenticator throws
- New test: userScoped channel accepts inbound from owner, rejects from anon
Six per-package AGENTS.md tables and the di-explainer wiring trace all
showed pre-ADR-014 binder shapes. Refreshed to the post-ADR-015
reality:
- Per-package "Public exports" tables now show the
(config, tracer, logger, bus, queue) production signature and the
(tracer, logger, bus, queue) dev-seed companion. auth and
marketing-pages also list their newly-public ./di/container,
./di/symbols, and (marketing-pages only) ./services/mailer +
./services/recording-mailer subpaths.
- di-explainer's wiring trace adds the resolveEventsAndJobs* step in
bindAll(), the (config, tracer, logger, bus, queue) binder
signature, and the // <gen:event-handlers> / // <gen:jobs>
injection sites.
No code change; pre-existing AGENTS.md staleness predates ADR-014 +
ADR-015 — this commit catches both up.
Three issues uncovered by the full pnpm typecheck/test/boundaries pass
and resolved here:
- core-testing was importing IEventBus / IJobQueue from core-events /
core-shared, creating two boundary violations (tooling → core) and a
build-graph cycle. Inlined the type aliases (mirroring how
RecordingTracer / RecordingLogger handle ITracer / ILogger).
recording-event-bus.test.ts replaces defineEvent() with an inline
descriptor literal so no runtime import is needed either. core-events
and core-shared are removed from core-testing dependencies.
- turbo.json: typecheck and test no longer dependsOn ^typecheck / ^build.
Each package's tsc / vitest resolves cross-package types via
node_modules independently, and dropping the topological dep avoids the
spurious cycle warning that appeared once core-testing started
importing core-events / core-shared.
- turbo.json: feature.dependencies.allow gains "feature". Cross-feature
event flow (ADR-015) requires a consumer feature to import the
publisher's event contract directly. The dangerous form (importing
the publisher's handler/use-case/repo) is still blocked by E1's
no-handler-reexport ESLint rule and the missing public exports.
- TaskConfig<"slug-string"> → TaskConfig<{ input; output }> in the gen
job task template (and the shipped send-welcome-email.task.ts) since
runtime-generated slugs aren't keys of TypedJobs['tasks'].
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 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>