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 🙏

© 2024 – Pkg Stats / Ryan Hefner

twilio-functions-injector-v2

v1.0.4

Published

Twilio Functions Utility Library

Downloads

5

Readme

Twilio Functions Utils

ABOUT

npm npm Coveralls

This lib was created with the aim of simplifying the use of serverless Twilio, reducing the need to apply frequent try-catches and improving context management, making it no longer necessary to return the callback() method in all functions.

Install

npm install twilio-functions-utils

HOW IT WORKS

The lib provides a function useInjection who returns a brand function for every execution. This returned function is ready to receive the Twilio Handler arguments and make them available as this properties as this.request, this.cookies, this.twilio and this.env at the Function level.

# useInjection(Function, Options) Function

The useInjection method takes two parameters. The first to apply as a handler and the last is an object of configuration options.

[useInjection] Function Function

Must be writen in standard format, this will be your handler function.

  function createSomeThing (event) {
    ...
  }
[useInjection] Options.validateToken Boolean

You can pass validateToken equal true to force Flex Token validation using Twilio Flex Token Validator

useInjection(yourFunction,
  {
    validateToken: true
  }
);

When using Token Validator, the Request body must contain a valid Token from Twilio Flex.

// Event
{
  Token: "Twilio-Token-Here"
}

# useTwilioImport(objectThis) Function

This captures the this object and prepare it for optimizing imports from Twilio Functions as Runtime.getFunctions()[path].path.

[useTwilioImport] objectThis This

The injected through handler function this object.

[useTwilioImport] Usage

The common way to import a function is like this:

  // In other way the code with Twilio should be like this.
  const { functionToImportName: functionThatUsesTwilio } = require(Runtime.getFunctions()['path-to-your-function'].path)

And with the useTwilioImport function you should start doing like this:

export const yourHandlerFunction = async function (event) {
  const { prop1, prop2 } = event;

  const twilio = useTwilioImport(this);

  const functionThatUsesTwilio = twilio(
    TWILIO_TYPES.Functions, // Could be "TWILIO_TYPES.Assets"
    'functionToImportName',
    'path-to-your-function'
  );

  const result = await functionThatUsesTwilio({ [prop1]: prop2 });

When using this approach your functionToImportName have an object this with { twilio: TwilioClient }.

  async function functionThatUsesTwilio (prop) {
    return this.twilio.sync.v1 // And the rest of your code.
  }

# pipe(...functions) Function

The pipe method could receive as many parameters as you desire. They will be called one after another. For async methods use pipeAsync.

[pipe] ...functions Function[]

Any sync function.

[pipe] Usage
  const sum1 = (x) => x + 1;
  const sum2 = (x) => x + 2;
  const sum3 = (x) => x + 3;

  const sum = pipe(sum1, sum2, sum3);
  const result = sum(1) // return 7

  // For async methods:
  const asyncPiped = pipeAsync(async1, async2, async3);
  const result = await asyncPiped(1) // return Promise { YOUR-VALUE }

# transformListTo(TwilioInstanceList, Function) Function

The transformListTo method takes two parameters. The first to apply as a handler and the last is a transformation function.

[transformListTo] TwilioInstanceList TwilioInstanceList

A Twilio Instance List method as twilio.calls.list or twilio.records.list.

[transformListTo] Function Function

A transformation function. You could use one of lib defaults as extract or factory.

[transformListTo] Usage
  const getCallSidList = transformListTo(twilio.calls.list, extract('sid')); 
  const callSidList = await getCallSidList(); // returns ['CA****', 'CA****', 'CA****', 'CA****']

# transformInstanceTo(TwilioInstance, Function) Function

The transformInstanceTo method takes two parameters. The first to apply as a handler and the last is a transformation function.

[transformInstanceTo] TwilioInstance TwilioInstance

A Twilio Instance method as twilio.calls or twilio.records.

[transformInstanceTo] Function Function

A transformation function. You could use one of lib defaults as extract or factory.

[transformInstanceTo] Usage
  const getToNumber = transformInstanceTo(twilio.calls, extract('to'));
  const toNumber = await getToNumber('CA****'); // returns "+956798915489"

Response Class

The responses coming from the function destined to the handler must be returned as an instance of Response.

Response receives a string and a number (status code):

return new Response('Your pretty answer.', 200);

There are two failure response models, BadRequest and NotFound. Its use follows the same model.

const notFound = new NotFoundError('Your error message here.');
const badRequest = new BadRequestError('Your error message here.');

TwiMLResponse Class

There is a proper response template to use with the TwiML format:

const twimlVoice = new Twilio.twiml
  .VoiceResponse();

const enqueueVoice = twimlVoice
  .enqueue({
    action,
    workflowSid,
  })
  .task('{}');

return new TwiMLResponse(twimlVoice, 201)

Usage

IMPORTANT TO USE REGULAR FUNCTIONS ➜ With arrow functions it doesn't work as expected as this cannot be injected correctly.

  function yourFunctionName() {
    // ...
  }

Get the context, event and request data just by deconstructing the object this:

  const { cookies, request, env, twilio, ...YOUR_BODY_VALUES } = this

Combine multiple functions to change the final result using one of the new transformListTo and transformInstanceTo methods:

// File: functions/create-action.js

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

async function createAction(event) {
  const { cookies, request, env, twilio, ...attributes } = this

  const findFromAttributes = transformListTo(twilio.calls.list, extract('sid'))

  const calls = await findFromAttributes(attributes);

  return new Response(calls, 200);
}

exports.handler = useInjection(createAction, {
  validateToken: true, // When using Token Validator, the Request body must contain a valid Token from Twilio.
});

EXTRAS

# typeOf(Value) Function

A simple method to discovery a value type. This is more specific then the original JavaScript typeof.

It will return as Array, Object, String, Number, Symbol.

[typeOf] Value *

Could be any JavaScript primitive value to be type checked.

Usage

const { typeOf } = require('twilio-functions-utils');

const type = typeOf('my name is Lorem');
const typeArray = typeOf(['one', 'two']);
const original = typeof ['one', 'two']

console.log(type) // String
console.log(typeArray) // Array
console.log(original) // object

# factory(Class) Function

A Factory method for your desired Class. It returns a function that works as the Class constructor and receive the Class constructor params.

[factory] Class Prototype

Could be any JavaScript primitive value to be type checked.

Usage

class CustomCall {
  constructor({ from, to, price }) {
    this.from = from;
    this.to = to;
    this.price = price;
  }
}

const customCallFactory = factory(CustomCall);
const call = customCallFactory({ from: '+987566498965', to: '+485797955646', price: 65 })
console.log(call.price) // return 65

TESTING

# useMock(Function, Options) Function

The Twilio Serverless structure make it hard for testing sometimes. So this provides a method that works perfectly with useInjection ready functions. The useMock act like useInjection but mocking some required fragments as getAssets and getFunctions.

[useMock] Function Function

The same function as used in useInjection.

Usage

(Required) Set your jest testing script with NODE_ENV=test:

"scripts": {
    "test": "NODE_ENV=test jest --collect-coverage --watchAll",
    "start": "twilio-run",
    "deploy": "twilio-run deploy"
  }

Your files structures must be have assets and functions into first or second levels starting from src (when in second level):

app/
├─ package.json
├─ node_modules/
├─ src/
│  ├─ functions/
│  ├─ assets/

or:

app/
├─ package.json
├─ functions/
├─ assets/
├─ node_modules/

Exports your function to be tested and your handler so it can be used by Twilio when in runtime:

async function functionToBeTested(event) {
  const something = await someFunction(event)
  return Response(something)
}

const handler = useInjection(functionToBeTested);

module.exports = { functionToBeTested, handler }; // <--

(Required) You always need to import the twilio.mock for Response Twilio Global object on your testing files begining.

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

Use Twilio Functions Utils useMock to do the hard job and just write your tests with the generated function. You can use Twilio.mockRequestResolvedValue, Twilio.mockRequestImplementation, Twilio.mockRequestRejectedValue to Mock your Twilio API requests.

/* global describe, it, expect */

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

const { useMock, Response } = require('twilio-functions-utils');
const { functionToBeTested } = require('../../functions/functionToBeTested'); // <-- Import here!

// Create the test function from the function to be tested
const fn = useMock(functionToBeTested, {
  env: {
    YOUR_ENV_VAR: 'value'
  },
  twilio: {
    functionToMock: {}
  }
});

describe('Function functionToBeTested', () => {
  it('if {"someValue": true}', async () => {
    const request = { TaskSid: '1234567', TaskAttributes: '{"someValue": true}' };

    Twilio.mockRequestResolvedValue({
      statusCode: 200,
      body: {
        sid: '1234567'
      }
    })
    
    Twilio.mockRequestResolvedValue({
      statusCode: 200,
      body: {
        key: "MP****",
        data: { sid: '7654321' }
      }
    })

    const res = await fn(request);
    
    const customMap = await Runtime.getSync().maps("MP****").fetch();

    expect(res).toBeInstanceOf(Response);
    expect(res.body).not.toEqual(request);
    expect(res.data).toEqual({ sid: '7654321' });
    expect(res.body).toEqual({ sid: '1234567' });
  });
});

AUTHOR