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

@bonniernews/local-esi

v3.0.1

Published

Local Edge Side Includes parser

Downloads

139

Readme

Local-ESI

Built latest

Make your Express app work like it had Akamai Edge Side Includes parsing or just stream your ESI decorated markup to the parser.

API

  • ESI: transform class that returns an ESI transform stream
  • HTMLWriter: transform class that returns markup from object stream
  • parse: async function that returns ESI evaluated markup

new ESI([options])

Create an ESI transform stream. Emits events.

Arguments:

  • options: optional options object with headers and cookies
    • headers: request headers, accessible through ESI globals HTTP_<HEADER_NAME>, x-forwarded-for will be accessible as REMOTE_ADDR
      • x-localesi-geo: headers to simulate Akamai's geo location abilities. Defaults to: country_code=SE,georegion=208. Accessible through ESI global GEO{}
    • cookies: object with request cookies, accessible through ESI global HTTP_COOKIE
    • path: string request path, mapped to ESI global REQUEST_PATH
    • query: object request query parameters, accessible through ESI global QUERY_STRING
    • localhost: host to use when a relative src is used by eval or include, defaults to headers.host

Returns:

  • esi evaluated object stream

Example express route:

"use strict";

const HTMLParser = require("@bonniernews/atlas-html-stream");
const {ESI, HTMLWriter} = require("@bonniernews/local-esi");
const {pipeline} = require("stream");

module.exports = function streamRender(req, res, next) {
  const { headers, cookies, path, query } = req;

  const options = {
    headers,
    cookies,
    path,
    query,
    localhost: `localhost:${req.socket.server.address().port}`,
  };

  const esi = new ESI(options)
    .once("set_redirect", function onSetRedirect(statusCode, location) {
      res.status(statusCode).redirect(location);
      this.destroy();
    })
    .on("set_response_code", function onSetResponseCode(statusCode, body) {
      res.status(statusCode);
      if (!body) return;
      res.send(body);
      this.destroy();
    })
    .on("add_header", (name, value) => {
      res.set(name, value);
    });

  const body = "";

  pipeline([
    res.render("index"),
    new HTMLParser({preserveWS: true}),
    esi,
    new HTMLWriter(),
  ], (err) => {
    if (err?.code === "ERR_STREAM_PREMATURE_CLOSE"]) {
      return;
    } else if (err) {
      return next(err);
    }

    return res.send(body);
  }).on("data", (chunk) => {
    body += chunk;
  });
};

parse(html, options)

Arguments:

  • html: markup to parse
  • options: same as for for ESI

Returns promise:

  • body: string with ESI evaluated markup or body from $set_response_code
  • statusCode: occasional status code from $set_response_code or $set_redirect
  • headers: object with added headers (in lowercase) from $add_header or $set_redirect(location), NB! set-cookie will be in a list

Example express route:

"use strict";

const {parse} = require("@bonniernews/local-esi");

module.exports = function render(req, res, next) {
  const { headers, cookies, path, query } = req;

  const options = {
    headers,
    cookies,
    path,
    query,
    localhost: `localhost:${req.socket.server.address().port}`,
  };

  const html = res.render("index");

  const {statusCode, headers, body} = await parse(html, options);
  if (statusCode < 309 && statusCode > 300) {
    return res.redirect(statusCode, headers.location);
  }

  if (statusCode) {
    res.status(statusCode);
  } else if (!res.statusCode) {
    res.status(200);
  }
  
  return res.send(body);
};

new HTMLWriter()

Returns transform object stream to markup buffer stream.

ESI Parsing Events

ESI instructions are emitted as events.

set_response_code

Parser encountered a $set_response_code instruction with status code and optional body.

Signature:

  • statusCode: number HTTP status code
  • body: optional string body

add_header

Parser encountered a $add_header instruction with HTTP header name and value.

Signature:

  • name: HTTP header name
  • value: HTTP header value

set_redirect

Parser encountered a $set_redirect instruction with optional status code and location.

Signature:

  • statusCode: redirect HTTP status code
  • location: redirect location

Markup object stream

Object streams requires the schema {name, data, text} representing tag name, tag attributes, and text. This project uses @bonniernews/atlas-html-stream for html parsing.