feat(09-03): add RouteToUser types and resolver registry
- Add RouteToUser, ResolvedRecipient, NotifyResolver, UserRouteFallback, UserRouteFallbackReason types to lib/types/pipeline.ts (ROUTE-01) - Create lib/services/pipeline-steps/notify-resolvers.ts with three v1 resolvers: direct_email, pulse_user_id, autotask_resource_email (ROUTE-02) - Resolver registry as Map<string, NotifyResolver> with registerResolver() and resolveRecipient() dispatcher with try/catch error handling
This commit is contained in:
parent
485053c639
commit
d27462f713
2 changed files with 155 additions and 0 deletions
|
|
@ -192,3 +192,55 @@ export interface UserEventSubscription {
|
|||
enabled: boolean;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Phase 9 — notify step per-user routing (ROUTE-01..06)
|
||||
// ============================================================================
|
||||
|
||||
/** Resolver name; resolvers live in lib/services/pipeline-steps/notify-resolvers.ts. */
|
||||
export type ResolverName = 'autotask_resource_email' | 'direct_email' | 'pulse_user_id' | string;
|
||||
|
||||
/** Optional block on a `notify` step's config. When present, the step attempts
|
||||
* delivery via the resolved Pulse user's personal channel before falling back
|
||||
* to the step's `channel_id`.
|
||||
*
|
||||
* v1 limitation: `field` is a single-level key; dotted paths like 'company.id'
|
||||
* are NOT walked. Admins must surface needed values at top level of the source
|
||||
* object (e.g., via an upstream transform step). */
|
||||
export interface RouteToUser {
|
||||
/** PipelineContext key whose value holds the entity (e.g. 'ticket'). */
|
||||
source: string;
|
||||
/** Single-level field name within context[source] (e.g. 'assignedResourceID').
|
||||
* v1 only: single-level lookup — dotted paths like 'company.id' are NOT walked. */
|
||||
field: string;
|
||||
/** Resolver name. Looks up the user from the field value. */
|
||||
resolve: ResolverName;
|
||||
/** Event key checked against user_event_subscriptions for muting (D-12). */
|
||||
event_key: string;
|
||||
/** Optional preferred channel type (D-10). When omitted: ntfy then teams then fallback. */
|
||||
channel_type?: 'teams' | 'ntfy';
|
||||
}
|
||||
|
||||
/** Output of a resolver. null = no recipient (notify.ts falls through to global). */
|
||||
export type ResolvedRecipient =
|
||||
| { user_id: string }
|
||||
| { email: string }
|
||||
| null;
|
||||
|
||||
/** A resolver fn. Pure async; reads from postgres if it needs to. */
|
||||
export type NotifyResolver = (fieldValue: unknown) => Promise<ResolvedRecipient>;
|
||||
|
||||
/** Reasons recorded in execution_step.output_data when fallback occurs (D-11). */
|
||||
export type UserRouteFallbackReason =
|
||||
| 'no_channel'
|
||||
| 'send_failed'
|
||||
| 'user_not_found'
|
||||
| 'no_field_value'
|
||||
| 'resolver_unknown';
|
||||
|
||||
export interface UserRouteFallback {
|
||||
reason: UserRouteFallbackReason;
|
||||
user_id?: string;
|
||||
channel_type: string;
|
||||
error?: string;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue