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

@envoy/envoy-integrations-sdk

v2.5.1

Published

SDK for building Envoy integrations.

Downloads

745

Readme

Envoy Node.js SDK

The SDK exports several classes and functions, however the most typical way to integrate the SDK is as middleware. The envoyMiddleware() function call returns a middleware that attaches an instance of EnvoyPluginSDK to the req object and verifies that the request came from Envoy. It is available as req.envoy.

Installation

npm install --save @envoy/envoy-integrations-sdk

Environment Variables

The SDK relies on a few environment variables:

  • ENVOY_CLIENT_ID - can be found in the Integration Builder
  • ENVOY_CLIENT_SECRET - can be found in the Integration Builder
  • ENVOY_BASE_URL - (optional in production) the URL to Envoy's API
  • JWT_SECRET - (optional) used if encoding/decoding JWTs

Locally, these environment variables can be set using a .env file.

Getting Started

View our Node.js quickstart guide.

Usage

Define your config

When customers go through your integration's setup steps, that info is saved in a config object that is sent along with every request Envoy makes to your integration.

Defining this object as a specific type allows us to safely type the various handlers that will use those values.

// defs/Config.ts
type Config = {
  greeting: string;
};
export default Config;

Implement setup routes

As customers go through the setup steps of your integration, they may trigger several requests to your integration for things like:

  • loading dropdown options
  • loading text fields with remote data
  • validating submitted step data

Below, we'll implement a route that will load a list of greetings into a dropdown in our setup steps.

View the other types of handlers here.

// greetingOptions.ts
import { optionsRouteHandler } from '@envoy/envoy-integrations-sdk';

export default optionsRouteHandler((req, res) => {
  res.send([
    {
      label: 'Hello',
      value: 'Hello',
    },
    {
      label: 'Hola',
      value: 'Hola',
    },
    {
      label: 'Aloha',
      value: 'Aloha',
    },
  ]);
});

Implement event handlers

Your integration can respond to several Envoy events. Below, we'll implement a simple event handler for an entry_sign_in event.

All it does is to take the greeting that the customer chose during setup, and displays it in the Envoy Dashboard when a visitor signs in.

View the other types of handlers here.

// entrySignIn.ts
import { entryEventHandler } from '@envoy/envoy-integrations-sdk';
import Config from './defs/Config';

export default entryEventHandler<Config>(async (req, res) => {
  const { envoy } = req;
  const { job, meta, payload: visitor } = envoy;
  const hello = `${meta.config.greeting} ${visitor.attributes['full-name']}!`; // our custom greeting
  await job.attach({ label: 'Greeting', value: hello }); // show in the Envoy dashboard.
  res.send({ hello });
});

Setup your express.js app

Use the envoyMiddleware to get an instance of EnvoyPluginSDK attached to every request.

View the other types of middleware here.

// index.ts
import express from 'express';
import { envoyMiddleware, errorMiddleware } from '@envoy/envoy-integrations-sdk';

import greetingOptions from './greetingOptions';
import entrySignIn from './entrySignIn';

const app = express();
app.use(envoyMiddleware());
app.post('/greeting-options', greetingOptions);
app.post('/entry-sign-in', entrySignIn);
app.use(errorMiddleware());
app.listen(process.env.PORT);

More examples

Here's some more things you can do with the req.envoy object.

/**
 * @type EnvoyPluginSDK
 */
const { envoy } = req; // "envoy" is the SDK
const {
  meta, // the platform event request_meta object
  payload, // the platform event request_body object
  userAPI, // user-scoped API calls, used in routes
  pluginAPI, // plugin-scoped API calls, for plugin services
  installStorage, // install-scoped storage
  globalStorage, // global-scoped storage
  job, // update the job (if in an event handler)
  jwt, // helper to encode/decode jwts
} = envoy;

/**
 * User API usage
 */
const visitorTypes = await userAPI.getFlows({ filter: { location: '1' } });

/**
 * Storage usage
 * The below can be used both at the install level or global level
 */
await installStorage.set('foo', 'bar'); // sets foo=bar in storage for this install
const { value } = await installStorage.get<string>('foo'); // also gets the current value of foo
const { value } = await installStorage.setUnique('foo'); // creates and returns a unique text value for foo
const { value } = await installStorage.get<string>('foo'); // also gets the current value of foo
const { value } = await installStorage.setUniqueNum('foo'); // creates and returns a unique number for foo
const { value } = await installStorage.get<number>('foo'); // also gets the current value of foo
await installStorage.unset('foo'); // deletes foo
/**
 * You can also send multiple commands at once,
 * to be executed in the same transaction.
 * The response will be an array of the results of each command, in order.
 */
const results = await installStorage.pipeline().set('foo1', 'bar').unset('foo2').get('foo3').execute();

/**
 * Job updates
 * Note that job.complete can take any number of attachments after the first argument.
 */
await job.complete('Credentials provisioned.', { label: 'password', value: 'password' });
await job.ignore('No credentials provisioned.', 'Email was not supplied.');
await job.fail('Could not provision credentials.', 'Server could not be reached.');
/**
 * You can also just attach things without completing the job.
 * Attach more things by providing more arguments.
 */
await job.attach({ type: 'text', label: 'foo', value: 'bar' });
/**
 * If the job is some multi-step process,
 * you can update it's message without changing the status.
 * You can also optionally attach things by providing more arguments.
 */
await job.update('Still working...');

/**
 * JWT usage
 */
const token = await jwt.encode(visitorId, '30m');
const { sub: visitorId } = await jwt.decode(token);

/**
 * If in a validation route:
 */
res.send({ foo: 'bar' }); // will save foo in the installation config.
// or
res.send({ foo: null }); // will remove foo from the installation config.
// or
res.sendFailed('This step has failed validation.'); // prevent the installer from progressing.

/**
 * If in an options route:
 */
res.send([
  { label: 'Foo', value: 1 },
  { label: 'Bar', value: 2 },
]); // display these options in the dropdown.

/**
 * If in an event handler:
 */
res.send({ hello: 'world' }); // the job was a success, and here's some data about it.
// or
res.sendOngoing("We're still working on it.", { hello: 'world' }); // the job is still ongoing, but here's some data about it.
// or
res.sendIgnored("We're not gonna do this one, sorry.", { hello: 'world' }); // doesnt meet the requirements to continue.
// or
res.sendFailed('We tried, but failed.', { hello: 'world' }); // we cant continue with this job.

/**
 * Implement Axios Loggers
 */
this.axios.interceptors.request.use(envoyAxiosRequestLogger, envoyAxiosErrorLogger); // Request interceptor

this.axios.interceptors.response.use(envoyAxiosResponseLogger, envoyAxiosErrorLogger); // Response interceptor

SDK Reference

Please see detailed documentation here.

Contributing

We're happy to accept contributions. Submit a PR.