totem-otp-delivery-webhook
v0.0.3
Published
Webhook delivery agent for TotemOTP
Readme
totem-otp-delivery-webhook
HTTP webhook delivery agent for TotemOTP framework.
Installation
npm install totem-otp-delivery-webhookUsage
Basic Usage
import { WebhookDeliveryAgent } from 'totem-otp-delivery-webhook'
import { TotemOTP } from 'totem-otp'
// Create webhook delivery agent
const webhookAgent = new WebhookDeliveryAgent({
webhookUrl: 'https://your-webhook-endpoint.com/otp'
})
// Use with TotemOTP
const totem = new TotemOTP({
storage: () => yourStorageInstance,
schemas: [
{
match: (target) => target.type === 'email',
otp: { charset: ['0123456789'], length: 6 },
reference: { charset: ['ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'], length: 8 },
aging: {
successValidateCount: 1,
purgeFromDbIn: 1800000, // 30 minutes
canResendIn: 120000, // 2 minutes
expiresIn: 300000 // 5 minutes
}
}
],
deliveryAgents: [
{
match: (target) => target.type === 'email',
agent: () => webhookAgent
}
]
})Custom Body Builder
const webhookAgent = new WebhookDeliveryAgent({
webhookUrl: 'https://your-webhook-endpoint.com/otp',
bodyBuilder: (otp) => ({
// Custom webhook payload
recipient: otp.target.value,
code: otp.value,
expires: new Date(otp.expiresAtMs).toISOString(),
reference: otp.reference,
type: otp.target.type
})
})Custom Headers and Method
const webhookAgent = new WebhookDeliveryAgent({
webhookUrl: 'https://your-webhook-endpoint.com/otp',
method: 'PUT',
headers: {
'Authorization': 'Bearer your-token',
'X-Custom-Header': 'custom-value'
},
timeout: 10000 // 10 seconds
})Configuration Options
interface WebhookDeliveryAgentOptions {
/**
* Webhook destination URL
*/
webhookUrl: string
/**
* Optional callback function to compute the request body
* If not provided, a default body structure will be used
*/
bodyBuilder?: (otp: IOTPValue) => Record<string, any>
/**
* Optional HTTP headers to include in the request
* @default { 'Content-Type': 'application/json' }
*/
headers?: Record<string, string>
/**
* Optional HTTP method
* @default 'POST'
*/
method?: 'POST' | 'PUT' | 'PATCH'
/**
* Optional timeout in milliseconds
* @default 30000 (30 seconds)
*/
timeout?: number
}Default Webhook Payload
When no custom bodyBuilder is provided, the webhook will receive:
{
"event": "otp_requested",
"timestamp": "2025-07-16T17:00:00.000Z",
"data": {
"target": {
"type": "email",
"value": "[email protected]",
"uniqueIdentifier": "user-123"
},
"otp": {
"value": "123456",
"reference": "REF12345",
"expiresAt": "2025-07-16T17:05:00.000Z",
"resendAllowedAt": "2025-07-16T17:02:00.000Z"
}
}
}Receipt ID Handling
The delivery agent attempts to extract a receipt ID from the webhook response:
JSON Response
{
"receiptId": "receipt-123",
// or "receipt_id", "id", "messageId", "message_id"
}Text Response
receipt-123If no receipt ID is found, a fallback ID is generated in the format:
webhook_{timestamp}_{hash}_{otpReference}Custom Body Builders
Email-Style Delivery Agent
const emailAgent = new WebhookDeliveryAgent({
webhookUrl: 'https://email-service.com/send',
headers: { 'Authorization': 'Bearer token' },
bodyBuilder: (otp) => ({
to: otp.target.value,
subject: 'Your OTP Code',
body: `Your OTP code is: ${otp.value}. This code will expire at ${new Date(otp.expiresAtMs).toLocaleString()}.`,
reference: otp.reference,
expiresAt: new Date(otp.expiresAtMs).toISOString()
})
})SMS-Style Delivery Agent
const smsAgent = new WebhookDeliveryAgent({
webhookUrl: 'https://sms-service.com/send',
bodyBuilder: (otp) => ({
to: otp.target.value,
message: `Your OTP code is: ${otp.value}. Expires in ${Math.ceil((otp.expiresAtMs - Date.now()) / 60000)} minutes.`,
reference: otp.reference,
expiresAt: new Date(otp.expiresAtMs).toISOString()
})
})Custom Delivery Agent
const customAgent = new WebhookDeliveryAgent({
webhookUrl: 'https://custom-service.com/notify',
method: 'PUT',
bodyBuilder: (otp) => ({
customField: otp.value,
customTarget: otp.target.value
})
})Error Handling
The delivery agent will throw an error if:
- The webhook responds with HTTP status code outside 200-299 range
- Network/connection errors occur
- Request timeout is exceeded
try {
const receiptId = await webhookAgent.sendMessageToAudience(otp)
console.log('OTP sent successfully:', receiptId)
} catch (error) {
console.error('Webhook delivery failed:', error.message)
}Testing
For testing purposes, you can use tools like nock to mock HTTP requests:
import nock from 'nock'
// Mock webhook endpoint
nock('https://your-webhook-endpoint.com')
.post('/otp')
.reply(200, { receiptId: 'test-receipt-123' })
// Test your delivery agent
const result = await webhookAgent.sendMessageToAudience(testOTPValue)
expect(result).toBe('test-receipt-123')Requirements
- Node.js 16 or higher
- TypeScript 4.5 or higher
License
ISC
