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

abcloud-edge-proxy

v1.0.0-alpha.6

Published

Cloudfront proxy, providing a/b/n testing, canary releasing, gatekeeping, and SEO a/b/n testing. Implemented as an edge lambda function.

Downloads

18

Readme

A/B Cloud - AWS Cloudfront edge proxy

A Lambda@Edge function used to enable a/b testing, canary releasing, gatekeeping, and SEO a/b/n testing. Enable SSL, for any domain, with AWS certificate manager and Cloudfront. Once set up, abcloud-edge-proxy enables you to a/b test, canary release, and point your domain to any backend, across any cloud provider. Analytics and experimental design (power calculation, statistical analysis) are not part of this package.

Usage

npm install --save abcloud-edge-proxy

Deploy as an Edge Lambda function, within an AWS Cloudfront distribution, for the viewer-request event.

All assignments are done deterministically, by hashing a salt and visitor Id. On every visit the proxy creates a unique request id (using uuid/v4) and forwards this to the origin as a request-id header. On first visits the proxy will use this id as the assignment id. To assure consistent hashing your application MUST set a _vq cookie with this value. On the first request the value of this cookie should be set from the request-id header and on subsequent visits it should come from the _vq cookie (not from the request-id header). For example, in an express app, that might be done as follows:

// set or reset the visitor ID cookie
res.cookie("_vq", req.cookies["_vq"] || req.headers["request-id"], {
    maxAge: 3600 * 1000 * 24 * 365
});

A/B/N Testing Example

import edgeProxy from "abcloud-edge-proxy";

const config = {
    defaultBackend: {
        domainName: "blue.my-site.com"
    },
    origins: [
        {
            domainName: "blue.my-site.com"
        },
        {
            domainName: "green.my-site.com"
        },
        {
            domainName: "red.my-site.com"
        }
    ],
    salt: "unique-assignment-salt",
    test: true
};

exports.handler = edgeProxy(config);

When configuring backends you may use any of the cloudfront parameters, as shown below. Only domainName is required. Current defaults are shown below.

{
    domainName: "required.com",
    port: 443,
    protocol: "https",
    path: "",
    sslProtocols: ["TLSv1", "TLSv1.1"],
    readTimeout: 5,
    keepaliveTimeout: 30,
    customHeaders: {}
};

Canary Releasing Example

Canary releasing can be used to gradually shift traffic from one backend to another. It should ONLY be used with two backends, (unlike a/b/n testing), so that users do not get reassigned as the traffic percentage is increased. An example config is shown below. To assure consistent assignment, for visitors, the weight parameter should only be increased.

import edgeProxy from "edge-proxy";

const config = {
    defaultBackend: {
        domainName: "blue.my-site.com",
    }
    canaryBackend: {
        domainName: "green.my-site.com"
    },
    salt: "unique-assignment-salt",
    canary: true,
    weight: 50 // an integer from 0-100 specifying
    // the percentage of traffic to allocate to the
    // canary backend
};

exports.handler = edgeProxy(config);

Gatekeeping

To enable gatekeeping, you must pass a JWT_SECRET_KEY with the config.

import edgeProxy from "edge-proxy";

const config = {
    JWT_SECRET_KEY: process.env["JWT_SECRET_KEY"]
    /* ... */
};

exports.handler = edgeProxy(config);

You can then encode desired backends into a JWT with your secret and then access your root domain with the JWT set as a query parameter ?devtoken=JWT or as a cookie devtoken=JWT. This allows for ANY backend to be accessed through the proxy and can be useful for developing / testing, on your production domain, without having to update the proxy to add development backends.

An example of creating such a token is shown below.

var jwttoken = require("jsonwebtoken");

const devtoken = jwttoken.sign(
    {
        domainName: "your-desired-backend.com"
        // optional parameters
        // port: 443,
        // protocol: "https",
        // path: "/test",
        // sslProtocols: ["TLSv1", "TLSv1.1"],
        // readTimeout: 60,
        // keepaliveTimeout: 60,
        // customHeaders: {}
    },
    process.env["JWT_SECRET_KEY"]
);

console.log(devtoken);

Search Engine Optimization - A/B Testing Example

Implement by setting SEOTest to true in the config.

Search engine optimization a/b testing is a technique used to validate changes that may impact search rankings. With a/b/n testing, as implemented in this proxy, a unique visitor id is used to hash to a backend. With SEO based a/b/n testing, the full path of each individual request is hashed and used to select the backend. After completion of the experiment period, traffic volumes between the two, or more, SEO implementation are compared for statistical significance.

When running an a/b test, on natural search traffic, it would be wise to validate that your website has enough ranked pages such that a random split of urls results in a generally equal split of natural search traffic (pre-test).

Example config.

import edgeProxy from "abcloud-edge-proxy";

const config = {
    defaultBackend: {
        domainName: "blue.my-site.com"
    },
    origins: [
        {
            domainName: "blue.my-site.com"
        },
        {
            domainName: "green.my-site.com"
        }
    ],
    salt: "unique-assignment-salt",

    // Note the SEOTest flag is set to true
    SEOTest: true
};

exports.handler = edgeProxy(config);

Echoer

To enable the echoer, you must pass an ECHO_TOKEN with the config. You may then access /proxy-echo?echotoken=ECHO_TOKEN and you will get the request object (after modification) returned as formatted JSON. Useful for debugging.

import edgeProxy from "edge-proxy";

const config = {
    ECHO_TOKEN: process.env["ECHO_TOKEN"]
    /* ... */
};

exports.handler = edgeProxy(config);

Building with Webpack

Example building with webpack. Note that edge functions do not currently support environment variables, so we are using webpack to build them into our deployment package.

var path = require("path");
var webpack = require("webpack");

module.exports = {
    entry: {
        proxy: path.join(__dirname, "/index.js")
    },
    output: {
        path: path.join(__dirname, "dist"),
        filename: "edge-proxy-lambda.js",
        libraryTarget: "commonjs"
    },
    target: "node",
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /(node_modules)/,
                use: {
                    loader: "babel-loader"
                }
            }
        ]
    },
    plugins: [
        // env vars
        new webpack.DefinePlugin({
            "process.env": {
                JWT_SECRET_KEY: JSON.stringify(process.env["JWT_SECRET_KEY"]),
                ECHO_TOKEN: JSON.stringify(process.env["ECHO_TOKEN"])
            }
        })
    ]
};

After building with webpack zip the function and deploy to AWS.