Skip to content

Commit b7bc393

Browse files
author
bgagent
committed
refactor(fanout): make SlackDispatchEvent a type alias of FanOutEvent (aws-samples#79 review aws-samples#10)
The two interfaces were structurally identical: same five fields, same readonly modifiers, same metadata shape. The decoupling was purely nominal and a silent-drift footgun — adding a field to ``FanOutEvent`` (e.g. when the router starts plumbing an ``approval_required`` ID through) would not flow into ``SlackDispatchEvent``, leaving the dispatcher unaware until a downstream test happened to fail. Replace with a one-line type alias: export type SlackDispatchEvent = FanOutEvent; The slack-notify module now type-imports ``FanOutEvent`` from fanout-task-events. ``import type`` is erased at compile time, so the runtime bundle still has the one-way dep (fanout-task-events → slack-notify) — no module-cycle hazard. Reviewer-suggested ``Pick<FanOutEvent, 'task_id' | …>`` was considered and rejected: the dispatcher uses every field of ``FanOutEvent``, so the Pick would just enumerate the same five fields with extra noise. A direct alias keeps the intent obvious and prevents drift identically.
1 parent 1a5cbe2 commit b7bc393

1 file changed

Lines changed: 11 additions & 10 deletions

File tree

cdk/src/handlers/slack-notify.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@
4646
*/
4747

4848
import { type DynamoDBDocumentClient, GetCommand, UpdateCommand } from '@aws-sdk/lib-dynamodb';
49+
// Type-only import of ``FanOutEvent`` — values flow only one way at
50+
// runtime (fanout-task-events imports + calls ``dispatchSlackEvent``),
51+
// so importing the type back creates no runtime cycle. ``import type``
52+
// is erased after compile, so the bundler sees a one-way dep.
53+
import type { FanOutEvent } from './fanout-task-events';
4954
import { logger } from './shared/logger';
5055
import { renderSlackBlocks } from './shared/slack-blocks';
5156
import { getSlackSecret, SLACK_SECRET_PREFIX } from './shared/slack-verify';
@@ -86,17 +91,13 @@ export const NOTIFIABLE_EVENTS = new Set<string>([
8691
]);
8792

8893
/**
89-
* Minimal event shape the dispatcher needs. The fan-out router passes
90-
* the parsed ``FanOutEvent`` (plus the raw ``metadata`` map), so the
91-
* dispatcher never reparses a DynamoDB stream record.
94+
* Minimal event shape the dispatcher needs. Defined as a type alias of
95+
* ``FanOutEvent`` so the contract between the router and the dispatcher
96+
* cannot silently drift if either side adds a field — TypeScript will
97+
* propagate the change automatically (PR #79 review #10). Originally a
98+
* standalone interface, but the structural duplication was a footgun.
9299
*/
93-
export interface SlackDispatchEvent {
94-
readonly task_id: string;
95-
readonly event_id: string;
96-
readonly event_type: string;
97-
readonly timestamp: string;
98-
readonly metadata?: Record<string, unknown>;
99-
}
100+
export type SlackDispatchEvent = FanOutEvent;
100101

101102
/**
102103
* Thrown when the Slack API returns a **terminal** error — one that

0 commit comments

Comments
 (0)