code:
'use strict';

var GetIntrinsic = require('get-intrinsic');
var callBound = require('call-bind/callBound');
var inspect = require('object-inspect');

var $TypeError = require('es-errors/type');
var $WeakMap = GetIntrinsic('%WeakMap%', true);
var $Map = GetIntrinsic('%Map%', true);

var $weakMapGet = callBound('WeakMap.prototype.get', true);
var $weakMapSet = callBound('WeakMap.prototype.set', true);
var $weakMapHas = callBound('WeakMap.prototype.has', true);
var $mapGet = callBound('Map.prototype.get', true);
var $mapSet = callBound('Map.prototype.set', true);
var $mapHas = callBound('Map.prototype.has', true);

/*
* This function traverses the list returning the node corresponding to the given key.
*
* That node is also moved to the head of the list, so that if it's accessed again we don't need to traverse the whole list. By doing so, all the recently used nodes can be accessed relatively quickly.
*/
/** @type {import('.').listGetNode} */
var listGetNode = function (list, key) { // eslint-disable-line consistent-return
	/** @type {typeof list | NonNullable<(typeof list)['next']>} */
	var prev = list;
	/** @type {(typeof list)['next']} */
	var curr;
	for (; (curr = prev.next) !== null; prev = curr) {
		if (curr.key === key) {
			prev.next = curr.next;
			// eslint-disable-next-line no-extra-parens
			curr.next = /** @type {NonNullable<typeof list.next>} */ (list.next);
			list.next = curr; // eslint-disable-line no-param-reassign
			return curr;
		}
	}
};

/** @type {import('.').listGet} */
var listGet = function (objects, key) {
	var node = listGetNode(objects, key);
	return node && node.value;
};
/** @type {import('.').listSet} */
var listSet = function (objects, key, value) {
	var node = listGetNode(objects, key);
	if (node) {
		node.value = value;
	} else {
		// Prepend the new node to the beginning of the list
		objects.next = /** @type {import('.').ListNode<typeof value>} */ ({ // eslint-disable-line no-param-reassign, no-extra-parens
			key: key,
			next: objects.next,
			value: value
		});
	}
};
/** @type {import('.').listHas} */
var listHas = function (objects, key) {
	return !!listGetNode(objects, key);
};

/** @type {import('.')} */
module.exports = function getSideChannel() {
	/** @type {WeakMap<object, unknown>} */ var $wm;
	/** @type {Map<object, unknown>} */ var $m;
	/** @type {import('.').RootNode<unknown>} */ var $o;

	/** @type {import('.').Channel} */
	var channel = {
		assert: function (key) {
			if (!channel.has(key)) {
				throw new $TypeError('Side channel does not contain ' + inspect(key));
			}
		},
		get: function (key) { // eslint-disable-line consistent-return
			if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) {
				if ($wm) {
					return $weakMapGet($wm, key);
				}
			} else if ($Map) {
				if ($m) {
					return $mapGet($m, key);
				}
			} else {
				if ($o) { // eslint-disable-line no-lonely-if
					return listGet($o, key);
				}
			}
		},
		has: function (key) {
			if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) {
				if ($wm) {
					return $weakMapHas($wm, key);
				}
			} else if ($Map) {
				if ($m) {
					return $mapHas($m, key);
				}
			} else {
				if ($o) { // eslint-disable-line no-lonely-if
					return listHas($o, key);
				}
			}
			return false;
		},
		set: function (key, value) {
			if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) {
				if (!$wm) {
					$wm = new $WeakMap();
				}
				$weakMapSet($wm, key, value);
			} else if ($Map) {
				if (!$m) {
					$m = new $Map();
				}
				$mapSet($m, key, value);
			} else {
				if (!$o) {
					// Initialize the linked list as an empty node, so that we don't have to special-case handling of the first node: we can always refer to it as (previous node).next, instead of something like (list).head
					$o = { key: {}, next: null };
				}
				listSet($o, key, value);
			}
		}
	};
	return channel;
};


side-channel

description: Store information about any JS value in a side channel. Uses WeakMap if available.

prepublishOnly: safe-publish-latest

prepublish: not-in-publish || npm run prepublishOnly

prelint: eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\.git')

lint: eslint --ext=js,mjs .

postlint: tsc -p .

pretest: npm run lint

tests-only: nyc tape 'test/**/*.js'

test: npm run tests-only

posttest: aud --production

version: auto-changelog && git add CHANGELOG.md

postversion: auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f "v$(node -e "console.log(require('./package.json').version)")"

type: git

keywords: weakmap map side channel metadata

author: Jordan Harband <ljharb@gmail.com>

license: MIT

typescript: next

output: CHANGELOG.md

template: keepachangelog

license: mit


code:
'use strict';

var test = require('tape');

var getSideChannel = require('../');

test('export', function (t) {
	t.equal(typeof getSideChannel, 'function', 'is a function');
	t.equal(getSideChannel.length, 0, 'takes no arguments');

	var channel = getSideChannel();
	t.ok(channel, 'is truthy');
	t.equal(typeof channel, 'object', 'is an object');

	t.end();
});

test('assert', function (t) {
	var channel = getSideChannel();
	t['throws'](
		function () { channel.assert({}); },
		TypeError,
		'nonexistent value throws'
	);

	var o = {};
	channel.set(o, 'data');
	t.doesNotThrow(function () { channel.assert(o); }, 'existent value noops');

	t.end();
});

test('has', function (t) {
	var channel = getSideChannel();
	/** @type {unknown[]} */ var o = [];

	t.equal(channel.has(o), false, 'nonexistent value yields false');

	channel.set(o, 'foo');
	t.equal(channel.has(o), true, 'existent value yields true');

	t.equal(channel.has('abc'), false, 'non object value non existent yields false');

	channel.set('abc', 'foo');
	t.equal(channel.has('abc'), true, 'non object value that exists yields true');

	t.end();
});

test('get', function (t) {
	var channel = getSideChannel();
	var o = {};
	t.equal(channel.get(o), undefined, 'nonexistent value yields undefined');

	var data = {};
	channel.set(o, data);
	t.equal(channel.get(o), data, '"get" yields data set by "set"');

	t.end();
});

test('set', function (t) {
	var channel = getSideChannel();
	var o = function () {};
	t.equal(channel.get(o), undefined, 'value not set');

	channel.set(o, 42);
	t.equal(channel.get(o), 42, 'value was set');

	channel.set(o, Infinity);
	t.equal(channel.get(o), Infinity, 'value was set again');

	var o2 = {};
	channel.set(o2, 17);
	t.equal(channel.get(o), Infinity, 'o is not modified');
	t.equal(channel.get(o2), 17, 'o2 is set');

	channel.set(o, 14);
	t.equal(channel.get(o), 14, 'o is modified');
	t.equal(channel.get(o2), 17, 'o2 is not modified');

	t.end();
});


code:
{
	"compilerOptions": {
		/* Visit https://aka.ms/tsconfig.json to read more about this file */

		/* Projects */

		/* Language and Environment */
		"target": "es2022",																	/* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
		// "lib": [],																				/* Specify a set of bundled library declaration files that describe the target runtime environment. */
		// "noLib": true,																		/* Disable including any library files, including the default lib.d.ts. */
		"useDefineForClassFields": true,										 /* Emit ECMAScript-standard-compliant class fields. */
		// "moduleDetection": "auto",												/* Control what method is used to detect module-format JS files. */

		/* Modules */
		"module": "commonjs",																/* Specify what module code is generated. */
		// "rootDir": "./",																	/* Specify the root folder within your source files. */
		// "moduleResolution": "node",											 /* Specify how TypeScript looks up a file from a given module specifier. */
		// "baseUrl": "./",																	/* Specify the base directory to resolve non-relative module names. */
		// "paths": {},																			/* Specify a set of entries that re-map imports to additional lookup locations. */
		// "rootDirs": [],																	 /* Allow multiple folders to be treated as one when resolving modules. */
		// "typeRoots": ["types"],													 /* Specify multiple folders that act like `./node_modules/@types`. */
		"resolveJsonModule": true,													 /* Enable importing .json files. */
		// "allowArbitraryExtensions": true,								 /* Enable importing files with any extension, provided a declaration file is present. */

		/* JavaScript Support */
		"allowJs": true,																		 /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
		"checkJs": true,																		 /* Enable error reporting in type-checked JavaScript files. */
		"maxNodeModuleJsDepth": 1,													 /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */

		/* Emit */
		"declaration": true,																 /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
		"declarationMap": true,															/* Create sourcemaps for d.ts files. */
		"noEmit": true,																			/* Disable emitting files from a compilation. */

		/* Interop Constraints */
		"allowSyntheticDefaultImports": true,								/* Allow `import x from y` when a module doesn't have a default export. */
		"esModuleInterop": true,														 /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
		"forceConsistentCasingInFileNames": true,						/* Ensure that casing is correct in imports. */

		/* Type Checking */
		"strict": true,																			/* Enable all strict type-checking options. */

		/* Completeness */
		// "skipLibCheck": true															/* Skip type checking all .d.ts files. */
	},
	"exclude": [
		"coverage",
		"test/list-exports"
	],
}


code:
# signal-exit

[![Build Status](https://travis-ci.org/tapjs/signal-exit.png)](https://travis-ci.org/tapjs/signal-exit)
[![Coverage](https://coveralls.io/repos/tapjs/signal-exit/badge.svg?branch=master)](https://coveralls.io/r/tapjs/signal-exit?branch=master)
[![NPM version](https://img.shields.io/npm/v/signal-exit.svg)](https://www.npmjs.com/package/signal-exit)
[![Standard Version](https://img.shields.io/badge/release-standard%20version-brightgreen.svg)](https://github.com/conventional-changelog/standard-version)

When you want to fire an event no matter how a process exits:

* reaching the end of execution.
* explicitly having `process.exit(code)` called.
* having `process.kill(pid, sig)` called.
* receiving a fatal signal from outside the process

Use `signal-exit`.

```js
var onExit = require('signal-exit')

onExit(function (code, signal) {
  console.log('process exited!')
})
```

## API

`var remove = onExit(function (code, signal) {}, options)`

The return value of the function is a function that will remove the
handler.

Note that the function *only* fires for signals if the signal would
cause the process to exit.  That is, there are no other listeners, and
it is a fatal signal.

## Options

* `alwaysLast`: Run this handler after any other signal or exit
  handlers.  This causes `process.emit` to be monkeypatched.


code:
// Note: since nyc uses this module to output coverage, any lines
// that are in the direct sync flow of nyc's outputCoverage are
// ignored, since we can never get coverage for them.
// grab a reference to node's real process object right away
var process = global.process

const processOk = function (process) {
  return process &&
    typeof process === 'object' &&
    typeof process.removeListener === 'function' &&
    typeof process.emit === 'function' &&
    typeof process.reallyExit === 'function' &&
    typeof process.listeners === 'function' &&
    typeof process.kill === 'function' &&
    typeof process.pid === 'number' &&
    typeof process.on === 'function'
}

// some kind of non-node environment, just no-op
/* istanbul ignore if */
if (!processOk(process)) {
  module.exports = function () {
    return function () {}
  }
} else {
  var assert = require('assert')
  var signals = require('./signals.js')
  var isWin = /^win/i.test(process.platform)

  var EE = require('events')
  /* istanbul ignore if */
  if (typeof EE !== 'function') {
    EE = EE.EventEmitter
  }

  var emitter
  if (process.__signal_exit_emitter__) {
    emitter = process.__signal_exit_emitter__
  } else {
    emitter = process.__signal_exit_emitter__ = new EE()
    emitter.count = 0
    emitter.emitted = {}
  }

  // Because this emitter is a global, we have to check to see if a
  // previous version of this library failed to enable infinite listeners.
  // I know what you're about to say.  But literally everything about
  // signal-exit is a compromise with evil.  Get used to it.
  if (!emitter.infinite) {
    emitter.setMaxListeners(Infinity)
    emitter.infinite = true
  }

  module.exports = function (cb, opts) {
    /* istanbul ignore if */
    if (!processOk(global.process)) {
      return function () {}
    }
    assert.equal(typeof cb, 'function', 'a callback must be provided for exit handler')

    if (loaded === false) {
      load()
    }

    var ev = 'exit'
    if (opts && opts.alwaysLast) {
      ev = 'afterexit'
    }

    var remove = function () {
      emitter.removeListener(ev, cb)
      if (emitter.listeners('exit').length === 0 &&
          emitter.listeners('afterexit').length === 0) {
        unload()
      }
    }
    emitter.on(ev, cb)

    return remove
  }

  var unload = function unload () {
    if (!loaded || !processOk(global.process)) {
      return
    }
    loaded = false

    signals.forEach(function (sig) {
      try {
        process.removeListener(sig, sigListeners[sig])
      } catch (er) {}
    })
    process.emit = originalProcessEmit
    process.reallyExit = originalProcessReallyExit
    emitter.count -= 1
  }
  module.exports.unload = unload

  var emit = function emit (event, code, signal) {
    /* istanbul ignore if */
    if (emitter.emitted[event]) {
      return
    }
    emitter.emitted[event] = true
    emitter.emit(event, code, signal)
  }

  // { <signal>: <listener fn>, ... }
  var sigListeners = {}
  signals.forEach(function (sig) {
    sigListeners[sig] = function listener () {
      /* istanbul ignore if */
      if (!processOk(global.process)) {
        return
      }
      // If there are no other listeners, an exit is coming!
      // Simplest way: remove us and then re-send the signal.
      // We know that this will kill the process, so we can
      // safely emit now.
      var listeners = process.listeners(sig)
      if (listeners.length === emitter.count) {
        unload()
        emit('exit', null, sig)
        /* istanbul ignore next */
        emit('afterexit', null, sig)
        /* istanbul ignore next */
        if (isWin && sig === 'SIGHUP') {
          // "SIGHUP" throws an `ENOSYS` error on Windows,
          // so use a supported signal instead
          sig = 'SIGINT'
        }
        /* istanbul ignore next */
        process.kill(process.pid, sig)
      }
    }
  })

  module.exports.signals = function () {
    return signals
  }

  var loaded = false

  var load = function load () {
    if (loaded || !processOk(global.process)) {
      return
    }
    loaded = true

    // This is the number of onSignalExit's that are in play.
    // It's important so that we can count the correct number of
    // listeners on signals, and don't wait for the other one to
    // handle it instead of us.
    emitter.count += 1

    signals = signals.filter(function (sig) {
      try {
        process.on(sig, sigListeners[sig])
        return true
      } catch (er) {
        return false
      }
    })

    process.emit = processEmit
    process.reallyExit = processReallyExit
  }
  module.exports.load = load

  var originalProcessReallyExit = process.reallyExit
  var processReallyExit = function processReallyExit (code) {
    /* istanbul ignore if */
    if (!processOk(global.process)) {
      return
    }
    process.exitCode = code || /* istanbul ignore next */ 0
    emit('exit', process.exitCode, null)
    /* istanbul ignore next */
    emit('afterexit', process.exitCode, null)
    /* istanbul ignore next */
    originalProcessReallyExit.call(process, process.exitCode)
  }

  var originalProcessEmit = process.emit
  var processEmit = function processEmit (ev, arg) {
    if (ev === 'exit' && processOk(global.process)) {
      /* istanbul ignore else */
      if (arg !== undefined) {
        process.exitCode = arg
      }
      var ret = originalProcessEmit.apply(this, arguments)
      /* istanbul ignore next */
      emit('exit', process.exitCode, null)
      /* istanbul ignore next */
      emit('afterexit', process.exitCode, null)
      /* istanbul ignore next */
      return ret
    } else {
      return originalProcessEmit.apply(this, arguments)
    }
  }
}


signal-exit

description: when you want to fire an event no matter how a process exits.

test: tap

snap: tap

preversion: npm test

postversion: npm publish

prepublishOnly: git push origin --follow-tags

keywords: signal exit

author: Ben Coe <ben@npmjs.com>

license: ISC


code:
// This is not the set of all possible signals.
//
// It IS, however, the set of all signals that trigger
// an exit on either Linux or BSD systems.  Linux is a
// superset of the signal names supported on BSD, and
// the unknown signals just fail to register, so we can
// catch that easily enough.
//
// Don't bother with SIGKILL.  It's uncatchable, which
// means that we can't fire any callbacks anyway.
//
// If a user does happen to register a handler on a non-
// fatal signal like SIGWINCH or something, and then
// exit, it'll end up firing `process.emit('exit')`, so
// the handler will be fired anyway.
//
// SIGBUS, SIGFPE, SIGSEGV and SIGILL, when not raised
// artificially, inherently leave the process in a
// state from which it is not safe to try and enter JS
// listeners.
module.exports = [
  'SIGABRT',
  'SIGALRM',
  'SIGHUP',
  'SIGINT',
  'SIGTERM'
]

if (process.platform !== 'win32') {
  module.exports.push(
    'SIGVTALRM',
    'SIGXCPU',
    'SIGXFSZ',
    'SIGUSR2',
    'SIGTRAP',
    'SIGSYS',
    'SIGQUIT',
    'SIGIOT'
    // should detect profiler and enable/disable accordingly.
    // see #21
    // 'SIGPROF'
  )
}

if (process.platform === 'linux') {
  module.exports.push(
    'SIGIO',
    'SIGPOLL',
    'SIGPWR',
    'SIGSTKFLT',
    'SIGUNUSED'
  )
}


code:
const fs = require('fs');
const { join, normalize, resolve } = require('path');
const { totalist } = require('totalist/sync');
const { parse } = require('@polka/url');
const { lookup } = require('mrmime');

const noop = () => {};

function isMatch(uri, arr) {
	for (let i=0; i < arr.length; i++) {
		if (arr[i].test(uri)) return true;
	}
}

function toAssume(uri, extns) {
	let i=0, x, len=uri.length - 1;
	if (uri.charCodeAt(len) === 47) {
		uri = uri.substring(0, len);
	}

	let arr=[], tmp=`${uri}/index`;
	for (; i < extns.length; i++) {
		x = extns[i] ? `.${extns[i]}` : '';
		if (uri) arr.push(uri + x);
		arr.push(tmp + x);
	}

	return arr;
}

function viaCache(cache, uri, extns) {
	let i=0, data, arr=toAssume(uri, extns);
	for (; i < arr.length; i++) {
		if (data = cache[arr[i]]) return data;
	}
}

function viaLocal(dir, isEtag, uri, extns) {
	let i=0, arr=toAssume(uri, extns);
	let abs, stats, name, headers;
	for (; i < arr.length; i++) {
		abs = normalize(join(dir, name=arr[i]));
		if (abs.startsWith(dir) && fs.existsSync(abs)) {
			stats = fs.statSync(abs);
			if (stats.isDirectory()) continue;
			headers = toHeaders(name, stats, isEtag);
			headers['Cache-Control'] = isEtag ? 'no-cache' : 'no-store';
			return { abs, stats, headers };
		}
	}
}

function is404(req, res) {
	return (res.statusCode=404,res.end());
}

function send(req, res, file, stats, headers) {
	let code=200, tmp, opts={};
	headers = { ...headers };

	for (let key in headers) {
		tmp = res.getHeader(key);
		if (tmp) headers[key] = tmp;
	}

	if (tmp = res.getHeader('content-type')) {
		headers['Content-Type'] = tmp;
	}

	if (req.headers.range) {
		code = 206;
		let [x, y] = req.headers.range.replace('bytes=', '').split('-');
		let end = opts.end = parseInt(y, 10) || stats.size - 1;
		let start = opts.start = parseInt(x, 10) || 0;

		if (end >= stats.size) {
			end = stats.size - 1;
		}

		if (start >= stats.size) {
			res.setHeader('Content-Range', `bytes */${stats.size}`);
			res.statusCode = 416;
			return res.end();
		}

		headers['Content-Range'] = `bytes ${start}-${end}/${stats.size}`;
		headers['Content-Length'] = (end - start + 1);
		headers['Accept-Ranges'] = 'bytes';
	}

	res.writeHead(code, headers);
	fs.createReadStream(file, opts).pipe(res);
}

const ENCODING = {
	'.br': 'br',
	'.gz': 'gzip',
};

function toHeaders(name, stats, isEtag) {
	let enc = ENCODING[name.slice(-3)];

	let ctype = lookup(name.slice(0, enc && -3)) || '';
	if (ctype === 'text/html') ctype += ';charset=utf-8';

	let headers = {
		'Content-Length': stats.size,
		'Content-Type': ctype,
		'Last-Modified': stats.mtime.toUTCString(),
	};

	if (enc) headers['Content-Encoding'] = enc;
	if (isEtag) headers['ETag'] = `W/"${stats.size}-${stats.mtime.getTime()}"`;

	return headers;
}

module.exports = function (dir, opts={}) {
	dir = resolve(dir || '.');

	let isNotFound = opts.onNoMatch || is404;
	let setHeaders = opts.setHeaders || noop;

	let extensions = opts.extensions || ['html', 'htm'];
	let gzips = opts.gzip && extensions.map(x => `${x}.gz`).concat('gz');
	let brots = opts.brotli && extensions.map(x => `${x}.br`).concat('br');

	const FILES = {};

	let fallback = '/';
	let isEtag = !!opts.etag;
	let isSPA = !!opts.single;
	if (typeof opts.single === 'string') {
		let idx = opts.single.lastIndexOf('.');
		fallback += !!~idx ? opts.single.substring(0, idx) : opts.single;
	}

	let ignores = [];
	if (opts.ignores !== false) {
		ignores.push(/[/]([A-Za-z\s\d~$._-]+\.\w+){1,}$/); // any extn
		if (opts.dotfiles) ignores.push(/\/\.\w/);
		else ignores.push(/\/\.well-known/);
		[].concat(opts.ignores || []).forEach(x => {
			ignores.push(new RegExp(x, 'i'));
		});
	}

	let cc = opts.maxAge != null && `public,max-age=${opts.maxAge}`;
	if (cc && opts.immutable) cc += ',immutable';
	else if (cc && opts.maxAge === 0) cc += ',must-revalidate';

	if (!opts.dev) {
		totalist(dir, (name, abs, stats) => {
			if (/\.well-known[\\+\/]/.test(name)) {} // keep
			else if (!opts.dotfiles && /(^\.|[\\+|\/+]\.)/.test(name)) return;

			let headers = toHeaders(name, stats, isEtag);
			if (cc) headers['Cache-Control'] = cc;

			FILES['/' + name.normalize().replace(/\\+/g, '/')] = { abs, stats, headers };
		});
	}

	let lookup = opts.dev ? viaLocal.bind(0, dir, isEtag) : viaCache.bind(0, FILES);

	return function (req, res, next) {
		let extns = [''];
		let pathname = parse(req).pathname;
		let val = req.headers['accept-encoding'] || '';
		if (gzips && val.includes('gzip')) extns.unshift(...gzips);
		if (brots && /(br|brotli)/i.test(val)) extns.unshift(...brots);
		extns.push(...extensions); // [...br, ...gz, orig, ...exts]

		if (pathname.indexOf('%') !== -1) {
			try { pathname = decodeURI(pathname) }
			catch (err) { /* malform uri */ }
		}

		let data = lookup(pathname, extns) || isSPA && !isMatch(pathname, ignores) && lookup(fallback, extns);
		if (!data) return next ? next() : isNotFound(req, res);

		if (isEtag && req.headers['if-none-match'] === data.headers['ETag']) {
			res.writeHead(304);
			return res.end();
		}

		if (gzips || brots) {
			res.setHeader('Vary', 'Accept-Encoding');
		}

		setHeaders(res, pathname, data.stats);
		send(req, res, data.abs, data.stats, data.headers);
	};
}


code:
import * as fs from 'fs';
import { join, normalize, resolve } from 'path';
import { totalist } from 'totalist/sync';
import { parse } from '@polka/url';
import { lookup } from 'mrmime';

const noop = () => {};

function isMatch(uri, arr) {
	for (let i=0; i < arr.length; i++) {
		if (arr[i].test(uri)) return true;
	}
}

function toAssume(uri, extns) {
	let i=0, x, len=uri.length - 1;
	if (uri.charCodeAt(len) === 47) {
		uri = uri.substring(0, len);
	}

	let arr=[], tmp=`${uri}/index`;
	for (; i < extns.length; i++) {
		x = extns[i] ? `.${extns[i]}` : '';
		if (uri) arr.push(uri + x);
		arr.push(tmp + x);
	}

	return arr;
}

function viaCache(cache, uri, extns) {
	let i=0, data, arr=toAssume(uri, extns);
	for (; i < arr.length; i++) {
		if (data = cache[arr[i]]) return data;
	}
}

function viaLocal(dir, isEtag, uri, extns) {
	let i=0, arr=toAssume(uri, extns);
	let abs, stats, name, headers;
	for (; i < arr.length; i++) {
		abs = normalize(join(dir, name=arr[i]));
		if (abs.startsWith(dir) && fs.existsSync(abs)) {
			stats = fs.statSync(abs);
			if (stats.isDirectory()) continue;
			headers = toHeaders(name, stats, isEtag);
			headers['Cache-Control'] = isEtag ? 'no-cache' : 'no-store';
			return { abs, stats, headers };
		}
	}
}

function is404(req, res) {
	return (res.statusCode=404,res.end());
}

function send(req, res, file, stats, headers) {
	let code=200, tmp, opts={};
	headers = { ...headers };

	for (let key in headers) {
		tmp = res.getHeader(key);
		if (tmp) headers[key] = tmp;
	}

	if (tmp = res.getHeader('content-type')) {
		headers['Content-Type'] = tmp;
	}

	if (req.headers.range) {
		code = 206;
		let [x, y] = req.headers.range.replace('bytes=', '').split('-');
		let end = opts.end = parseInt(y, 10) || stats.size - 1;
		let start = opts.start = parseInt(x, 10) || 0;

		if (end >= stats.size) {
			end = stats.size - 1;
		}

		if (start >= stats.size) {
			res.setHeader('Content-Range', `bytes */${stats.size}`);
			res.statusCode = 416;
			return res.end();
		}

		headers['Content-Range'] = `bytes ${start}-${end}/${stats.size}`;
		headers['Content-Length'] = (end - start + 1);
		headers['Accept-Ranges'] = 'bytes';
	}

	res.writeHead(code, headers);
	fs.createReadStream(file, opts).pipe(res);
}

const ENCODING = {
	'.br': 'br',
	'.gz': 'gzip',
};

function toHeaders(name, stats, isEtag) {
	let enc = ENCODING[name.slice(-3)];

	let ctype = lookup(name.slice(0, enc && -3)) || '';
	if (ctype === 'text/html') ctype += ';charset=utf-8';

	let headers = {
		'Content-Length': stats.size,
		'Content-Type': ctype,
		'Last-Modified': stats.mtime.toUTCString(),
	};

	if (enc) headers['Content-Encoding'] = enc;
	if (isEtag) headers['ETag'] = `W/"${stats.size}-${stats.mtime.getTime()}"`;

	return headers;
}

export default function (dir, opts={}) {
	dir = resolve(dir || '.');

	let isNotFound = opts.onNoMatch || is404;
	let setHeaders = opts.setHeaders || noop;

	let extensions = opts.extensions || ['html', 'htm'];
	let gzips = opts.gzip && extensions.map(x => `${x}.gz`).concat('gz');
	let brots = opts.brotli && extensions.map(x => `${x}.br`).concat('br');

	const FILES = {};

	let fallback = '/';
	let isEtag = !!opts.etag;
	let isSPA = !!opts.single;
	if (typeof opts.single === 'string') {
		let idx = opts.single.lastIndexOf('.');
		fallback += !!~idx ? opts.single.substring(0, idx) : opts.single;
	}

	let ignores = [];
	if (opts.ignores !== false) {
		ignores.push(/[/]([A-Za-z\s\d~$._-]+\.\w+){1,}$/); // any extn
		if (opts.dotfiles) ignores.push(/\/\.\w/);
		else ignores.push(/\/\.well-known/);
		[].concat(opts.ignores || []).forEach(x => {
			ignores.push(new RegExp(x, 'i'));
		});
	}

	let cc = opts.maxAge != null && `public,max-age=${opts.maxAge}`;
	if (cc && opts.immutable) cc += ',immutable';
	else if (cc && opts.maxAge === 0) cc += ',must-revalidate';

	if (!opts.dev) {
		totalist(dir, (name, abs, stats) => {
			if (/\.well-known[\\+\/]/.test(name)) {} // keep
			else if (!opts.dotfiles && /(^\.|[\\+|\/+]\.)/.test(name)) return;

			let headers = toHeaders(name, stats, isEtag);
			if (cc) headers['Cache-Control'] = cc;

			FILES['/' + name.normalize().replace(/\\+/g, '/')] = { abs, stats, headers };
		});
	}

	let lookup = opts.dev ? viaLocal.bind(0, dir, isEtag) : viaCache.bind(0, FILES);

	return function (req, res, next) {
		let extns = [''];
		let pathname = parse(req).pathname;
		let val = req.headers['accept-encoding'] || '';
		if (gzips && val.includes('gzip')) extns.unshift(...gzips);
		if (brots && /(br|brotli)/i.test(val)) extns.unshift(...brots);
		extns.push(...extensions); // [...br, ...gz, orig, ...exts]

		if (pathname.indexOf('%') !== -1) {
			try { pathname = decodeURI(pathname) }
			catch (err) { /* malform uri */ }
		}

		let data = lookup(pathname, extns) || isSPA && !isMatch(pathname, ignores) && lookup(fallback, extns);
		if (!data) return next ? next() : isNotFound(req, res);

		if (isEtag && req.headers['if-none-match'] === data.headers['ETag']) {
			res.writeHead(304);
			return res.end();
		}

		if (gzips || brots) {
			res.setHeader('Vary', 'Accept-Encoding');
		}

		setHeaders(res, pathname, data.stats);
		send(req, res, data.abs, data.stats, data.headers);
	};
}


sirv

description: The optimized & lightweight middleware for serving requests to static assets

repository: lukeed/sirv


code:
# sirv ![CI](https://github.com/lukeed/sirv/workflows/CI/badge.svg)

> The optimized and lightweight middleware for serving requests to static assets

You may use `sirv` as a *very* fast and lightweight alternative to [`serve-static`](https://www.npmjs.com/package/serve-static).

The massive performance advantage over `serve-static` is explained by **not** relying on the file system for existence checks on every request. These are expensive interactions and must be avoided whenever possible! Instead, when not in "dev" mode, `sirv` performs all its file-system operations upfront and then relies on its cache for future operations.

This middleware will work out of the box for [Polka](https://github.com/lukeed/polka), Express, and other Express-like frameworks. It will also work with the native `http`, `https` and `http2` modules. It requires _very_ little effort to modify/wrap it for servers that don't accept the `(req, res, next)` signature.

:bulb: For a feature-complete CLI application, check out the sibling [`sirv-cli`](https://github.com/lukeed/sirv/tree/master/packages/sirv-cli) package as an alternative to [`zeit/serve`](https://github.com/zeit/serve)~!

## Install

```
$ npm install --save sirv
```

## Usage

```js
const sirv = require('sirv');
const polka = require('polka');
const compress = require('compression')();

// Init `sirv` handler
const assets = sirv('public', {
  maxAge: 31536000, // 1Y
  immutable: true
});

polka()
  .use(compress, assets)
  .use('/api', require('./api'))
  .listen(3000, err => {
    if (err) throw err;
    console.log('> Ready on localhost:3000~!');
  });
```

## API

### sirv(dir, opts={})

Returns: `Function`

The returned function is a middleware in the standard Express-like signature: `(req, res, next)`, where `req` is the [`http.IncomingMessage`](https://nodejs.org/api/http.html#http_class_http_incomingmessage), `res` is the [`http.ServerResponse`](https://nodejs.org/dist/latest-v9.x/docs/api/http.html#http_class_http_serverresponse), and `next` (in this case) is the function to call if no file was found for the given path.

When defined, a `next()` callback is always called _instead of_ the [`opts.onNoMatch`](#optsonnomatch) callback. However, unlike `onNoMatch`, your `next()` is given no arguments.

#### dir
Type: `String`

Default: `.`

The directory from which to read and serve assets. It is resolved to an absolute path — you must provide an absolute path yourself if `process.cwd()` is not the correct assumption.

#### opts.dev
Type: `Boolean`

Default: `false`

Enable "dev" mode, which disables/skips caching. Instead, `sirv` will traverse the file system ***on every request***.

Additionally, `dev` mode will ignore `maxAge` and `immutable` as these options generate a production-oriented `Cache-Control` header value.

> **Important:** Do not use `dev` mode in production!

#### opts.etag
Type: `Boolean`

Default: `false`

Generate and attach an `ETag` header to responses.

> **Note:** If an incoming request's [`If-None-Match` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match) matches the `ETag` value, a `304` response is given.

#### opts.dotfiles
Type: `Boolean`

Default: `false`

Allow requests to dotfiles (files or directories beginning with a `.`).

> **Note:** Requests to [`/.well-known/*`](https://tools.ietf.org/html/rfc8615) are always allowed.

#### opts.extensions
Type: `Array<String>`

Default: `['html', 'htm']`

The file extension fallbacks to check for if a pathame is not initially found. For example, if a `/login` request cannot find a `login` filename, it will then look for `login.html` and `login.htm` before giving up~!

> **Important:** Actually, `sirv` will **also** look for `login/index.html` and `login/index.htm` before giving up.

#### opts.gzip
Type: `Boolean`

Default: `false`

Determine if `sirv` look for **precompiled** `*.gz` files.

Must be enabled _and_ the incoming request's [`Accept Encoding`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding) must include "gzip" in order for `sirv` to search for the gzip'd alternative.

> **Note:** The `.gz` assumption also applies to the `opts.extensions` list.

```js
// NOTE: PSEUDO CODE
// Showing lookup logic

// Request: [Accept-Encoding: gzip] "/foobar.jpg"
lookup([
  '/foobar.jpg.gz', '/foobar.jpg',
  '/foobar.jpg.html.gz', '/foobar.jpg/index.html.gz',
  '/foobar.jpg.htm.gz', '/foobar.jpg/index.htm.gz',
  '/foobar.jpg.html', '/foobar.jpg/index.html',
  '/foobar.jpg.htm', '/foobar.jpg/index.htm',
]);

// Request: [Accept-Encoding: gzip] "/"
lookup([
  '/index.html.gz',
  '/index.htm.gz',
  '/index.html',
  '/index.htm',
]);
```

#### opts.brotli
Type: `Boolean`

Default: `false`

Determine if `sirv` look for **precompiled** `*.br` files.

Must be enabled _and_ the incoming request's [`Accept Encoding`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding) must include either "br" or "brotli" in order for `sirv` to search for the brotli-compressed alternative.

> **Note:** The `.br` assumption also applies to the `opts.extensions` list.

When both `opts.broli` and `opts.gzip` are enabled — and all conditions are equal — then the brotli variant always takes priority.

```js
// NOTE: PSEUDO CODE
// Showing lookup logic

// Request: [Accept-Encoding: br] "/foobar.jpg"
lookup([
  '/foobar.jpg.br', '/foobar.jpg',
  '/foobar.jpg.html.br', '/foobar.jpg/index.html.br',
  '/foobar.jpg.htm.br', '/foobar.jpg/index.htm.br',
  '/foobar.jpg.html', '/foobar.jpg/index.html',
  '/foobar.jpg.htm', '/foobar.jpg/index.htm',
]);

// Request: [Accept-Encoding: br,gz] "/"
lookup([
  '/index.html.br'
  '/index.htm.br'
  '/index.html.gz'
  '/index.htm.gz'
  '/index.html'
  '/index.htm'
]);
```

#### opts.maxAge
Type: `Number`

Default: `undefined`

Enables the `Cache-Control` header on responses and sets the `max-age` value (in seconds).

For example, `maxAge: 31536000` is equivalent to one year.

#### opts.immutable
Type: `Boolean`

Default: `false`

Appends the [`immutable` directive](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#Revalidation_and_reloading) on your `Cache-Control` header, used for uniquely-named assets that will not change!

> **Important:** Will only work if `opts.maxAge` has a value defined!

#### opts.single
Type: `Boolean` or `String`

Default: `false`

Treat the directory as a single-page application.

When `true`, the directory's index page (default `index.html`) will be sent if the request asset does not exist.

You may pass a `string` value to use a file _instead of_ `index.html` as your fallback.

For example, if "/about" is requested but no variants of that file exist, then the response for "/" is sent instead:

```js
// Note: This is psuedo code to illustrate what's happening

// Request: "/about"
let file = find(['/about', '/about.html', '/about.htm', '/about/index.html', '/about.htm']);
if (file) {
  send(file);
} else if (opts.single === true) {
  file = find(['/', '/index.html', '/index.htm']);
  send(file);
} else if (typeof opts.single === 'string') {
  file = find([opts.single]);
  send(file);
} else {
  // next() or 404
}
```

#### opts.ignores
Type: `false` or `Array<String | RegExp>`

Specify paths/patterns that should ignore the fallback behavior that `opts.single` provides.

By default, any asset-like path (URLs that end with an extension) will be ignored. This means that, for example, if `/foobar.jpg` is not found, a `404` response is sent instead of the `index.html` fallback.

Additionally, any `/.well-known/*` pathname ignores the fallback – as do all other dotfile requests when `opts.dotfiles` is enabled.

Any string value(s) will be passed through `new RegExp(value, 'i')` directly.

Finally, you may set `ignores: false` to disable ***all*** ignores, including the defaults. Put differently, this will fallback ***all*** unknown pathnames to your `index.html` (or custom `opts.single` value).

> **Important:** Only has an effect if `opts.single` is enabled.

#### opts.onNoMatch
Type: `Function`

A custom function to run if a file cannot be found for a given request.
By default, `sirv` will send a basic `(404) Not found` response.

The function receives the current `req <IncomingMessage>, res <ServerResponse>` pair for as its two arguments.

> **Note:** This won't run if a `next` callback has been provided to the middleware; see [`sirv`](#sirvdir-opts) description.

#### opts.setHeaders
Type: `Function`

A custom function to append or change any headers on the outgoing response. There is no default.

Its signature is `(res, pathname, stats)`, where `res` is the `ServerResponse`, `pathname` is incoming request path (stripped of queries), and `stats` is the file's result from [`fs.statSync`](https://nodejs.org/api/fs.html#fs_fs_statsync_path).

## License

MIT © [Luke Edwards](https://lukeed.com)


code:
declare module 'sirv' {
	import type { Stats } from 'fs';
	import type { IncomingMessage, ServerResponse } from 'http';

	type Arrayable<T> = T | T[];
	export type NextHandler = () => void | Promise<void>;
	export type RequestHandler = (req: IncomingMessage, res: ServerResponse, next?: NextHandler) => void;

	export interface Options {
		dev?: boolean;
		etag?: boolean;
		maxAge?: number;
		immutable?: boolean;
		single?: string | boolean;
		ignores?: false | Arrayable<string | RegExp>;
		extensions?: string[];
		dotfiles?: boolean;
		brotli?: boolean;
		gzip?: boolean;
		onNoMatch?: (req: IncomingMessage, res: ServerResponse) => void;
		setHeaders?: (res: ServerResponse, pathname: string, stats: Stats) => void;
	}

	export default function(dir?: string, opts?: Options): RequestHandler;
}


code:
/**
Convert Windows backslash paths to slash paths: `foo\\bar` ➔ `foo/bar`.

[Forward-slash paths can be used in Windows](http://superuser.com/a/176395/6877) as long as they're not extended-length paths and don't contain any non-ascii characters.

@param path - A Windows backslash path.
@returns A path with forward slashes.

@example
```
import * as path from 'path';
import slash = require('slash');

const string = path.join('foo', 'bar');
// Unix    => foo/bar
// Windows => foo\\bar

slash(string);
// Unix    => foo/bar
// Windows => foo/bar
```
*/
declare function slash(path: string): string;

export = slash;


code:
'use strict';
module.exports = path => {
	const isExtendedLengthPath = /^\\\\\?\\/.test(path);
	const hasNonAscii = /[^\u0000-\u0080]+/.test(path); // eslint-disable-line no-control-regex

	if (isExtendedLengthPath || hasNonAscii) {
		return path;
	}

	return path.replace(/\\/g, '/');
};


slash

description: Convert Windows backslash paths to slash paths

repository: sindresorhus/slash

test: xo && ava && tsd

keywords: path seperator slash backslash windows convert


code:
# slash [![Build Status](https://travis-ci.org/sindresorhus/slash.svg?branch=master)](https://travis-ci.org/sindresorhus/slash)

> Convert Windows backslash paths to slash paths: `foo\\bar` ➔ `foo/bar`

[Forward-slash paths can be used in Windows](http://superuser.com/a/176395/6877) as long as they're not extended-length paths and don't contain any non-ascii characters.

This was created since the `path` methods in Node.js outputs `\\` paths on Windows.

## Install

```
$ npm install slash
```

## Usage

```js
const path = require('path');
const slash = require('slash');

const string = path.join('foo', 'bar');
// Unix    => foo/bar
// Windows => foo\\bar

slash(string);
// Unix    => foo/bar
// Windows => foo/bar
```

## API

### slash(path)

Type: `string`

Accepts a Windows backslash path and returns a path with forward slashes.

## License

MIT © [Sindre Sorhus](https://sindresorhus.com)


code:
import isFullwidthCodePoint from 'is-fullwidth-code-point';
import ansiStyles from 'ansi-styles';

const astralRegex = /^[\uD800-\uDBFF][\uDC00-\uDFFF]$/;

const ESCAPES = [
	'\u001B',
	'\u009B'
];

const wrapAnsi = code => `${ESCAPES[0]}[${code}m`;

const checkAnsi = (ansiCodes, isEscapes, endAnsiCode) => {
	let output = [];
	ansiCodes = [...ansiCodes];

	for (let ansiCode of ansiCodes) {
		const ansiCodeOrigin = ansiCode;
		if (ansiCode.includes(';')) {
			ansiCode = ansiCode.split(';')[0][0] + '0';
		}

		const item = ansiStyles.codes.get(Number.parseInt(ansiCode, 10));
		if (item) {
			const indexEscape = ansiCodes.indexOf(item.toString());
			if (indexEscape === -1) {
				output.push(wrapAnsi(isEscapes ? item : ansiCodeOrigin));
			} else {
				ansiCodes.splice(indexEscape, 1);
			}
		} else if (isEscapes) {
			output.push(wrapAnsi(0));
			break;
		} else {
			output.push(wrapAnsi(ansiCodeOrigin));
		}
	}

	if (isEscapes) {
		output = output.filter((element, index) => output.indexOf(element) === index);

		if (endAnsiCode !== undefined) {
			const fistEscapeCode = wrapAnsi(ansiStyles.codes.get(Number.parseInt(endAnsiCode, 10)));
			// TODO: Remove the use of `.reduce` here.
			// eslint-disable-next-line unicorn/no-array-reduce
			output = output.reduce((current, next) => next === fistEscapeCode ? [next, ...current] : [...current, next], []);
		}
	}

	return output.join('');
};

export default function sliceAnsi(string, begin, end) {
	const characters = [...string];
	const ansiCodes = [];

	let stringEnd = typeof end === 'number' ? end : characters.length;
	let isInsideEscape = false;
	let ansiCode;
	let visible = 0;
	let output = '';

	for (const [index, character] of characters.entries()) {
		let leftEscape = false;

		if (ESCAPES.includes(character)) {
			const code = /\d[^m]*/.exec(string.slice(index, index + 18));
			ansiCode = code && code.length > 0 ? code[0] : undefined;

			if (visible < stringEnd) {
				isInsideEscape = true;

				if (ansiCode !== undefined) {
					ansiCodes.push(ansiCode);
				}
			}
		} else if (isInsideEscape && character === 'm') {
			isInsideEscape = false;
			leftEscape = true;
		}

		if (!isInsideEscape && !leftEscape) {
			visible++;
		}

		if (!astralRegex.test(character) && isFullwidthCodePoint(character.codePointAt())) {
			visible++;

			if (typeof end !== 'number') {
				stringEnd++;
			}
		}

		if (visible > begin && visible <= stringEnd) {
			output += character;
		} else if (visible === begin && !isInsideEscape && ansiCode !== undefined) {
			output = checkAnsi(ansiCodes);
		} else if (visible >= stringEnd) {
			output += checkAnsi(ansiCodes, true, ansiCode);
			break;
		}
	}

	return output;
}


code:
export interface CSPair { // eslint-disable-line @typescript-eslint/naming-convention
	/**
	The ANSI terminal control sequence for starting this style.
	*/
	readonly open: string;

	/**
	The ANSI terminal control sequence for ending this style.
	*/
	readonly close: string;
}

export interface ColorBase {
	/**
	The ANSI terminal control sequence for ending this color.
	*/
	readonly close: string;

	ansi(code: number): string;

	ansi256(code: number): string;

	ansi16m(red: number, green: number, blue: number): string;
}

export interface Modifier {
	/**
	Resets the current color chain.
	*/
	readonly reset: CSPair;

	/**
	Make text bold.
	*/
	readonly bold: CSPair;

	/**
	Emitting only a small amount of light.
	*/
	readonly dim: CSPair;

	/**
	Make text italic. (Not widely supported)
	*/
	readonly italic: CSPair;

	/**
	Make text underline. (Not widely supported)
	*/
	readonly underline: CSPair;

	/**
	Make text overline.

	Supported on VTE-based terminals, the GNOME terminal, mintty, and Git Bash.
	*/
	readonly overline: CSPair;

	/**
	Inverse background and foreground colors.
	*/
	readonly inverse: CSPair;

	/**
	Prints the text, but makes it invisible.
	*/
	readonly hidden: CSPair;

	/**
	Puts a horizontal line through the center of the text. (Not widely supported)
	*/
	readonly strikethrough: CSPair;
}

export interface ForegroundColor {
	readonly black: CSPair;
	readonly red: CSPair;
	readonly green: CSPair;
	readonly yellow: CSPair;
	readonly blue: CSPair;
	readonly cyan: CSPair;
	readonly magenta: CSPair;
	readonly white: CSPair;

	/**
	Alias for `blackBright`.
	*/
	readonly gray: CSPair;

	/**
	Alias for `blackBright`.
	*/
	readonly grey: CSPair;

	readonly blackBright: CSPair;
	readonly redBright: CSPair;
	readonly greenBright: CSPair;
	readonly yellowBright: CSPair;
	readonly blueBright: CSPair;
	readonly cyanBright: CSPair;
	readonly magentaBright: CSPair;
	readonly whiteBright: CSPair;
}

export interface BackgroundColor {
	readonly bgBlack: CSPair;
	readonly bgRed: CSPair;
	readonly bgGreen: CSPair;
	readonly bgYellow: CSPair;
	readonly bgBlue: CSPair;
	readonly bgCyan: CSPair;
	readonly bgMagenta: CSPair;
	readonly bgWhite: CSPair;

	/**
	Alias for `bgBlackBright`.
	*/
	readonly bgGray: CSPair;

	/**
	Alias for `bgBlackBright`.
	*/
	readonly bgGrey: CSPair;

	readonly bgBlackBright: CSPair;
	readonly bgRedBright: CSPair;
	readonly bgGreenBright: CSPair;
	readonly bgYellowBright: CSPair;
	readonly bgBlueBright: CSPair;
	readonly bgCyanBright: CSPair;
	readonly bgMagentaBright: CSPair;
	readonly bgWhiteBright: CSPair;
}

export interface ConvertColor {
	/**
	Convert from the RGB color space to the ANSI 256 color space.

	@param red - (`0...255`)
	@param green - (`0...255`)
	@param blue - (`0...255`)
	*/
	rgbToAnsi256(red: number, green: number, blue: number): number;

	/**
	Convert from the RGB HEX color space to the RGB color space.

	@param hex - A hexadecimal string containing RGB data.
	*/
	hexToRgb(hex: string): [red: number, green: number, blue: number];

	/**
	Convert from the RGB HEX color space to the ANSI 256 color space.

	@param hex - A hexadecimal string containing RGB data.
	*/
	hexToAnsi256(hex: string): number;

	/**
	Convert from the ANSI 256 color space to the ANSI 16 color space.

	@param code - A number representing the ANSI 256 color.
	*/
	ansi256ToAnsi(code: number): number;

	/**
	Convert from the RGB color space to the ANSI 16 color space.

	@param red - (`0...255`)
	@param green - (`0...255`)
	@param blue - (`0...255`)
	*/
	rgbToAnsi(red: number, green: number, blue: number): number;

	/**
	Convert from the RGB HEX color space to the ANSI 16 color space.

	@param hex - A hexadecimal string containing RGB data.
	*/
	hexToAnsi(hex: string): number;
}

/**
Basic modifier names.
*/
export type ModifierName = keyof Modifier;

/**
Basic foreground color names.

[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support)
*/
export type ForegroundColorName = keyof ForegroundColor;

/**
Basic background color names.

[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support)
*/
export type BackgroundColorName = keyof BackgroundColor;

/**
Basic color names. The combination of foreground and background color names.

[More colors here.](https://github.com/chalk/chalk/blob/main/readme.md#256-and-truecolor-color-support)
*/
export type ColorName = ForegroundColorName | BackgroundColorName;

/**
Basic modifier names.
*/
export const modifierNames: readonly ModifierName[];

/**
Basic foreground color names.
*/
export const foregroundColorNames: readonly ForegroundColorName[];

/**
Basic background color names.
*/
export const backgroundColorNames: readonly BackgroundColorName[];

/*
Basic color names. The combination of foreground and background color names.
*/
export const colorNames: readonly ColorName[];

declare const ansiStyles: {
	readonly modifier: Modifier;
	readonly color: ColorBase & ForegroundColor;
	readonly bgColor: ColorBase & BackgroundColor;
	readonly codes: ReadonlyMap<number, number>;
} & ForegroundColor & BackgroundColor & Modifier & ConvertColor;

export default ansiStyles;


code:
const ANSI_BACKGROUND_OFFSET = 10;

const wrapAnsi16 = (offset = 0) => code => `\u001B[${code + offset}m`;

const wrapAnsi256 = (offset = 0) => code => `\u001B[${38 + offset};5;${code}m`;

const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`;

const styles = {
	modifier: {
		reset: [0, 0],
		// 21 isn't widely supported and 22 does the same thing
		bold: [1, 22],
		dim: [2, 22],
		italic: [3, 23],
		underline: [4, 24],
		overline: [53, 55],
		inverse: [7, 27],
		hidden: [8, 28],
		strikethrough: [9, 29],
	},
	color: {
		black: [30, 39],
		red: [31, 39],
		green: [32, 39],
		yellow: [33, 39],
		blue: [34, 39],
		magenta: [35, 39],
		cyan: [36, 39],
		white: [37, 39],

		// Bright color
		blackBright: [90, 39],
		gray: [90, 39], // Alias of `blackBright`
		grey: [90, 39], // Alias of `blackBright`
		redBright: [91, 39],
		greenBright: [92, 39],
		yellowBright: [93, 39],
		blueBright: [94, 39],
		magentaBright: [95, 39],
		cyanBright: [96, 39],
		whiteBright: [97, 39],
	},
	bgColor: {
		bgBlack: [40, 49],
		bgRed: [41, 49],
		bgGreen: [42, 49],
		bgYellow: [43, 49],
		bgBlue: [44, 49],
		bgMagenta: [45, 49],
		bgCyan: [46, 49],
		bgWhite: [47, 49],

		// Bright color
		bgBlackBright: [100, 49],
		bgGray: [100, 49], // Alias of `bgBlackBright`
		bgGrey: [100, 49], // Alias of `bgBlackBright`
		bgRedBright: [101, 49],
		bgGreenBright: [102, 49],
		bgYellowBright: [103, 49],
		bgBlueBright: [104, 49],
		bgMagentaBright: [105, 49],
		bgCyanBright: [106, 49],
		bgWhiteBright: [107, 49],
	},
};

export const modifierNames = Object.keys(styles.modifier);
export const foregroundColorNames = Object.keys(styles.color);
export const backgroundColorNames = Object.keys(styles.bgColor);
export const colorNames = [...foregroundColorNames, ...backgroundColorNames];

function assembleStyles() {
	const codes = new Map();

	for (const [groupName, group] of Object.entries(styles)) {
		for (const [styleName, style] of Object.entries(group)) {
			styles[styleName] = {
				open: `\u001B[${style[0]}m`,
				close: `\u001B[${style[1]}m`,
			};

			group[styleName] = styles[styleName];

			codes.set(style[0], style[1]);
		}

		Object.defineProperty(styles, groupName, {
			value: group,
			enumerable: false,
		});
	}

	Object.defineProperty(styles, 'codes', {
		value: codes,
		enumerable: false,
	});

	styles.color.close = '\u001B[39m';
	styles.bgColor.close = '\u001B[49m';

	styles.color.ansi = wrapAnsi16();
	styles.color.ansi256 = wrapAnsi256();
	styles.color.ansi16m = wrapAnsi16m();
	styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
	styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
	styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);

	// From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js
	Object.defineProperties(styles, {
		rgbToAnsi256: {
			value: (red, green, blue) => {
				// We use the extended greyscale palette here, with the exception of
				// black and white. normal palette only has 4 greyscale shades.
				if (red === green && green === blue) {
					if (red < 8) {
						return 16;
					}

					if (red > 248) {
						return 231;
					}

					return Math.round(((red - 8) / 247) * 24) + 232;
				}

				return 16
					+ (36 * Math.round(red / 255 * 5))
					+ (6 * Math.round(green / 255 * 5))
					+ Math.round(blue / 255 * 5);
			},
			enumerable: false,
		},
		hexToRgb: {
			value: hex => {
				const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
				if (!matches) {
					return [0, 0, 0];
				}

				let [colorString] = matches;

				if (colorString.length === 3) {
					colorString = [...colorString].map(character => character + character).join('');
				}

				const integer = Number.parseInt(colorString, 16);

				return [
					/* eslint-disable no-bitwise */
					(integer >> 16) & 0xFF,
					(integer >> 8) & 0xFF,
					integer & 0xFF,
					/* eslint-enable no-bitwise */
				];
			},
			enumerable: false,
		},
		hexToAnsi256: {
			value: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
			enumerable: false,
		},
		ansi256ToAnsi: {
			value: code => {
				if (code < 8) {
					return 30 + code;
				}

				if (code < 16) {
					return 90 + (code - 8);
				}

				let red;
				let green;
				let blue;

				if (code >= 232) {
					red = (((code - 232) * 10) + 8) / 255;
					green = red;
					blue = red;
				} else {
					code -= 16;

					const remainder = code % 36;

					red = Math.floor(code / 36) / 5;
					green = Math.floor(remainder / 6) / 5;
					blue = (remainder % 6) / 5;
				}

				const value = Math.max(red, green, blue) * 2;

				if (value === 0) {
					return 30;
				}

				// eslint-disable-next-line no-bitwise
				let result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red));

				if (value === 2) {
					result += 60;
				}

				return result;
			},
			enumerable: false,
		},
		rgbToAnsi: {
			value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
			enumerable: false,
		},
		hexToAnsi: {
			value: hex => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
			enumerable: false,
		},
	});

	return styles;
}

const ansiStyles = assembleStyles();

export default ansiStyles;


ansi-styles

description: ANSI escape codes for styling strings in the terminal

repository: chalk/ansi-styles

type: module

screenshot: svg-term --command='node screenshot' --out=screenshot.svg --padding=3 --width=55 --height=3 --at=1000 --no-cursor

keywords: ansi styles color colour colors terminal console cli string tty escape formatting rgb 256 shell xterm log logging command-line text


code:
# ansi-styles

> [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors_and_Styles) for styling strings in the terminal

You probably want the higher-level [chalk](https://github.com/chalk/chalk) module for styling your strings.

![](screenshot.png)

## Install

```sh
npm install ansi-styles
```

## Usage

```js
import styles from 'ansi-styles';

console.log(`${styles.green.open}Hello world!${styles.green.close}`);

// Color conversion between 256/truecolor
// NOTE: When converting from truecolor to 256 colors, the original color
//       may be degraded to fit the new color palette. This means terminals
//       that do not support 16 million colors will best-match the
//       original color.
console.log(`${styles.color.ansi(styles.rgbToAnsi(199, 20, 250))}Hello World${styles.color.close}`)
console.log(`${styles.color.ansi256(styles.rgbToAnsi256(199, 20, 250))}Hello World${styles.color.close}`)
console.log(`${styles.color.ansi16m(...styles.hexToRgb('#abcdef'))}Hello World${styles.color.close}`)
```

## API

### `open` and `close`

Each style has an `open` and `close` property.

### `modifierNames`, `foregroundColorNames`, `backgroundColorNames`, and `colorNames`

All supported style strings are exposed as an array of strings for convenience. `colorNames` is the combination of `foregroundColorNames` and `backgroundColorNames`.

This can be useful if you need to validate input:

```js
import {modifierNames, foregroundColorNames} from 'ansi-styles';

console.log(modifierNames.includes('bold'));
//=> true

console.log(foregroundColorNames.includes('pink'));
//=> false
```

## Styles

### Modifiers

- `reset`
- `bold`
- `dim`
- `italic` *(Not widely supported)*
- `underline`
- `overline` *Supported on VTE-based terminals, the GNOME terminal, mintty, and Git Bash.*
- `inverse`
- `hidden`
- `strikethrough` *(Not widely supported)*

### Colors

- `black`
- `red`
- `green`
- `yellow`
- `blue`
- `magenta`
- `cyan`
- `white`
- `blackBright` (alias: `gray`, `grey`)
- `redBright`
- `greenBright`
- `yellowBright`
- `blueBright`
- `magentaBright`
- `cyanBright`
- `whiteBright`

### Background colors

- `bgBlack`
- `bgRed`
- `bgGreen`
- `bgYellow`
- `bgBlue`
- `bgMagenta`
- `bgCyan`
- `bgWhite`
- `bgBlackBright` (alias: `bgGray`, `bgGrey`)
- `bgRedBright`
- `bgGreenBright`
- `bgYellowBright`
- `bgBlueBright`
- `bgMagentaBright`
- `bgCyanBright`
- `bgWhiteBright`

## Advanced usage

By default, you get a map of styles, but the styles are also available as groups. They are non-enumerable so they don't show up unless you access them explicitly. This makes it easier to expose only a subset in a higher-level module.

- `styles.modifier`
- `styles.color`
- `styles.bgColor`

###### Example

```js
import styles from 'ansi-styles';

console.log(styles.color.green.open);
```

Raw escape codes (i.e. without the CSI escape prefix `\u001B[` and render mode postfix `m`) are available under `styles.codes`, which returns a `Map` with the open codes as keys and close codes as values.

###### Example

```js
import styles from 'ansi-styles';

console.log(styles.codes.get(36));
//=> 39
```

## 16 / 256 / 16 million (TrueColor) support

`ansi-styles` allows converting between various color formats and ANSI escapes, with support for 16, 256 and [16 million colors](https://gist.github.com/XVilka/8346728).

The following color spaces are supported:

- `rgb`
- `hex`
- `ansi256`
- `ansi`

To use these, call the associated conversion function with the intended output, for example:

```js
import styles from 'ansi-styles';

styles.color.ansi(styles.rgbToAnsi(100, 200, 15)); // RGB to 16 color ansi foreground code
styles.bgColor.ansi(styles.hexToAnsi('#C0FFEE')); // HEX to 16 color ansi foreground code

styles.color.ansi256(styles.rgbToAnsi256(100, 200, 15)); // RGB to 256 color ansi foreground code
styles.bgColor.ansi256(styles.hexToAnsi256('#C0FFEE')); // HEX to 256 color ansi foreground code

styles.color.ansi16m(100, 200, 15); // RGB to 16 million color foreground code
styles.bgColor.ansi16m(...styles.hexToRgb('#C0FFEE')); // Hex (RGB) to 16 million color foreground code
```

## Related

- [ansi-escapes](https://github.com/sindresorhus/ansi-escapes) - ANSI escape codes for manipulating the terminal

## Maintainers

- [Sindre Sorhus](https://github.com/sindresorhus)
- [Josh Junon](https://github.com/qix-)

## For enterprise

Available as part of the Tidelift Subscription.

The maintainers of `ansi-styles` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-ansi-styles?utm_source=npm-ansi-styles&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)


slice-ansi

description: Slice a string with ANSI escape codes

repository: chalk/slice-ansi

test: xo && ava

keywords: slice string ansi styles color colour colors terminal console cli tty escape formatting rgb 256 shell xterm log logging command-line text


code:
# slice-ansi [![XO: Linted](https://img.shields.io/badge/xo-linted-blue.svg)](https://github.com/xojs/xo)

> Slice a string with [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors_and_Styles)

## Install

```
$ npm install slice-ansi
```

## Usage

```js
import chalk from 'chalk';
import sliceAnsi from 'slice-ansi';

const string = 'The quick brown ' + chalk.red('fox jumped over ') +
	'the lazy ' + chalk.green('dog and then ran away with the unicorn.');

console.log(sliceAnsi(string, 20, 30));
```

## API

### sliceAnsi(string, beginSlice, endSlice?)

#### string

Type: `string`

String with ANSI escape codes. Like one styled by [`chalk`](https://github.com/chalk/chalk).

#### beginSlice

Type: `number`

Zero-based index at which to begin the slice.

#### endSlice

Type: `number`

Zero-based index at which to end the slice.

## Related

- [wrap-ansi](https://github.com/chalk/wrap-ansi) - Wordwrap a string with ANSI escape codes
- [cli-truncate](https://github.com/sindresorhus/cli-truncate) - Truncate a string to a specific width in the terminal
- [chalk](https://github.com/chalk/chalk) - Terminal string styling done right

## Maintainers

- [Sindre Sorhus](https://github.com/sindresorhus)
- [Josh Junon](https://github.com/qix-)

---

		Get professional support for this package with a Tidelift subscription

		Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies.


code:
0.3.24
======
  * Remove excess file from npm package

0.3.23
======
  * Fix `uuid` usage

0.3.22
======
  * Update `uuid`

0.3.21
======
  * Update `faye-websocket` and `websocket-driver` to address DDoS vulnerability #275

0.3.20
======
  * Updated `node-uuid` and `coffeescript`
  * Exclude `examples`, `tests`, and `Makefile` from npm package
  * Update examples to use latest jQuery and sockjs-client #271
  * Don't call `res.end` in `writeHead` #266
  * Pin `websocket-driver` as later versions cause some tests from `sockjs-protocol` to fail

0.3.19
======

  * Update `node-uuid` version #224
  * Add `disable_cors` option to prevent CORS headers from being added to responses #218
  * Add `dnt` header to whitelist #212
  * Add `x-forwarded-host` and `x-forwarded-port` headers to whitelist #208
  * Update `sockjs_url` default to latest 1.x target #223
  * Updated hapi.js example #216

0.3.18
======

  * Change to using `res.statusCode` instead of manual parsing of `res._header` #213
  * Update sockjs-protocol filename in README #203

0.3.17
======

  * Fix usage of undefined `session` in `heartbeat_timeout` #179

0.3.16
======

  * Fix CORS response for null origin #177
  * Add websocket ping-pong and close if no response #129, #162, #169
  * Update sockjs-client version in examples #182
  * Add koa example #180
  * Disable raw websocket endpoint when websocket = false #183
  * Upgrade to faye-websocket 0.10.0 and use proper close code
  * When connection is aborted, don't delay the teardown
  * Forward additional headers #188
  * Add `no-transform` to Cache-Control headers #189
  * Update documentation about heartbeats #192

0.3.15
======

  * Remove usage of naked '@' function params to be compatible with coffeescript 1.9.0 #175

0.3.14
======

  * Re-publish to npm because of build issue in 0.3.13

0.3.13
======

  * Upgrade faye-websocket to 0.9.3 to fix #171

0.3.12
======

 * Allow Faye socket constructor options to be passed with
   faye_server_options option to createServer
 * Fix websocket bad json tests
 * Upgrade Faye to allow 0.9.*

0.3.11
======

 * #133 -  only delay disconnect on non-websocket transports
 * Upgrade Faye to 0.8.0

0.3.10
======

 * #168 - Add CORS headers for eventsource
 * #158 - schedule heartbeat timer even if send_buffer is not empty
 * #96 - remove rbytes dependency
 * #83 - update documentation for prefix
 * #163 - add protection to JSON for SWF exploit
 * #104 - delete unused parameters in code
 * #106 - update CDN urls
 * #79 - Don't remove stream listeners until after end so 'close' event is heard
 * Get rid of need for _sockjs_onload global variable
 * Use Faye for websocket request validation
 * Upgrade Faye to 0.7.3
 * Upgrade node-uuid to 1.4.1

0.3.9
=====

 * #130 - Set Vary: Origin on CORS requests
 * Upgrade Faye to 0.7.2 from 0.7.0

0.3.8
=====

 * #118 - Allow servers to specify a base URL in /info
 * #131 - Don't look up session id undefined
 * #124 - Small grammar updates for ReadMe
 * Upgrade Faye to 0.7.0 from 0.4.0

0.3.7
=====

 * Expose "protocol" on raw websocket connection instance, correctly

0.3.6
=====

 * When the server closes a connection, make sure the send buffer still
   gets flushed.
 * Expose "protocol" on raw websocket connection instance
 * #105, #109, #113 - expose 'host', 'user-agent', and 'accept-language'
   headers
 * Serve SockJS over https CDN by default
 * Upgrade Faye to 0.4.4 from 0.4.0

0.3.5
=====

 * #103 - connection.protocol might have been empty on some rare
   occasions.
 * #99 - faye-websocket was leaking sockets in "closed" state
   when dealing with rfc websockets

0.3.4
=====

 * #73 - apparently 'package' is a reserved keyword (use 'pkg' instead)
 * #93 - Coffescript can leak a variable when the same name is used
   in catch statement. Let's always use 'x' as the variable in catch.
 * #76 - decorateConnection could throw an error if remote connection
   was closed before setup was complete
 * #90 - Fix "TypeError: 'addListener'" exception (via @pl).
 * remove 'optionalDependencies' section from package.json,
   'rbytes' was always optional.
 * #91 - Fix rare null exception.

0.3.3
=====

 * sockjs/sockjs-protocol#56, #88 Fix for iOS 6 caching POSTs

0.3.1
=====

 * #58 - websocket transport emitted an array instead of a string
   during onmessage event.
 * Running under node.js 0.7 caused infinite recursion (Stephan Kochen)
 * #59 - restrict characters allowed in callback parameter
 * Updated readme - rbytes package is optional
 * Updated readme WRT deployments on heroku
 * Add minimalistic license block to every source file.

0.3.0
=====

 * Sending JSESSIONID cookie is now *disabled* by default.
 * sockjs/sockjs-protocol#46 - introduce new service
   required for protocol tests "/cookie_needed_echo"
 * Initial work towards better integration with
   "connect" (Stephan Kochen). See discusion:
       https://github.com/senchalabs/connect/pull/506
 * More documentation about the Cookie and Origin headers.
 * #51 - expose "readyState" on connection instance
 * #53 - expose "protocol" on connection instance
 * #52 - Some protocols may not emit 'close' event with IE.
 * sockjs/sockjs-client#49 - Support 'null' origin - aka: allow SockJS
   client to be served from file:// paths.

0.2.1
=====

 * Bumped "faye-websocket" dependency to 0.4. Updated
   code to take advantage of introduced changes.
 * Pinned "node-static" and bumped "node-uuid" dependencies.
 * Removed "Origin" header list of headers exposed to the user.
   This header is not really meaningful in sockjs context.
 * Header "Access-Control-Allow-Methods" was misspelled.

0.2.0
=====

 * #36, #3 - Replace a custom WebSocket server implementation
   with  faye-websocket-node.
 * Multiple changes to support SockJS-protocol 0.2.
    * The session is now closed on network errors immediately
      (instead of waiting 5 seconds)
    * Raw websocket interface available - to make it easier
      to write command line SockJS clients.
    * Support '/info' url.
 * The test server got moved from SockJS-client to SockJS-node.
 * Dropped deprecated Server API (use createServer method instead).
 * Option `websocket` is now used instead of `disabled_transports`.

0.1.2
=====

 * #27 - Allow all unicode characters to be send over SockJS.
 * #14 - Make it possible to customize JSESSIONID cookie logic.

0.1.1
=====

 * #32 Expose various request headers on connection.
 * #30 Expose request path on connection.

0.1.0
=====

 * The API changed, there is now an idiomatic API, modelled on node.js
   Stream API. The old API is deprecated and there is a dummy wrapper
   that emulates it. Please do upgrade to the new idiomatic API.
 * #22 Initial support for hybi13 (stephank)
 * New options accepted by the `Server` constructor: `log`,
   `heartbeat_delay` and `disconnect_delay`.
 * SockJS is now not able to send rich data structures - all data
   passed to `write` is converted to a string.
 * #23 `Connection.remoteAddress` property introduced (Stéphan Kochen)
 * Loads of small changes in order to adhere to protocol spec.

0.0.5
=====

 * #20: `npm submodule sockjs` didn't work due to outdated github
   path.

0.0.4
=====

 * Support for htmlfile transport, used by IE in a deployment
   dependent on cookies.
 * Added /chunking_test API, used to detect support for HTTP chunking
   on client side.
 * Unified code logic for all the chunking transports - the same code
   is reused for polling versions.
 * All the chunking transports are closed by the server after 128K was
   send, in order to force client to GC and reconnect.
 * Don't distribute source coffeescript with npm.
 * Minor fixes in websocket code.
 * Dropped jQuery dependency.
 * Unicode encoding could been garbled during XHR upload.
 * Other minor fixes.

0.0.3
======

 * EventSource transport didn't emit 'close' event.

0.0.2
=====

 * By default set JSESSIONID cookie, useful for load balancing.

0.0.1
=====

 * Initial release.


code:
[![NPM version](https://badge.fury.io/js/sockjs.svg)](http://badge.fury.io/js/sockjs)

SockJS family:

  * [SockJS-client](https://github.com/sockjs/sockjs-client) JavaScript client library
  * [SockJS-node](https://github.com/sockjs/sockjs-node) Node.js server
  * [SockJS-erlang](https://github.com/sockjs/sockjs-erlang) Erlang server
  * [SockJS-tornado](https://github.com/MrJoes/sockjs-tornado) Python/Tornado server
  * [vert.x](https://github.com/eclipse/vert.x) Java/vert.x server

Work in progress:

  * [SockJS-ruby](https://github.com/nyarly/sockjs-ruby)
  * [SockJS-netty](https://github.com/cgbystrom/sockjs-netty)
  * [SockJS-gevent](https://github.com/sdiehl/sockjs-gevent) ([and a fork](https://github.com/njoyce/sockjs-gevent))
  * [pyramid-SockJS](https://github.com/fafhrd91/pyramid_sockjs)
  * [wildcloud-websockets](https://github.com/wildcloud/wildcloud-websockets)
  * [SockJS-cyclone](https://github.com/flaviogrossi/sockjs-cyclone)
  * [SockJS-twisted](https://github.com/Fugiman/sockjs-twisted/)
  * [wai-SockJS](https://github.com/Palmik/wai-sockjs)
  * [SockJS-perl](https://github.com/vti/sockjs-perl)
  * [SockJS-go](https://github.com/igm/sockjs-go/)

What is SockJS?
===============

SockJS is a JavaScript library (for browsers) that provides a WebSocket-like
object. SockJS gives you a coherent, cross-browser, Javascript API
which creates a low latency, full duplex, cross-domain communication
channel between the browser and the web server, with WebSockets or without.
This necessitates the use of a server, which this is one version of, for Node.js.

SockJS-node server
==================

SockJS-node is a Node.js server side counterpart of
[SockJS-client browser library](https://github.com/sockjs/sockjs-client)
written in CoffeeScript.

To install `sockjs-node` run:

    npm install sockjs

A simplified echo SockJS server could look more or less like:

```javascript
var http = require('http');
var sockjs = require('sockjs');

var echo = sockjs.createServer();
echo.on('connection', function(conn) {
    conn.on('data', function(message) {
        conn.write(message);
    });
    conn.on('close', function() {});
});

var server = http.createServer();
echo.installHandlers(server, {prefix:'/echo'});
server.listen(9999, '0.0.0.0');
```

(Take look at
[examples](https://github.com/sockjs/sockjs-node/tree/master/examples/echo)
directory for a complete version.)

Subscribe to
[SockJS mailing list](https://groups.google.com/forum/#!forum/sockjs) for
discussions and support.

SockJS-node API
---------------

The API design is based on common Node APIs like the
[Streams API](http://nodejs.org/docs/v0.5.8/api/streams.html) or the
[Http.Server API](http://nodejs.org/docs/v0.5.8/api/http.html#http.Server).

### Server class

SockJS module is generating a `Server` class, similar to
[Node.js http.createServer](http://nodejs.org/docs/v0.5.8/api/http.html#http.createServer)
module.

```javascript
var sockjs_server = sockjs.createServer(options);
```

Where `options` is a hash which can contain:

sockjs_url (string)

Transports which don't support cross-domain communication natively
   ('eventsource' to name one) use an iframe trick. A simple page is
   served from the SockJS server (using its foreign domain) and is
   placed in an invisible iframe. Code run from this iframe doesn't
   need to worry about cross-domain issues, as it's being run from
   domain local to the SockJS server. This iframe also does need to
   load SockJS javascript client library, and this option lets you specify
   its url (if you're unsure, point it to

   the latest minified SockJS client release, this is the default).
   You must explicitly specify this url on the server side for security
   reasons - we don't want the possibility of running any foreign
   javascript within the SockJS domain (aka cross site scripting attack).
   Also, sockjs javascript library is probably already cached by the
   browser - it makes sense to reuse the sockjs url you're using in
   normally.

prefix (string regex)

A url prefix for the server. All http requests which paths begins
   with selected prefix will be handled by SockJS. All other requests
   will be passed through, to previously registered handlers.

response_limit (integer)

Most streaming transports save responses on the client side and
   don't free memory used by delivered messages. Such transports need
   to be garbage-collected once in a while. `response_limit` sets
   a minimum number of bytes that can be send over a single http streaming
   request before it will be closed. After that client needs to open
   new request. Setting this value to one effectively disables
   streaming and will make streaming transports to behave like polling
   transports. The default value is 128K.

websocket (boolean)

Some load balancers don't support websockets. This option can be used
   to disable websockets support by the server. By default websockets are
   enabled.

jsessionid (boolean or function)

Some hosting providers enable sticky sessions only to requests that
  have JSESSIONID cookie set. This setting controls if the server should
  set this cookie to a dummy value. By default setting JSESSIONID cookie
  is disabled. More sophisticated behaviour can be achieved by supplying
  a function.

log (function(severity, message))

It's quite useful, especially for debugging, to see some messages
  printed by a SockJS-node library. This is done using this `log`
  function, which is by default set to `console.log`. If this
  behaviour annoys you for some reason, override `log` setting with a
  custom handler.  The following `severities` are used: `debug`
  (miscellaneous logs), `info` (requests logs), `error` (serious
  errors, consider filing an issue).

heartbeat_delay (milliseconds)

In order to keep proxies and load balancers from closing long
  running http requests we need to pretend that the connection is
  active and send a heartbeat packet once in a while. This setting
  controls how often this is done. By default a heartbeat packet is
  sent every 25 seconds.

disconnect_delay (milliseconds)

The server sends a `close` event when a client receiving
  connection have not been seen for a while. This delay is configured
  by this setting. By default the `close` event will be emitted when a
  receiving connection wasn't seen for 5 seconds.

disable_cors (boolean)

Enabling this option will prevent
  CORS
  headers from being included in the HTTP response. Can be used when the
  sockjs client is known to be connecting from the same origin as the
  sockjs server.

### Server instance

Once you have create `Server` instance you can hook it to the
[http.Server instance](http://nodejs.org/docs/v0.5.8/api/http.html#http.createServer).

```javascript
var http_server = http.createServer();
sockjs_server.installHandlers(http_server, options);
http_server.listen(...);
```

Where `options` can overshadow options given when creating `Server`
instance.

`Server` instance is an
[EventEmitter](http://nodejs.org/docs/v0.4.10/api/events.html#events.EventEmitter),
and emits following event:

Event: connection (connection)

A new connection has been successfully opened.

All http requests that don't go under the path selected by `prefix`
will remain unanswered and will be passed to previously registered
handlers. You must install your custom http handlers before calling
`installHandlers`.

### Connection instance

A `Connection` instance supports
[Node Stream API](http://nodejs.org/docs/v0.5.8/api/streams.html) and
has following methods and properties:

Property: readable (boolean)

Is the stream readable?

Property: writable (boolean)

Is the stream writable?

Property: remoteAddress (string)

Last known IP address of the client.

Property: remotePort (number)

Last known port number of the client.

Property: address (object)

Hash with 'address' and 'port' fields.

Property: headers (object)

Hash containing various headers copied from last receiving request
    on that connection. Exposed headers include: `origin`, `referer`
    and `x-forwarded-for` (and friends). We explicitly do not grant
    access to `cookie` header, as using it may easily lead to security
    issues (for details read the section "Authorisation").

Property: url (string)

Url
    property copied from last request.

Property: pathname (string)

`pathname` from parsed url, for convenience.

Property: prefix (string)

Prefix of the url on which the request was handled.

Property: protocol (string)

Protocol used by the connection. Keep in mind that some protocols
   are indistinguishable - for example "xhr-polling" and "xdr-polling".

Property: readyState (integer)

Current state of the connection:
   0-connecting, 1-open, 2-closing, 3-closed.

write(message)

Sends a message over opened connection. A message must be a
  non-empty string. It's illegal to send a message after the connection was
  closed (either after 'close' or 'end' method or 'close' event).

close([code], [reason])

Asks the remote client to disconnect. 'code' and 'reason'
   parameters are optional and can be used to share the reason of
   disconnection.

end()

Asks the remote client to disconnect with default 'code' and
   'reason' values.

A `Connection` instance emits the following events:

Event: data (message)

A message arrived on the connection. Message is a unicode
  string.

Event: close ()

Connection was closed. This event is triggered exactly once for
   every connection.

For example:

```javascript
sockjs_server.on('connection', function(conn) {
    console.log('connection' + conn);
    conn.on('close', function() {
        console.log('close ' + conn);
    });
    conn.on('data', function(message) {
        console.log('message ' + conn,
                    message);
    });
});
```

### Footnote

A fully working echo server does need a bit more boilerplate (to
handle requests unanswered by SockJS), see the
[`echo` example](https://github.com/sockjs/sockjs-node/tree/master/examples/echo)
for a complete code.

### Examples

If you want to see samples of running code, take a look at:

 * [./examples/echo](https://github.com/sockjs/sockjs-node/tree/master/examples/echo)
   directory, which contains a full example of a echo server.
 * [./examples/test_server](https://github.com/sockjs/sockjs-node/tree/master/examples/test_server) a standard SockJS test server.

Connecting to SockJS-node without the client
--------------------------------------------

Although the main point of SockJS it to enable browser-to-server
connectivity, it is possible to connect to SockJS from an external
application. Any SockJS server complying with 0.3 protocol does
support a raw WebSocket url. The raw WebSocket url for the test server
looks like:

 * ws://localhost:8081/echo/websocket

You can connect any WebSocket RFC 6455 compliant WebSocket client to
this url. This can be a command line client, external application,
third party code or even a browser (though I don't know why you would
want to do so).

Note: This endpoint will *not send any heartbeat packets*.

Deployment and load balancing
-----------------------------

There are two issues that need to be considered when planning a
non-trivial SockJS-node deployment: WebSocket-compatible load balancer
and sticky sessions (aka session affinity).

### WebSocket compatible load balancer

Often WebSockets don't play nicely with proxies and load balancers.
Deploying a SockJS server behind Nginx or Apache could be painful.

Fortunately recent versions of an excellent load balancer
[HAProxy](http://haproxy.1wt.eu/) are able to proxy WebSocket
connections. We propose to put HAProxy as a front line load balancer
and use it to split SockJS traffic from normal HTTP data. Take a look
at the sample
[SockJS HAProxy configuration](https://github.com/sockjs/sockjs-node/blob/master/examples/haproxy.cfg).

The config also shows how to use HAproxy balancing to split traffic
between multiple Node.js servers. You can also do balancing using dns
names.

### Sticky sessions

If you plan deploying more than one SockJS server, you must make sure
that all HTTP requests for a single session will hit the same server.
SockJS has two mechanisms that can be useful to achieve that:

 * Urls are prefixed with server and session id numbers, like:
   `/resource/<server_number>/<session_id>/transport`.  This is
   useful for load balancers that support prefix-based affinity
   (HAProxy does).
 * `JSESSIONID` cookie is being set by SockJS-node. Many load
   balancers turn on sticky sessions if that cookie is set. This
   technique is derived from Java applications, where sticky sessions
   are often necessary. HAProxy does support this method, as well as
   some hosting providers, for example CloudFoundry.  In order to
   enable this method on the client side, please supply a
   `cookie:true` option to SockJS constructor.

Development and testing
-----------------------

If you want to work on SockJS-node source code, you need to clone the
git repo and follow these steps. First you need to install
dependencies:

    cd sockjs-node
    npm install
    npm install --dev
    ln -s .. node_modules/sockjs

You're ready to compile CoffeeScript:

    make build

If compilation succeeds you may want to test if your changes pass all
the tests. Currently, there are two separate test suites. For both of
them you need to start a SockJS-node test server (by default listening
on port 8081):

    make test_server

### SockJS-protocol Python tests

To run it run something like:

    cd sockjs-protocol
    make test_deps
    ./venv/bin/python sockjs-protocol.py

For details see
[SockJS-protocol README](https://github.com/sockjs/sockjs-protocol#readme).

### SockJS-client QUnit tests

You need to start a second web server (by default listening on 8080)
that is serving various static html and javascript files:

    cd sockjs-client
    make test

At that point you should have two web servers running: sockjs-node on
8081 and sockjs-client on 8080. When you open the browser on
[http://localhost:8080/](http://localhost:8080/) you should be able
run the QUnit tests against your sockjs-node server.

For details see
[SockJS-client README](https://github.com/sockjs/sockjs-client#readme).

Additionally, if you're doing more serious development consider using
`make serve`, which will automatically the server when you modify the
source code.

Various issues and design considerations
----------------------------------------

### Authorisation

SockJS-node does not expose cookies to the application. This is done
deliberately as using cookie-based authorisation with SockJS simply
doesn't make sense and will lead to security issues.

Cookies are a contract between a browser and an http server, and are
identified by a domain name. If a browser has a cookie set for
particular domain, it will pass it as a part of all http requests to
the host. But to get various transports working, SockJS uses a middleman
- an iframe hosted from target SockJS domain. That means the server
will receive requests from the iframe, and not from the real
domain. The domain of an iframe is the same as the SockJS domain. The
problem is that any website can embed the iframe and communicate with
it - and request establishing SockJS connection. Using cookies for
authorisation in this scenario will result in granting full access to
SockJS communication with your website from any website. This is a
classic CSRF attack.

Basically - cookies are not suited for SockJS model. If you want to
authorise a session - provide a unique token on a page, send it as a
first thing over SockJS connection and validate it on the server
side. In essence, this is how cookies work.

### Deploying SockJS on Heroku

Long polling is known to cause problems on Heroku, but
[workaround for SockJS is available](https://github.com/sockjs/sockjs-node/issues/57#issuecomment-5242187).


code:
// Generated by CoffeeScript 1.12.7
(function() {
  var utils;

  utils = require('./utils');

  exports.app = {
    chunking_test: function(req, res, _, next_filter) {
      var write;
      res.setHeader('Content-Type', 'application/javascript; charset=UTF-8');
      res.writeHead(200);
      write = (function(_this) {
        return function(payload) {
          var x;
          try {
            return res.write(payload + '\n');
          } catch (error) {
            x = error;
          }
        };
      })(this);
      utils.timeout_chain([
        [
          0, (function(_this) {
            return function() {
              return write('h');
            };
          })(this)
        ], [
          1, (function(_this) {
            return function() {
              return write(Array(2049).join(' ') + 'h');
            };
          })(this)
        ], [
          5, (function(_this) {
            return function() {
              return write('h');
            };
          })(this)
        ], [
          25, (function(_this) {
            return function() {
              return write('h');
            };
          })(this)
        ], [
          125, (function(_this) {
            return function() {
              return write('h');
            };
          })(this)
        ], [
          625, (function(_this) {
            return function() {
              return write('h');
            };
          })(this)
        ], [
          3125, (function(_this) {
            return function() {
              write('h');
              return res.end();
            };
          })(this)
        ]
      ]);
      return true;
    },
    info: function(req, res, _) {
      var info;
      info = {
        websocket: this.options.websocket,
        origins: !this.options.disable_cors ? ['*:*'] : void 0,
        cookie_needed: !!this.options.jsessionid,
        entropy: utils.random32()
      };
      if (typeof this.options.base_url === 'function') {
        info.base_url = this.options.base_url();
      } else if (this.options.base_url) {
        info.base_url = this.options.base_url;
      }
      res.setHeader('Content-Type', 'application/json; charset=UTF-8');
      res.writeHead(200);
      return res.end(JSON.stringify(info));
    },
    info_options: function(req, res) {
      res.statusCode = 204;
      res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
      res.setHeader('Access-Control-Max-Age', res.cache_for);
      return '';
    }
  };

}).call(this);


code:
// Generated by CoffeeScript 1.12.7
(function() {
  var iframe_template, utils;

  utils = require('./utils');

  iframe_template = "<!DOCTYPE html>\n\n\n  <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n  \n  \n\n\n
Don't panic!
\n
This is a SockJS hidden iframe. It's used for cross domain magic.
\n\n";

  exports.app = {
    iframe: function(req, res) {
      var content, context, k, quoted_md5;
      context = {
        '{{ sockjs_url }}': this.options.sockjs_url
      };
      content = iframe_template;
      for (k in context) {
        content = content.replace(k, context[k]);
      }
      quoted_md5 = '"' + utils.md5_hex(content) + '"';
      if ('if-none-match' in req.headers && req.headers['if-none-match'] === quoted_md5) {
        res.statusCode = 304;
        return '';
      }
      res.setHeader('Content-Type', 'text/html; charset=UTF-8');
      res.setHeader('ETag', quoted_md5);
      return content;
    }
  };

}).call(this);


code:
// Generated by CoffeeScript 1.12.7
(function() {
  var App, Listener, Server, chunking_test, events, fs, generate_dispatcher, iframe, sockjsVersion, trans_eventsource, trans_htmlfile, trans_jsonp, trans_websocket, trans_xhr, utils, webjs,
    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
    hasProp = {}.hasOwnProperty,
    bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

  events = require('events');

  fs = require('fs');

  webjs = require('./webjs');

  utils = require('./utils');

  trans_websocket = require('./trans-websocket');

  trans_jsonp = require('./trans-jsonp');

  trans_xhr = require('./trans-xhr');

  iframe = require('./iframe');

  trans_eventsource = require('./trans-eventsource');

  trans_htmlfile = require('./trans-htmlfile');

  chunking_test = require('./chunking-test');

  sockjsVersion = function() {
    var pkg, x;
    try {
      pkg = fs.readFileSync(__dirname + '/../package.json', 'utf-8');
    } catch (error) {
      x = error;
    }
    if (pkg) {
      return JSON.parse(pkg).version;
    } else {
      return null;
    }
  };

  App = (function(superClass) {
    extend(App, superClass);

    function App() {
      return App.__super__.constructor.apply(this, arguments);
    }

    App.prototype.welcome_screen = function(req, res) {
      res.setHeader('content-type', 'text/plain; charset=UTF-8');
      res.writeHead(200);
      res.end("Welcome to SockJS!\n");
      return true;
    };

    App.prototype.handle_404 = function(req, res) {
      res.setHeader('content-type', 'text/plain; charset=UTF-8');
      res.writeHead(404);
      res.end('404 Error: Page not found\n');
      return true;
    };

    App.prototype.disabled_transport = function(req, res, data) {
      return this.handle_404(req, res, data);
    };

    App.prototype.h_sid = function(req, res, data) {
      var jsid;
      req.cookies = utils.parseCookie(req.headers.cookie);
      if (typeof this.options.jsessionid === 'function') {
        this.options.jsessionid(req, res);
      } else if (this.options.jsessionid && res.setHeader) {
        jsid = req.cookies['JSESSIONID'] || 'dummy';
        res.setHeader('Set-Cookie', 'JSESSIONID=' + jsid + '; path=/');
      }
      return data;
    };

    App.prototype.log = function(severity, line) {
      return this.options.log(severity, line);
    };

    return App;

  })(webjs.GenericApp);

  utils.objectExtend(App.prototype, iframe.app);

  utils.objectExtend(App.prototype, chunking_test.app);

  utils.objectExtend(App.prototype, trans_websocket.app);

  utils.objectExtend(App.prototype, trans_jsonp.app);

  utils.objectExtend(App.prototype, trans_xhr.app);

  utils.objectExtend(App.prototype, trans_eventsource.app);

  utils.objectExtend(App.prototype, trans_htmlfile.app);

  generate_dispatcher = function(options) {
    var opts_filters, p, prefix_dispatcher, t, transport_dispatcher;
    p = (function(_this) {
      return function(s) {
        return new RegExp('^' + options.prefix + s + '[/]?$');
      };
    })(this);
    t = (function(_this) {
      return function(s) {
        return [p('/([^/.]+)/([^/.]+)' + s), 'server', 'session'];
      };
    })(this);
    opts_filters = function(options_filter) {
      if (options_filter == null) {
        options_filter = 'xhr_options';
      }
      return ['h_sid', 'xhr_cors', 'cache_for', options_filter, 'expose'];
    };
    prefix_dispatcher = [['GET', p(''), ['welcome_screen']], ['GET', p('/iframe[0-9-.a-z_]*.html'), ['iframe', 'cache_for', 'expose']], ['OPTIONS', p('/info'), opts_filters('info_options')], ['GET', p('/info'), ['xhr_cors', 'h_no_cache', 'info', 'expose']], ['OPTIONS', p('/chunking_test'), opts_filters()], ['POST', p('/chunking_test'), ['xhr_cors', 'expect_xhr', 'chunking_test']]];
    transport_dispatcher = [['GET', t('/jsonp'), ['h_sid', 'h_no_cache', 'jsonp']], ['POST', t('/jsonp_send'), ['h_sid', 'h_no_cache', 'expect_form', 'jsonp_send']], ['POST', t('/xhr'), ['h_sid', 'h_no_cache', 'xhr_cors', 'xhr_poll']], ['OPTIONS', t('/xhr'), opts_filters()], ['POST', t('/xhr_send'), ['h_sid', 'h_no_cache', 'xhr_cors', 'expect_xhr', 'xhr_send']], ['OPTIONS', t('/xhr_send'), opts_filters()], ['POST', t('/xhr_streaming'), ['h_sid', 'h_no_cache', 'xhr_cors', 'xhr_streaming']], ['OPTIONS', t('/xhr_streaming'), opts_filters()], ['GET', t('/eventsource'), ['h_sid', 'h_no_cache', 'eventsource']], ['GET', t('/htmlfile'), ['h_sid', 'h_no_cache', 'htmlfile']]];
    if (options.websocket) {
      prefix_dispatcher.push(['GET', p('/websocket'), ['raw_websocket']]);
      transport_dispatcher.push(['GET', t('/websocket'), ['sockjs_websocket']]);
    } else {
      prefix_dispatcher.push(['GET', p('/websocket'), ['cache_for', 'disabled_transport']]);
      transport_dispatcher.push(['GET', t('/websocket'), ['cache_for', 'disabled_transport']]);
    }
    return prefix_dispatcher.concat(transport_dispatcher);
  };

  Listener = (function() {
    function Listener(options1, emit) {
      this.options = options1;
      this.handler = bind(this.handler, this);
      this.app = new App();
      this.app.options = this.options;
      this.app.emit = emit;
      this.app.log('debug', 'SockJS v' + sockjsVersion() + ' ' + 'bound to ' + JSON.stringify(this.options.prefix));
      this.dispatcher = generate_dispatcher(this.options);
      this.webjs_handler = webjs.generateHandler(this.app, this.dispatcher);
      this.path_regexp = new RegExp('^' + this.options.prefix + '([/].+|[/]?)$');
    }

    Listener.prototype.handler = function(req, res, extra) {
      if (!req.url.match(this.path_regexp)) {
        return false;
      }
      this.webjs_handler(req, res, extra);
      return true;
    };

    Listener.prototype.getHandler = function() {
      return (function(_this) {
        return function(a, b, c) {
          return _this.handler(a, b, c);
        };
      })(this);
    };

    return Listener;

  })();

  Server = (function(superClass) {
    extend(Server, superClass);

    function Server(user_options) {
      this.options = {
        prefix: '',
        response_limit: 128 * 1024,
        websocket: true,
        faye_server_options: null,
        jsessionid: false,
        heartbeat_delay: 25000,
        disconnect_delay: 5000,
        log: function(severity, line) {
          return console.log(line);
        },
        sockjs_url: 'https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js'
      };
      if (user_options) {
        utils.objectExtend(this.options, user_options);
      }
    }

    Server.prototype.listener = function(handler_options) {
      var options;
      options = utils.objectExtend({}, this.options);
      if (handler_options) {
        utils.objectExtend(options, handler_options);
      }
      return new Listener(options, (function(_this) {
        return function() {
          return _this.emit.apply(_this, arguments);
        };
      })(this));
    };

    Server.prototype.installHandlers = function(http_server, handler_options) {
      var handler;
      handler = this.listener(handler_options).getHandler();
      utils.overshadowListeners(http_server, 'request', handler);
      utils.overshadowListeners(http_server, 'upgrade', handler);
      return true;
    };

    Server.prototype.middleware = function(handler_options) {
      var handler;
      handler = this.listener(handler_options).getHandler();
      handler.upgrade = handler;
      return handler;
    };

    return Server;

  })(events.EventEmitter);

  exports.createServer = function(options) {
    return new Server(options);
  };

  exports.listen = function(http_server, options) {
    var srv;
    srv = exports.createServer(options);
    if (http_server) {
      srv.installHandlers(http_server);
    }
    return srv;
  };

}).call(this);


code:
// Generated by CoffeeScript 1.12.7
(function() {
  var EventSourceReceiver, transport, utils,
    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
    hasProp = {}.hasOwnProperty;

  utils = require('./utils');

  transport = require('./transport');

  EventSourceReceiver = (function(superClass) {
    extend(EventSourceReceiver, superClass);

    function EventSourceReceiver() {
      return EventSourceReceiver.__super__.constructor.apply(this, arguments);
    }

    EventSourceReceiver.prototype.protocol = "eventsource";

    EventSourceReceiver.prototype.doSendFrame = function(payload) {
      var data;
      data = ['data: ', utils.escape_selected(payload, '\r\n\x00'), '\r\n\r\n'];
      return EventSourceReceiver.__super__.doSendFrame.call(this, data.join(''));
    };

    return EventSourceReceiver;

  })(transport.ResponseReceiver);

  exports.app = {
    eventsource: function(req, res) {
      var headers, origin;
      if (!req.headers['origin'] || req.headers['origin'] === 'null') {
        origin = '*';
      } else {
        origin = req.headers['origin'];
        res.setHeader('Access-Control-Allow-Credentials', 'true');
      }
      res.setHeader('Content-Type', 'text/event-stream');
      res.setHeader('Access-Control-Allow-Origin', origin);
      res.setHeader('Vary', 'Origin');
      headers = req.headers['access-control-request-headers'];
      if (headers) {
        res.setHeader('Access-Control-Allow-Headers', headers);
      }
      res.writeHead(200);
      res.write('\r\n');
      transport.register(req, this, new EventSourceReceiver(req, res, this.options));
      return true;
    }
  };

}).call(this);