SimpleNS LogoDocs

Utilities

Helper functions for template processing, retries, and common operations.


Overview

The SDK provides utility functions to help with common tasks when building notification providers:

import {
  replaceVariables,
  isHtmlContent,
  truncate,
  sleep,
  retryWithBackoff,
} from '@simplens/sdk';

Template Processing

replaceVariables(template, variables)

Substitutes {{variable_name}} placeholders in a string with values from the variables object. Supports optional whitespace inside braces.

function replaceVariables(
  template: string,
  variables: Record<string, string>
): string

Parameters:

ParameterTypeDescription
templatestringString with placeholders
variablesRecord<string, string>Key-value pairs

Returns: String with placeholders replaced.

import { replaceVariables } from '@simplens/sdk';

const result = replaceVariables(
  'Hello {{name}}, your order #{{order_id}} is ready!',
  { name: 'Alice', order_id: '12345' }
);
// Result: "Hello Alice, your order #12345 is ready!"
// Handles whitespace inside braces
const result = replaceVariables(
  'Hi {{ name }}, welcome to {{  platform  }}!',
  { name: 'Bob', platform: 'SimpleNS' }
);
// Result: "Hi Bob, welcome to SimpleNS!"
async send(notification: MyNotification): Promise<DeliveryResult> {
  let html = notification.content.html || '';
  
  // Apply variable substitution if variables provided
  if (notification.variables) {
    html = replaceVariables(html, notification.variables);
  }
  
  // Send the processed content
  await this.client.send({ html });
  return { success: true };
}

Variables that don't exist in the variables object are left unchanged in the template. This prevents accidental data loss if some variables are missing.


isHtmlContent(content)

Checks if a string contains HTML tags. Useful for determining whether to send HTML or plain text.

function isHtmlContent(content: string): boolean

Parameters:

ParameterTypeDescription
contentstringContent to check

Returns: true if the content appears to contain HTML tags.

Examples:

import { isHtmlContent } from '@simplens/sdk';

isHtmlContent('<p>Hello</p>');           // true
isHtmlContent('<div class="test">Hi</div>'); // true
isHtmlContent('Hello, World!');          // false
isHtmlContent('Use <angle> brackets');   // true (has tag-like syntax)

Use Case:

async send(notification: MyNotification): Promise<DeliveryResult> {
  const content = notification.content.text || '';
  
  // Decide format based on content
  const format = isHtmlContent(content) ? 'html' : 'text';
  
  await this.api.send({
    body: content,
    contentType: format === 'html' ? 'text/html' : 'text/plain',
  });
  
  return { success: true };
}

String Manipulation

truncate(str, maxLength, suffix)

Truncates a string to a maximum length, adding a suffix if truncated.

function truncate(
  str: string,
  maxLength: number,
  suffix: string = '...'
): string

Parameters:

ParameterTypeDefaultDescription
strstring-String to truncate
maxLengthnumber-Maximum total length
suffixstring'...'Suffix added when truncated

Returns: Truncated string with suffix (if needed).

Examples:

import { truncate } from '@simplens/sdk';

truncate('Hello, World!', 20);        // "Hello, World!" (no change)
truncate('Hello, World!', 10);        // "Hello, ..." (7 chars + 3 for "...")
truncate('Hello, World!', 10, '…');   // "Hello, Wo…" (9 chars + 1 for "…")

Use Case - SMS Character Limits:

async send(notification: SMSNotification): Promise<DeliveryResult> {
  // Ensure message fits in single SMS
  const message = truncate(notification.content.message, 160);
  
  await this.client.messages.create({
    body: message,
    to: notification.recipient.phone,
  });
  
  return { success: true };
}

Async Helpers

sleep(ms)

Returns a Promise that resolves after the specified milliseconds. Useful for implementing delays between retries.

function sleep(ms: number): Promise<void>

Parameters:

ParameterTypeDescription
msnumberMilliseconds to wait

Example:

import { sleep } from '@simplens/sdk';

async function sendWithDelay() {
  console.log('Sending first message...');
  await sendMessage();
  
  await sleep(1000); // Wait 1 second
  
  console.log('Sending second message...');
  await sendMessage();
}

retryWithBackoff(fn, maxRetries, baseDelayMs)

Retries an async function with exponential backoff. The delay doubles after each failed attempt.

async function retryWithBackoff<T>(
  fn: () => Promise<T>,
  maxRetries: number = 3,
  baseDelayMs: number = 1000
): Promise<T>

Parameters:

ParameterTypeDefaultDescription
fn() => Promise<T>-Async function to retry
maxRetriesnumber3Maximum retry attempts
baseDelayMsnumber1000Initial delay (doubles each retry)

Returns: Result of successful function call.

Throws: Last error if all retries fail.

Backoff Schedule (with defaults):

AttemptDelay Before
10ms (immediate)
21000ms
32000ms
44000ms
import { retryWithBackoff } from '@simplens/sdk';

const result = await retryWithBackoff(
  () => fetch('https://api.example.com/data').then(r => r.json())
);
// 5 retries with 500ms base delay
const result = await retryWithBackoff(
  () => unstableApiCall(),
  5,      // maxRetries
  500     // baseDelayMs
);
// Delays: 0, 500, 1000, 2000, 4000ms
async send(notification: MyNotification): Promise<DeliveryResult> {
  try {
    const response = await retryWithBackoff(
      async () => {
        const res = await this.client.send({
          to: notification.recipient.email,
          html: notification.content.html,
        });
        
        if (!res.ok) {
          throw new Error(`API error: ${res.status}`);
        }
        
        return res.json();
      },
      3,    // 3 retries
      1000  // 1 second base delay
    );
    
    return {
      success: true,
      messageId: response.id,
    };
  } catch (error) {
    return {
      success: false,
      error: {
        code: 'SEND_FAILED',
        message: error.message,
        retryable: false, // Already retried
      },
    };
  }
}

Use retryWithBackoff for transient errors within your provider. SimpleNS also has its own retry mechanism, so don't retry indefinitely - let SimpleNS handle long-term retries.


Usage in Providers

Here's how these utilities work together in a real provider:

import {
  SimpleNSProvider,
  DeliveryResult,
  replaceVariables,
  isHtmlContent,
  truncate,
  retryWithBackoff,
} from '@simplens/sdk';

class MyEmailProvider implements SimpleNSProvider<MyNotification> {
  async send(notification: MyNotification): Promise<DeliveryResult> {
    try {
      let body = notification.content.html || notification.content.text || '';
      
      // 1. Apply template variables
      if (notification.variables) {
        body = replaceVariables(body, notification.variables);
      }
      
      // 2. Detect content type
      const contentType = isHtmlContent(body) ? 'text/html' : 'text/plain';
      
      // 3. Truncate subject for safety
      const subject = truncate(notification.content.subject || '', 100);
      
      // 4. Send with retries for transient failures
      const result = await retryWithBackoff(
        () => this.api.sendEmail({
          to: notification.recipient.email,
          subject,
          body,
          contentType,
        }),
        2,    // 2 retries
        500   // 500ms base delay
      );
      
      return { success: true, messageId: result.id };
    } catch (error) {
      return {
        success: false,
        error: {
          code: 'SEND_FAILED',
          message: error.message,
          retryable: true,
        },
      };
    }
  }
}

On this page