totem-otp-delivery-webhook
Version:
Webhook delivery agent for TotemOTP
246 lines (200 loc) • 5.41 kB
Markdown
HTTP webhook delivery agent for TotemOTP framework.
```bash
npm install totem-otp-delivery-webhook
```
```typescript
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
}
]
})
```
```typescript
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
})
})
```
```typescript
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
})
```
```typescript
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
}
```
When no custom `bodyBuilder` is provided, the webhook will receive:
```json
{
"event": "otp_requested",
"timestamp": "2025-07-16T17:00:00.000Z",
"data": {
"target": {
"type": "email",
"value": "user@example.com",
"uniqueIdentifier": "user-123"
},
"otp": {
"value": "123456",
"reference": "REF12345",
"expiresAt": "2025-07-16T17:05:00.000Z",
"resendAllowedAt": "2025-07-16T17:02:00.000Z"
}
}
}
```
The delivery agent attempts to extract a receipt ID from the webhook response:
```json
{
"receiptId": "receipt-123",
// or "receipt_id", "id", "messageId", "message_id"
}
```
```
receipt-123
```
If no receipt ID is found, a fallback ID is generated in the format:
```
webhook_{timestamp}_{hash}_{otpReference}
```
```typescript
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()
})
})
```
```typescript
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()
})
})
```
```typescript
const customAgent = new WebhookDeliveryAgent({
webhookUrl: 'https://custom-service.com/notify',
method: 'PUT',
bodyBuilder: (otp) => ({
customField: otp.value,
customTarget: otp.target.value
})
})
```
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
```typescript
try {
const receiptId = await webhookAgent.sendMessageToAudience(otp)
console.log('OTP sent successfully:', receiptId)
} catch (error) {
console.error('Webhook delivery failed:', error.message)
}
```
For testing purposes, you can use tools like [nock](https://github.com/nock/nock) to mock HTTP requests:
```typescript
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')
```
- Node.js 16 or higher
- TypeScript 4.5 or higher
ISC