EdgeInteract
Pre-Send Hook
The pre-send hook (OnBeforePublish) runs after the request is constructed and validated but before it is delivered to the client via EdgeStream. It can inspect, enrich, modify, or block the interaction.
What the Pre-Send Hook Can Do
- Inspect: Read the request without modifying it — for logging, tracing, metrics
- Enrich: Add metadata fields, attach correlation IDs, populate dynamic payload fields
- Modify target: Change the
targetUserId— e.g., redirect to an out-of-office substitute - Block: Throw
InteractionBlockedExceptionto prevent the interaction from being sent at all - Rate limit: Check the current rate for the target user and block if exceeded (the built-in
RateLimitInteractionHookdoes this)
Blocking an Interaction
public class OutOfOfficeRedirectHook : IInteractionHook
{
private readonly IUserPresenceService _presence;
public OutOfOfficeRedirectHook(IUserPresenceService presence)
{
_presence = presence;
}
public async Task OnBeforePublish(
InteractionRequest request,
CancellationToken ct)
{
var userStatus = await _presence.GetStatusAsync(request.TargetUserId, ct);
if (userStatus == UserStatus.OutOfOffice)
{
var substitute = await _presence.GetSubstituteAsync(request.TargetUserId, ct);
if (substitute is null)
{
// No substitute — block the interaction
throw new InteractionBlockedException(
$"User {request.TargetUserId} is out of office and has no substitute.");
}
// Redirect to substitute
request = request with { TargetUserId = substitute.UserId };
}
}
public Task OnAfterRespond(
InteractionRequest request,
InteractionResponse response,
CancellationToken ct) => Task.CompletedTask;
}
Enriching the Request
public class TraceEnrichmentHook : IInteractionHook
{
private readonly ITraceContext _trace;
public async Task OnBeforePublish(
InteractionRequest request,
CancellationToken ct)
{
// Add OpenTelemetry trace context to metadata
request.Metadata["traceparent"] = _trace.CurrentTraceParent;
request.Metadata["tracestate"] = _trace.CurrentTraceState;
request.Metadata["publishedBy"] = _trace.CurrentService;
await Task.CompletedTask;
}
public Task OnAfterRespond(
InteractionRequest request,
InteractionResponse response,
CancellationToken ct) => Task.CompletedTask;
}
InteractionBlockedException
| Property | Type | Description |
|---|---|---|
Message | string | Human-readable reason for blocking |
BlockedBy | string | Name of the hook that blocked (auto-populated) |
InteractionId | string | The interaction that was blocked |
When InteractionBlockedException is thrown, PublishAndWaitAsync() re-throws it to the caller. The interaction is recorded in the audit log as status: "blocked".
Modifying the Request Object
The
InteractionRequest passed to OnBeforePublish is mutable during the hook chain. Modifications made in one hook are visible to subsequent hooks and to the delivery stage. Be careful about ordering when multiple hooks modify the same field.
Pre-Send Hook Use Cases
| Use Case | Implementation |
|---|---|
| Out-of-office redirect | Check user presence; change TargetUserId to substitute |
| Rate limiting | Count interactions per user per minute; throw if exceeded |
| Payload enrichment | Add dynamic fields to payload from external data sources |
| Spam protection | Detect duplicate interactions (same type + target within N seconds) |
| Trace context injection | Add OTel traceparent to metadata for distributed tracing |
| Permission check | Verify the requester has permission to send this type to this user |