๐Ÿš€ Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more โ†’
Socket
Book a DemoInstallSign in
Socket

twilio-functions-utils

Package Overview
Dependencies
Maintainers
1
Versions
71
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

twilio-functions-utils

Twilio Functions utils library

2.6.1
latest
Source
npm
Version published
Weekly downloads
215
641.38%
Maintainers
1
Weekly downloads
ย 
Created
Source

Twilio Functions Utils โšก

npm npm npms.io (final) Coveralls

๐Ÿš€ Next-Generation Twilio Functions Development

A powerful, RxJS-powered utility library that revolutionizes Twilio serverless function development with reactive streams, functional composition, and zero-boilerplate dependency injection.

โœจ What's New in v2.4+:

  • ๐Ÿ”„ Reactive Streams: Built on RxJS for composable, testable functions
  • ๐ŸŽฏ Zero Breaking Changes: 100% backward compatible with existing code
  • ๐Ÿงช Enhanced Testing: Marble testing and advanced mocking capabilities
  • ๐Ÿ›  Two API Levels: Simple injection API + powerful Effects API
  • โšก Better Performance: Optimized stream processing
  • ๐Ÿ”’ Type Safe: Full TypeScript support with proper inference
npm install twilio-functions-utils

๐Ÿ“‹ Requirements & Compatibility

  • Node.js: >= 14.0.0
  • Twilio Runtime: Compatible with Twilio Functions runtime
  • TypeScript: >= 5.0.0 (for TypeScript projects)
  • Dependencies: RxJS 7.8.2+, Twilio SDK 3.77.2+

Peer Dependencies

  • twilio - Twilio JavaScript SDK
  • @twilio/runtime-handler - For local development

๐Ÿ›  Development Setup

Building the Project

npm run build        # Compile TypeScript to JavaScript
npm run prebuild     # Clean build directory before building

Testing

npm run test         # Run Jest test suite with coverage
NODE_ENV=test npm test  # Ensure test environment

Documentation

npm run docs         # Generate JSDoc documentation

Project Structure

The library supports flexible directory structures:

  • ./functions/ or ./src/functions/ for your Twilio Functions
  • ./assets/ or ./src/assets/ for static assets
  • Automatically detected during testing

๐ŸŽฏ Quick Start

Option 1: Simple API (Familiar & Easy)

const { useInjection, Response, BadRequestError, Result } = require('twilio-functions-utils');

// Provider: Your business logic
const sendSmsProvider = async function (to, message) {
  const { client } = this;
  
  try {
    const result = await client.messages.create({
      to,
      from: '+1234567890',
      body: message
    });
    return Result.ok({ sid: result.sid, status: 'sent' });
  } catch (error) {
    return Result.failed(error.message);
  }
};

// Handler: Your Twilio Function
async function sendSmsHandler(event) {
  const { env, providers } = this;
  const { to, message } = event;
  
  if (!to || !message) {
    return new BadRequestError('Missing "to" or "message" parameters');
  }
  
  const result = await providers.sendSms(to, message);
  
  if (result.isError) {
    return new BadRequestError(result.error);
  }
  
  return new Response(result.data, 201);
}

// Export for Twilio
exports.handler = useInjection(sendSmsHandler, {
  providers: { sendSms: sendSmsProvider }
});

Option 2: RxJS Effects API (Advanced & Powerful)

const { 
  twilioEffect, 
  injectEvent, 
  injectClient, 
  requireFields, 
  ok, 
  handleError 
} = require('twilio-functions-utils');

const { switchMap, map } = require('rxjs/operators');

const sendSmsEffect = context$ => 
  context$.pipe(
    requireFields('to', 'message'),
    injectEvent(),
    injectClient(),
    switchMap(([event, client]) =>
      client.messages.create({
        to: event.to,
        from: '+1234567890',
        body: event.message
      })
    ),
    map(result => ({ sid: result.sid, status: 'sent' })),
    ok(),
    handleError()
  );

exports.handler = twilioEffect(sendSmsEffect);

TypeScript Examples

import { 
  useInjection, 
  Response, 
  BadRequestError, 
  Result,
  InjectorFunction,
  ProviderFunction 
} from 'twilio-functions-utils';

// Type your environment variables
interface MyEnv {
  ACCOUNT_SID: string;
  AUTH_TOKEN: string;
  FROM_NUMBER: string;
}

// Type your event data
interface SmsEvent {
  to: string;
  message: string;
}

// Type your providers
interface MyProviders {
  sendSms: (to: string, message: string) => Promise<Result<{ sid: string }, string>>;
}

// Provider with full typing
const sendSmsProvider: ProviderFunction<SmsEvent, MyEnv> = async function (
  to: string, 
  message: string
) {
  const { client, env } = this;
  
  try {
    const result = await client.messages.create({
      to,
      from: env.FROM_NUMBER,
      body: message
    });
    return Result.ok({ sid: result.sid });
  } catch (error: any) {
    return Result.failed(error.message);
  }
};

// Handler with full typing
const sendSmsHandler: InjectorFunction<SmsEvent, MyEnv, MyProviders> = async function (event) {
  const { env, providers } = this;
  const { to, message } = event;
  
  if (!to || !message) {
    return new BadRequestError('Missing required parameters');
  }
  
  const result = await providers.sendSms(to, message);
  
  if (result.isError) {
    return new BadRequestError(result.error);
  }
  
  return new Response(result.data, 201);
};

// Export with types
export const handler = useInjection<SmsEvent, MyEnv, MyProviders>(sendSmsHandler, {
  providers: { sendSms: sendSmsProvider }
});

RxJS Effects with TypeScript

import { 
  twilioEffect, 
  EffectWithContext,
  EffectContext,
  injectEvent, 
  injectClient,
  requireFields,
  ok 
} from 'twilio-functions-utils';
import { switchMap, map } from 'rxjs/operators';

interface SmsEnv {
  FROM_NUMBER: string;
}

interface SmsEvent {
  to: string;
  message: string;
}

const sendSmsEffect: EffectWithContext<SmsEnv, {}, Response> = (context$) =>
  context$.pipe(
    requireFields<SmsEvent>('to', 'message'),
    injectEvent<SmsEvent>(),
    injectClient(),
    switchMap(([event, client]) =>
      client.messages.create({
        to: event.to,
        from: process.env.FROM_NUMBER,
        body: event.message
      })
    ),
    map(result => ({ sid: result.sid, status: 'sent' })),
    ok()
  );

export const handler = twilioEffect<SmsEnv, {}>(sendSmsEffect);

๐Ÿ”ฅ Core Features

๐ŸŽญ Dependency Injection Made Simple

Access everything you need through clean this context:

async function myHandler(event) {
  const { 
    env,        // Environment variables
    providers,  // Your business logic
    request,    // HTTP headers & data
    cookies     // Request cookies
  } = this;
  
  // Your logic here...
}

๐Ÿ“ฆ Result Pattern (No More Try-Catch Hell)

// In your providers
const fetchUser = async function (userId) {
  const { client, env } = this;
  
  try {
    const user = await client.api.accounts(env.ACCOUNT_SID)
      .calls
      .list({ limit: 1 });
    
    return Result.ok(user[0]);
  } catch (error) {
    return Result.failed('User not found');
  }
};

// In your handlers
const userResult = await this.providers.fetchUser(event.userId);

if (userResult.isError) {
  return new NotFoundError(userResult.error);
}

return new Response(userResult.data);

๐ŸŽฏ Smart Response Handling

// JSON Responses
return new Response({ success: true, data: results }, 201);

// TwiML Responses
const twiml = new Twilio.twiml.VoiceResponse();
twiml.say('Hello from RxJS-powered Twilio!');
return new TwiMLResponse(twiml.toString());

// Error Responses
return new BadRequestError('Invalid input');
return new NotFoundError('Resource not found');
return new UnauthorizedError('Access denied');
return new InternalServerError('Something went wrong');

๐Ÿ”„ RxJS Effects API

For advanced use cases, leverage the full power of reactive programming:

Composition with Operators

const complexWorkflow = context$ =>
  context$.pipe(
    // Validation
    requireFields('customerId', 'action'),
    authenticated(ctx => ctx.event.token),
    
    // Data fetching
    switchMap(ctx => 
      ctx.providers.customerService.getProfile(ctx.event.customerId)
    ),
    
    // Business logic
    map(customer => ({
      id: customer.id,
      name: customer.name,
      tier: customer.subscriptions.length > 0 ? 'premium' : 'basic'
    })),
    
    // Response formatting
    apiResponse({ message: 'Profile retrieved successfully' }),
    
    // Error handling
    handleError(error => {
      if (error.code === 'CUSTOMER_NOT_FOUND') {
        return new NotFoundError('Customer not found');
      }
      return null; // Use default error handling
    })
  );

Built-in Operators

// Validation
requireFields('email', 'phone')
validateEvent(event => event.email.includes('@'))
authenticated(ctx => checkApiKey(ctx.event.apiKey))

// Data injection
injectEvent()           // Get event data
injectEnv()            // Get environment vars
injectClient()         // Get Twilio client
injectProviders()      // Get all providers
injectProvider('userService')  // Get specific provider

// Response formatting
ok()                   // 200 response
created()              // 201 response  
apiResponse({ meta: { version: '1.0' } })
toTwiMLResponse()      // Convert TwiML to response

// Error handling
handleError()          // Comprehensive error handling
retryWithBackoff(3)    // Retry failed operations
timeoutWithError(5000) // Timeout after 5 seconds
fallback(defaultValue) // Provide fallback value

๐Ÿงช Testing Made Easy

Simple Testing (Original API)

require('twilio-functions-utils/dist/lib/twilio.mock.js');

const { useMock, Response } = require('twilio-functions-utils');
const { myHandler } = require('../functions/myHandler');

const mockFn = useMock(myHandler, {
  providers: {
    sendSms: async (to, message) => ({ sid: 'SM123', status: 'sent' })
  },
  env: { ACCOUNT_SID: 'AC123' },
  client: { /* mock Twilio client */ }
});

test('should send SMS successfully', async () => {
  const result = await mockFn({ to: '+1234567890', message: 'Hello!' });
  
  expect(result).toBeInstanceOf(Response);
  expect(result.statusCode).toBe(201);
});

Advanced Testing (RxJS Effects)

const { testEffect, marbleTest, expectEmissions } = require('twilio-functions-utils');

test('should handle SMS sending with marble testing', () => {
  marbleTest(({ cold, expectObservable }) => {
    const context$ = cold('a|', {
      a: { event: { to: '+1234567890', message: 'Test' } }
    });

    const result$ = sendSmsEffect(context$);

    expectObservable(result$).toBe('a|', {
      a: expect.objectContaining({ statusCode: 200 })
    });
  });
});

๐Ÿ”’ Flex Integration

Built-in support for Twilio Flex token validation:

// Simple API
exports.handler = useInjection(myHandler, {
  providers: { taskService },
  validateToken: true  // Automatically validates Flex tokens
});

// RxJS API  
const flexEffect = context$ =>
  context$.pipe(
    validateFlexToken(),  // Validates token from event.Token
    // ... rest of your logic
  );

// Custom token validation
const customFlexEffect = context$ =>
  context$.pipe(
    validateFlexTokenWithOptions({
      tokenField: 'customToken',
      onValidation: (result) => console.log('Token validated:', result)
    }),
    // ... rest of your logic
  );

๐Ÿ“š Migration Guide

From v2.4.x to v2.5.0: Zero Breaking Changes! ๐ŸŽ‰

Your existing code works without any modifications:

// This code works exactly the same in v2.5.0
const { useInjection, Response, Result } = require('twilio-functions-utils');

async function existingHandler(event) {
  const result = await this.providers.existingProvider(event);
  return new Response(result.data);
}

exports.handler = useInjection(existingHandler, {
  providers: { existingProvider }
});

What's New in v2.5.0:

  • โœ… RxJS-Powered Architecture - Enhanced reactive stream processing under the hood
  • โœ… Advanced Effects API - Optional RxJS Effects for complex workflows
  • โœ… Enhanced Testing - Marble testing and improved mocking capabilities
  • โœ… Better Performance - Optimized stream processing and error handling
  • โœ… Full TypeScript Support - Complete type safety with proper inference

๐Ÿ›  API Reference

Core Functions

FunctionDescription
useInjection(fn, options)Main dependency injection wrapper
twilioEffect(effect, options)RxJS Effects wrapper
useMock(fn, options)Testing utility (test environment only)

Response Classes

ClassStatus CodeUsage
Response(body, statusCode)CustomGeneral responses
TwiMLResponse(twiml)200TwiML responses
BadRequestError(message)400Invalid input
UnauthorizedError(message)401Authentication required
NotFoundError(message)404Resource not found
InternalServerError(message)500Server errors

Utility Classes

ClassDescription
Result.ok(data)Success result wrapper
Result.failed(error)Error result wrapper
typeOf(value)Enhanced type checking

๐Ÿ”ง Troubleshooting

Common Issues

"Module not found" Error

# Ensure you've installed the package
npm install twilio-functions-utils

# For TypeScript projects, ensure proper types
npm install --save-dev typescript @types/node

Testing Issues

// โŒ Wrong - Missing mock import
const { useMock } = require('twilio-functions-utils');

// โœ… Correct - Import mock first
require('twilio-functions-utils/dist/lib/twilio.mock.js');
const { useMock } = require('twilio-functions-utils');

// Ensure NODE_ENV=test
process.env.NODE_ENV = 'test';

RxJS Operator Issues

# Ensure RxJS is installed
npm install rxjs@^7.8.2

# Import operators correctly
const { switchMap, map } = require('rxjs/operators');

TypeScript Compilation Errors

// tsconfig.json - Ensure proper configuration
{
  "compilerOptions": {
    "target": "ES2018",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

Runtime Context Issues

// โŒ Wrong - Arrow functions lose 'this' context
const handler = (event) => {
  // 'this' is undefined here
};

// โœ… Correct - Use regular functions
async function handler(event) {
  // 'this' context available here
  const { env, providers } = this;
}

Performance Tips

  • Use injectMany() instead of multiple inject() calls
  • Leverage RxJS operators for complex data transformations
  • Use Result pattern to avoid try-catch overhead
  • Enable TypeScript strict mode for better optimization

Getting Help

  • ๐Ÿ“– Check documentation
  • ๐Ÿ› Report bugs on GitHub Issues
  • ๐Ÿ’ฌ Ask questions in Twilio Community

๐Ÿค Contributing

We welcome contributions! Here's how you can help:

  • ๐Ÿ› Report bugs - Open an issue with reproduction steps
  • ๐Ÿ’ก Suggest features - Describe your use case and proposed solution
  • ๐Ÿ“ Improve docs - Help make our documentation clearer
  • ๐Ÿงช Write tests - Add test cases for new features
  • ๐Ÿ”ง Submit PRs - Follow our coding standards and include tests

๐ŸŒŸ Community & Support

๐Ÿ“š Resources

๐Ÿ†˜ Getting Help

๐Ÿค Contributing

๐Ÿ“„ License

MIT License - see LICENSE file for details.

๐Ÿ‘จโ€๐Ÿ’ป Author

Iago Calazans - Senior Node.js Engineer

โญ If this library helps you build amazing Twilio Functions, give it a star! โญ

Made with โค๏ธ and โ˜• for the Twilio community

Keywords

twilio

FAQs

Package last updated on 06 Jul 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts