npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

twilio-functions-utils

v2.6.1

Published

Twilio Functions utils library

Readme

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

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

Response Classes

| Class | Status Code | Usage | |-------|-------------|-------| | Response(body, statusCode) | Custom | General responses | | TwiMLResponse(twiml) | 200 | TwiML responses | | BadRequestError(message) | 400 | Invalid input | | UnauthorizedError(message) | 401 | Authentication required | | NotFoundError(message) | 404 | Resource not found | | InternalServerError(message) | 500 | Server errors |

Utility Classes

| Class | Description | |-------|-------------| | 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


🤝 Contributing

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

  1. 🐛 Report bugs - Open an issue with reproduction steps
  2. 💡 Suggest features - Describe your use case and proposed solution
  3. 📝 Improve docs - Help make our documentation clearer
  4. 🧪 Write tests - Add test cases for new features
  5. 🔧 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