Skip to main content

@siglo/notifications Adapter Guide

[!IMPORTANT] Production Security & Hardening: For production deployment requirements, read Notification Hardening & Recovery. Callback GET requests are read-only confirmation previews; only POST requests accept approval decisions. Configure an authorize(payload, request) callback or explicitly opt into allowBearerApproval: true.
@siglo/notifications provides multi-channel messaging, tamper-proof cryptographic approval tokens, and distributed durable callback resumption for Siglo workflows. It enables human-in-the-loop workflows (deployment gates, expense approvals, manual fraud reviews) with signed tokens, application-provided authorization, distributed concurrency control, and zero external SDK dependencies.

1. Overview & Problem Space

In enterprise backend workflows, human intervention and multi-channel notifications (Slack, Discord, Email, SMS, Push) are standard requirements. Implementing these with ad-hoc scripts introduces critical failure modes that @siglo/notifications helps address:

2. Architecture & Step Lifecycle Integration

Siglo executes steps through a formal 5-phase lifecycle: BEFORE → VALIDATION → ACTION → AFTER → COMPENSATE. @siglo/notifications hooks into every phase:

3. Installation & Requirements

Install @siglo/notifications alongside core Siglo and crypto packages:
Optional dependencies for production multi-worker deployments:
Peer dependencies:
  • @siglo/core: ^1.0.0
  • @siglo/crypto: ^1.0.0
  • @siglo/http: ^1.0.0
  • @siglo/scheduler (optional, for background timeout polling): ^1.0.0
  • @siglo/postgres (optional, for persistent checkpoints and shared revocation): ^1.0.0

4. Multi-Channel Transports

@siglo/notifications provides zero-dependency transport implementations using native HTTPS with validated socket DNS resolution with strict network host assertions:

Transport Capability Matrix

Transport Registration

Transports can be registered globally in the application registry or passed directly to individual steps:

5. Workflow Step Integration

sendNotificationStep(name, options)

Used for one-way alerts and messages with automatic idempotency deduplication and context redaction:

sendInteractiveApprovalStep(name, options)

Generates signed callback URLs for human sign-off, dispatches the interactive card/email, and registers saga compensation:

6. Cryptographic Action Tokens & Secret Rotation

Action tokens embed all callback state directly in a signed, URL-safe bearer token: Token=base64url(Payload) ∥ base64url(HMAC-SHA256(Payload,Secret))\text{Token} = \text{base64url}(\text{Payload}) \,\|\, \text{base64url}(\text{HMAC-SHA256}(\text{Payload}, \text{Secret}))

Embedded Payload Structure

Security Defenses:

  1. Zero Database Lookups: The token is verified cryptographically before touching persistent storage.
  2. Timing Attack Defense: Comparisons use timingSafeCompare from @siglo/crypto.
  3. Future Clock Skew Defense: Validates issuedAt <= now + toleranceSeconds. Nonces are not a consumption registry; completed durable claims reject replay.
  4. Key Rotation: Accepts both raw string secrets and KeyRing instances (StaticKeyRing from @siglo/crypto):

7. Web Framework Resumption Handlers

@siglo/notifications exports turnkey callback handlers for Express, Fastify, and Hono.

Security Headers & Sanitization

Every callback response automatically includes:
  • Cache-Control: no-store
  • Referrer-Policy: no-referrer
  • X-Content-Type-Options: nosniff
  • Content-Security-Policy: default-src 'none'; frame-ancestors 'none'
  • Optional allowlisted CORS origin headers (allowedOrigins: ['https://orchestrator.acme.com', 'https://dashboard.acme.com'])

Express Example

Fastify Example

Hono Example (Node)

HTTP Status Code Normalization


8. Distributed Resumption, Shared Revocation & Concurrency

Dual-Worker Atomic Claims

When an approval link is clicked, multiple workers behind a load balancer may receive duplicate requests simultaneously. @siglo/notifications integrates with @siglo/core’s atomic claimWaitRecord call:
  1. Worker 1 acquires the stack session lock, persists the accepted event, and atomically updates (WAITING → RESUMING). Claim succeeds; workflow resumes.
  2. Worker 2 cannot acquire the active session lock or finds the request already completed. Core throws a conflict exception, which the callback handler maps to HTTP 409 Conflict.

Shared PostgreSQL Revocation Store

When a workflow aborts or compensation runs, tokens must be revoked across all worker processes.

9. Two-Way Twilio SMS Approvals

Approvers can reply directly via SMS with APPROVE <ref> or REJECT <ref>. @siglo/notifications provides parseTwilioSmsReply to verify Twilio’s signed form webhooks:

10. Saga Compensation & Interactive Message Invalidation

If downstream steps fail or the workflow is cancelled, Siglo’s named compensation mechanism triggers cancelNotification:
  1. Slack Channels: The registered SlackTransport invokes chat.update on the original message ID, removing interactive buttons and replacing the text with "Workflow cancelled".
  2. Email & Discord: Calls revocationStore.revoke(correlationKey). If an approver clicks an old email link later, the callback endpoint rejects it with HTTP 409 Conflict.

11. Network Egress Security & ASL Perimeter

@siglo/notifications asserts all transport hostnames against Siglo’s AsyncLocalStorage (ASL) network policy:
  • Static host assertions (slack.com, api.resend.com, api.sendgrid.com, api.postmarkapp.com, discord.com, api.twilio.com) run in the BEFORE phase before any network connection is initiated.
  • HTTP requests reject redirects and validate DNS results in the actual socket lookup; injected clients must provide their own controls.
  • Injected transports declare allowedHosts directly on their class definition.

12. Observability, Telemetry & PII Redaction

Automatic Core Redaction

Siglo core automatically masks sensitive fields before emitting monitoring events:
  • Standard keys masked: recipient, email, phone, slackUserId, slackChannelId, discordWebhookUrl, approvalTokens, approveUrl, rejectUrl, signingSecret.
  • Cyclic data structures are safely replaced with '[Circular]'.

Custom Wildcard PII Masking (NotificationMonitor)

To mask domain-specific PII in execution logs and DevTools:

13. Testing & Deterministic Mocking

MockNotificationTransport

Exported from @siglo/notifications/testing to inspect payloads and URLs without real network traffic:

Fast-Forwarding Timeouts with FakeClock

To test approval timeouts deterministically:
[!NOTE] FakeClock advances its own internal virtual timestamp counter (clock.now()). Calling clock.tick() flushes microtasks via setImmediate without replacing global Node.js Date.now or setTimeout.

14. Complete TypeScript API Signatures