Comparing version 0.0.1 to 0.0.2
@@ -1,99 +0,248 @@ | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
'use strict'; | ||
var SimpleDOM = require('simple-dom'); | ||
var najax = require('najax'); | ||
var debug = require('debug')('ember-cli-fastboot:ember-app'); | ||
var FastBootInfo = require('./fastboot-info'); | ||
var Sandbox = require('./sandbox'); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
var HTMLSerializer = new SimpleDOM.HTMLSerializer(SimpleDOM.voidMap); | ||
const najax = require('najax'); | ||
const SimpleDOM = require('simple-dom'); | ||
const existsSync = require('exists-sync'); | ||
const debug = require('debug')('fastboot:ember-app'); | ||
function EmberApp(options) { | ||
var distPath = options.distPath; | ||
const FastBootInfo = require('./fastboot-info'); | ||
const Result = require('./result'); | ||
var appFilePath = options.appFile; | ||
var vendorFilePath = options.vendorFile; | ||
var moduleWhitelist = options.moduleWhitelist; | ||
this._hostWhitelist = options.hostWhitelist; | ||
/** | ||
* @private | ||
* | ||
* The `EmberApp` class serves as a non-sandboxed wrapper around a sandboxed | ||
* `Ember.Application`. This bridge allows the FastBoot to quickly spin up new | ||
* `ApplicationInstances` initialized at a particular route, then destroy them | ||
* once the route has finished rendering. | ||
*/ | ||
class EmberApp { | ||
/** | ||
* Create a new EmberApp. | ||
* @param {Object} options | ||
* @param {string} options.distPath - path to the built Ember application | ||
* @param {Sandbox} [options.sandbox=VMSandbox] - sandbox to use | ||
*/ | ||
constructor(options) { | ||
let distPath = path.resolve(options.distPath); | ||
let config = this.readPackageJSON(distPath); | ||
debug("app created; app=%s; vendor=%s", appFilePath, vendorFilePath); | ||
this.appFilePath = config.appFile; | ||
this.vendorFilePath = config.vendorFile; | ||
this.moduleWhitelist = config.moduleWhitelist; | ||
this.hostWhitelist = config.hostWhitelist; | ||
moduleWhitelist.forEach(function(whitelistedModule) { | ||
debug("module whitelisted; module=%s", whitelistedModule); | ||
}); | ||
this.html = fs.readFileSync(config.htmlFile, 'utf8'); | ||
// Create the sandbox, giving it the resolver to resolve once the app | ||
// has booted. | ||
var sandboxRequire = buildWhitelistedRequire(moduleWhitelist, distPath); | ||
var sandbox = new Sandbox({ | ||
globals: { | ||
najax: najax, | ||
FastBoot: { require: sandboxRequire } | ||
} | ||
}); | ||
this.sandbox = this.buildSandbox(distPath, options.sandbox); | ||
this.app = this.retrieveSandboxedApp(); | ||
} | ||
sandbox.eval('sourceMapSupport.install(Error);'); | ||
/** | ||
* @private | ||
* | ||
* Builds and initializes a new sandbox to run the Ember application in. | ||
* | ||
* @param {string} distPath path to the built Ember app to load | ||
* @param {Sandbox} [sandboxClass=VMSandbox] sandbox class to use | ||
*/ | ||
buildSandbox(distPath, sandboxClass) { | ||
let Sandbox = sandboxClass || require('./vm-sandbox'); | ||
let sandboxRequire = this.buildWhitelistedRequire(this.moduleWhitelist, distPath); | ||
var appFile = fs.readFileSync(appFilePath, 'utf8'); | ||
var vendorFile = fs.readFileSync(vendorFilePath, 'utf8'); | ||
return new Sandbox({ | ||
globals: { | ||
najax: najax, | ||
FastBoot: { require: sandboxRequire } | ||
} | ||
}); | ||
} | ||
sandbox.eval(vendorFile, vendorFilePath); | ||
debug("vendor file evaluated"); | ||
/** | ||
* @private | ||
* | ||
* The Ember app runs inside a sandbox that doesn't have access to the normal | ||
* Node.js environment, including the `require` function. Instead, we provide | ||
* our own `require` method that only allows whitelisted packages to be | ||
* requested. | ||
* | ||
* This method takes an array of whitelisted package names and the path to the | ||
* built Ember app and constructs this "fake" `require` function that gets made | ||
* available globally inside the sandbox. | ||
* | ||
* @param {string[]} whitelist array of whitelisted package names | ||
* @param {string} distPath path to the built Ember app | ||
*/ | ||
buildWhitelistedRequire(whitelist, distPath) { | ||
whitelist.forEach(function(whitelistedModule) { | ||
debug("module whitelisted; module=%s", whitelistedModule); | ||
}); | ||
sandbox.eval(appFile, appFilePath); | ||
debug("app file evaluated"); | ||
return function(moduleName) { | ||
if (whitelist.indexOf(moduleName) > -1) { | ||
let nodeModulesPath = path.join(distPath, 'node_modules', moduleName); | ||
var AppFactory = sandbox.run(function(ctx) { | ||
return ctx.require('~fastboot/app-factory'); | ||
}); | ||
if (existsSync(nodeModulesPath)) { | ||
return require(nodeModulesPath); | ||
} else { | ||
// If it's not on disk, assume it's a built-in node package | ||
return require(moduleName); | ||
} | ||
} else { | ||
throw new Error("Unable to require module '" + moduleName + "' because it was not in the whitelist."); | ||
} | ||
}; | ||
} | ||
if (!AppFactory || typeof AppFactory['default'] !== 'function') { | ||
throw new Error('Failed to load Ember app from ' + appFilePath + ', make sure it was built for FastBoot with the `ember fastboot:build` command.'); | ||
/** | ||
* @private | ||
* | ||
* Initializes the sandbox by evaluating the Ember app's JavaScript | ||
* code, then retrieves the application factory from the sandbox and creates a new | ||
* `Ember.Application`. | ||
* | ||
* @returns {Ember.Application} the Ember application from the sandbox | ||
*/ | ||
retrieveSandboxedApp() { | ||
let sandbox = this.sandbox; | ||
let appFilePath = this.appFilePath; | ||
let vendorFilePath = this.vendorFilePath; | ||
sandbox.eval('sourceMapSupport.install(Error);'); | ||
let appFile = fs.readFileSync(appFilePath, 'utf8'); | ||
let vendorFile = fs.readFileSync(vendorFilePath, 'utf8'); | ||
debug("evaluating app; app=%s; vendor=%s", appFilePath, vendorFilePath); | ||
sandbox.eval(vendorFile, vendorFilePath); | ||
debug("vendor file evaluated"); | ||
sandbox.eval(appFile, appFilePath); | ||
debug("app file evaluated"); | ||
// Retrieve the application factory from within the sandbox | ||
let AppFactory = sandbox.run(function(ctx) { | ||
return ctx.require('~fastboot/app-factory'); | ||
}); | ||
// If the application factory couldn't be found, throw an error | ||
if (!AppFactory || typeof AppFactory['default'] !== 'function') { | ||
throw new Error('Failed to load Ember app from ' + appFilePath + ', make sure it was built for FastBoot with the `ember fastboot:build` command.'); | ||
} | ||
// Otherwise, return a new `Ember.Application` instance | ||
return AppFactory['default'](); | ||
} | ||
this._app = AppFactory['default'](); | ||
} | ||
/** | ||
* Destroys the app and its sandbox. | ||
*/ | ||
destroy() { | ||
if (this.app) { | ||
this.app.destroy(); | ||
} | ||
EmberApp.prototype.destroy = function() { | ||
if (this._app) { | ||
this._app.destroy(); | ||
this.sandbox = null; | ||
} | ||
}; | ||
EmberApp.prototype.buildApp = function() { | ||
return this._app.boot().then(function(app) { | ||
return app.buildInstance(); | ||
}); | ||
}; | ||
/** | ||
* @private | ||
* | ||
* Creates a new `ApplicationInstance` from the sandboxed `Application`. | ||
* | ||
* @returns {Promise<Ember.ApplicationInstance>} instance | ||
*/ | ||
buildAppInstance() { | ||
return this.app.boot().then(function(app) { | ||
debug('building instance'); | ||
return app.buildInstance(); | ||
}); | ||
} | ||
/* | ||
* Called by an HTTP server to render the app at a specific URL. | ||
*/ | ||
EmberApp.prototype.visit = function(path, options) { | ||
var req = options.request; | ||
var res = options.response; | ||
/** | ||
* Creates a new application instance and renders the instance at a specific | ||
* URL, returning a promise that resolves to a {@link Result}. The `Result` | ||
* givesg you access to the rendered HTML as well as metadata about the | ||
* request such as the HTTP status code. | ||
* | ||
* If this call to `visit()` is to service an incoming HTTP request, you may | ||
* provide Node's `ClientRequest` and `ServerResponse` objects as options | ||
* (e.g., the `res` and `req` arguments passed to Express middleware). These | ||
* are provided to the Ember application via the FastBoot service. | ||
* | ||
* @param {string} path the URL path to render, like `/photos/1` | ||
* @param {Object} options | ||
* @param {ClientRequest} | ||
* @returns {Promise<Result>} result | ||
*/ | ||
visit(path, options) { | ||
let req = options.request; | ||
let res = options.response; | ||
let html = options.html || this.html; | ||
var bootOptions = buildBootOptions(); | ||
var doc = bootOptions.document; | ||
var rootElement = bootOptions.rootElement; | ||
let bootOptions = buildBootOptions(); | ||
let fastbootInfo = new FastBootInfo(req, res, this.hostWhitelist); | ||
let doc = bootOptions.document; | ||
return this.buildApp() | ||
.then(registerFastBootInfo(req, res, this._hostWhitelist)) | ||
.then(function(instance) { | ||
return instance.boot(bootOptions); | ||
}) | ||
.then(function(instance) { | ||
return instance.visit(path, bootOptions); | ||
}) | ||
.then(function(instance) { | ||
var fastbootInfo = instance.lookup('info:-fastboot'); | ||
let instance; | ||
return fastbootInfo.deferredPromise.then(function() { | ||
return instance; | ||
}); | ||
}) | ||
.then(serializeHTML(doc, rootElement)); | ||
}; | ||
let result = new Result({ | ||
doc: doc, | ||
html: html, | ||
fastbootInfo: fastbootInfo | ||
}); | ||
return this.buildAppInstance() | ||
.then(appInstance => { | ||
instance = appInstance; | ||
result.instance = instance; | ||
registerFastBootInfo(fastbootInfo, instance); | ||
return instance.boot(bootOptions); | ||
}) | ||
.then(() => instance.visit(path, bootOptions)) | ||
.then(() => waitForApp(instance)) | ||
.catch(error => result.error = error) | ||
.then(() => result._finalize()) | ||
.finally(() => instance.destroy()); | ||
} | ||
/** | ||
* Given the path to a built Ember app, reads the FastBoot manifest | ||
* information from its `package.json` file. | ||
*/ | ||
readPackageJSON(distPath) { | ||
let pkgPath = path.join(distPath, 'package.json'); | ||
let file; | ||
try { | ||
file = fs.readFileSync(pkgPath); | ||
} catch (e) { | ||
throw new Error(`Couldn't find ${pkgPath}. You may need to update your version of ember-cli-fastboot.`); | ||
} | ||
let manifest; | ||
let pkg; | ||
try { | ||
pkg = JSON.parse(file); | ||
manifest = pkg.fastboot.manifest; | ||
} catch (e) { | ||
throw new Error(`${pkgPath} was malformed or did not contain a manifest. Ensure that you have a compatible version of ember-cli-fastboot.`); | ||
} | ||
return { | ||
appFile: path.join(distPath, manifest.appFile), | ||
vendorFile: path.join(distPath, manifest.vendorFile), | ||
htmlFile: path.join(distPath, manifest.htmlFile), | ||
moduleWhitelist: pkg.fastboot.moduleWhitelist, | ||
hostWhitelist: pkg.fastboot.hostWhitelist | ||
}; | ||
} | ||
} | ||
/* | ||
@@ -104,4 +253,4 @@ * Builds an object with the options required to boot an ApplicationInstance in | ||
function buildBootOptions() { | ||
var doc = new SimpleDOM.Document(); | ||
var rootElement = doc.body; | ||
let doc = new SimpleDOM.Document(); | ||
let rootElement = doc.body; | ||
@@ -116,49 +265,22 @@ return { | ||
/* | ||
* Builds a new FastBootInfo instance with the request and response and injects | ||
* it into the application instance. | ||
* Ember apps can manually defer rendering in FastBoot mode if they're waiting | ||
* on something async the router doesn't know about. This function fetches | ||
* that promise for deferred rendering from the app. | ||
*/ | ||
function registerFastBootInfo(req, res, hostWhitelist) { | ||
return function(instance) { | ||
var info = new FastBootInfo(req, res, hostWhitelist); | ||
info.register(instance); | ||
function waitForApp(instance) { | ||
let fastbootInfo = instance.lookup('info:-fastboot'); | ||
return fastbootInfo.deferredPromise.then(function() { | ||
return instance; | ||
}; | ||
}); | ||
} | ||
/* | ||
* After the ApplicationInstance has finished rendering, serializes the | ||
* resulting DOM element into HTML to be transmitted back to the user agent. | ||
* Builds a new FastBootInfo instance with the request and response and injects | ||
* it into the application instance. | ||
*/ | ||
function serializeHTML(doc, rootElement) { | ||
return function(instance) { | ||
var head; | ||
if (doc.head) { | ||
head = HTMLSerializer.serializeChildren(doc.head); | ||
} | ||
try { | ||
return { | ||
url: instance.getURL(), // TODO: use this to determine whether to 200 or redirect | ||
title: doc.title, | ||
head: head, | ||
body: HTMLSerializer.serializeChildren(rootElement) | ||
}; | ||
} finally { | ||
instance.destroy(); | ||
} | ||
}; | ||
function registerFastBootInfo(info, instance) { | ||
info.register(instance); | ||
} | ||
function buildWhitelistedRequire(whitelist, distPath) { | ||
return function(moduleName) { | ||
if (whitelist.indexOf(moduleName) > -1) { | ||
return require(path.join(distPath, 'node_modules', moduleName)); | ||
} else { | ||
throw new Error("Unable to require module '" + moduleName + "' because it was not in the whitelist."); | ||
} | ||
}; | ||
} | ||
module.exports = EmberApp; |
// Partially implements Headers from the Fetch API | ||
// https://developer.mozilla.org/en-US/docs/Web/API/Headers | ||
function FastBootHeaders(headers) { | ||
this.headers = headers | ||
headers = headers || {}; | ||
this.headers = {}; | ||
for (var header in headers) { | ||
this.headers[header] = headers[header].split(', '); | ||
} | ||
} | ||
FastBootHeaders.prototype.append = function(header, value) { | ||
header = header.toLowerCase(); | ||
if (!this.has(header)) { | ||
this.headers[header] = []; | ||
} | ||
this.headers[header].push(value); | ||
}; | ||
FastBootHeaders.prototype.delete = function(header) { | ||
delete this.headers[header.toLowerCase()]; | ||
}; | ||
FastBootHeaders.prototype.entries = function() { | ||
var entries = []; | ||
for(var key in this.headers) { | ||
var values = this.headers[key]; | ||
for(var index = 0; index < values.length; ++index ) { | ||
entries.push([key, values[index]]); | ||
} | ||
} | ||
return entries[Symbol.iterator](); | ||
}; | ||
FastBootHeaders.prototype.get = function(header) { | ||
return this.getAll(header)[0] || null; | ||
} | ||
}; | ||
FastBootHeaders.prototype.getAll = function(header) { | ||
var headerValue = this.headers[header.toLowerCase()]; | ||
return this.headers[header.toLowerCase()] || []; | ||
}; | ||
if (headerValue) { | ||
return headerValue.split(', '); | ||
FastBootHeaders.prototype.has = function(header) { | ||
return this.headers[header.toLowerCase()] !== undefined; | ||
}; | ||
FastBootHeaders.prototype.keys = function() { | ||
var entries = []; | ||
for(var key in this.headers) { | ||
var values = this.headers[key]; | ||
for(var index = 0; index < values.length; ++index ) { | ||
entries.push(key); | ||
} | ||
} | ||
return []; | ||
} | ||
return entries[Symbol.iterator](); | ||
}; | ||
FastBootHeaders.prototype.has = function(header) { | ||
return this.headers[header.toLowerCase()] !== undefined; | ||
} | ||
FastBootHeaders.prototype.set = function(header, value) { | ||
header = header.toLowerCase(); | ||
this.headers[header] = [value]; | ||
}; | ||
FastBootHeaders.prototype.values = function() { | ||
var entries = []; | ||
for(var key in this.headers) { | ||
var values = this.headers[key]; | ||
for(var index = 0; index < values.length; ++index ) { | ||
entries.push(values[index]); | ||
} | ||
} | ||
return entries[Symbol.iterator](); | ||
}; | ||
module.exports = FastBootHeaders; |
var RSVP = require('rsvp'); | ||
var FastBootRequest = require('./fastboot-request'); | ||
var FastBootResponse = require('./fastboot-response'); | ||
@@ -10,5 +11,8 @@ /* | ||
function FastBootInfo(request, response, hostWhitelist) { | ||
this.response = response; | ||
this.deferredPromise = RSVP.resolve(); | ||
this.request = new FastBootRequest(request, hostWhitelist); | ||
if (request) { | ||
this.request = new FastBootRequest(request, hostWhitelist); | ||
} | ||
this.response = new FastBootResponse(response || {}); | ||
} | ||
@@ -20,3 +24,3 @@ | ||
}); | ||
} | ||
}; | ||
@@ -23,0 +27,0 @@ /* |
@@ -7,3 +7,3 @@ var cookie = require('cookie'); | ||
this.protocol = request.protocol | ||
this.protocol = request.protocol; | ||
this.headers = new FastBootHeaders(request.headers); | ||
@@ -10,0 +10,0 @@ this.queryParams = request.query; |
@@ -22,2 +22,2 @@ var sourceMapSupport = require('source-map-support'); | ||
install: install | ||
} | ||
}; |
var chalk = require('chalk'); | ||
function isLegacyVM() { | ||
return require('vm').isContext === undefined; | ||
function Sandbox() { | ||
} | ||
function Sandbox(options) { | ||
var klass; | ||
if (isLegacyVM()) { | ||
klass = require('./sandboxes/contextify'); | ||
} else { | ||
klass = require('./sandboxes/vm'); | ||
} | ||
return new klass(options); | ||
} | ||
Sandbox.prototype.init = function(options) { | ||
@@ -63,4 +50,2 @@ this.globals = options.globals; | ||
Sandbox.isLegacyVM = isLegacyVM; | ||
module.exports = Sandbox; |
{ | ||
"name": "fastboot", | ||
"version": "0.0.1", | ||
"version": "0.0.2", | ||
"description": "Library for rendering Ember apps in node.js", | ||
"main": "./lib/server", | ||
"scripts": { | ||
"postinstall": "scripts/is-not-legacy-vm || npm install contextify@^0.1.11", | ||
"test": "mocha" | ||
@@ -23,5 +21,2 @@ }, | ||
}, | ||
"bin": { | ||
"ember-fastboot": "./bin/ember-fastboot" | ||
}, | ||
"homepage": "https://github.com/ember-fastboot/ember-fastboot-server#readme", | ||
@@ -32,2 +27,3 @@ "dependencies": { | ||
"debug": "^2.1.0", | ||
"exists-sync": "0.0.3", | ||
"express": "^4.13.3", | ||
@@ -47,2 +43,3 @@ "express-cluster": "0.0.4", | ||
"mocha": "^2.4.5", | ||
"mocha-jshint": "^2.3.1", | ||
"request-promise": "^2.0.1", | ||
@@ -49,0 +46,0 @@ "temp": "^0.8.3" |
@@ -1,8 +0,6 @@ | ||
# Ember FastBoot Server | ||
# FastBoot | ||
[![Build Status](https://travis-ci.org/ember-fastboot/ember-fastboot-server.svg?branch=master)](https://travis-ci.org/ember-fastboot/ember-fastboot-server) | ||
The Ember FastBoot Server is used to render Ember.js applications on the | ||
server and deliver them to clients over HTTP. This server is meant to be | ||
run in a production environment. | ||
FastBoot is a library for rendering Ember.js applications in Node.js. | ||
@@ -15,14 +13,26 @@ For more information about FastBoot, see | ||
The FastBoot server requires Node 0.12 or later. | ||
To serve server-rendered versions of your Ember app over HTTP, see the | ||
[FastBoot App | ||
Server](https://github.com/ember-fastboot/fastboot-app-server). | ||
FastBoot requires Node.js v4 or later. | ||
## Usage | ||
The FastBoot server supports two modes of usage: | ||
```js | ||
const FastBoot = require('fastboot'); | ||
1. Running as a binary from the command line. | ||
2. Running programmatically as an Express middleware. | ||
let app = new FastBoot({ | ||
distPath: 'path/to/dist' | ||
}); | ||
In both cases, you will first need to build your Ember application, | ||
which packages it up for using in both the browser and in Node.js. | ||
app.visit('/photos') | ||
.then(result => result.html()) | ||
.then(html => res.send(html)); | ||
``` | ||
In order to get a `dist` directory, you will first need to build your | ||
Ember application, which packages it up for using in both the browser | ||
and in Node.js. | ||
### Build Your App | ||
@@ -56,33 +66,5 @@ | ||
### Middleware | ||
### Debugging | ||
Alternatively, you can integrate the FastBoot server into an existing | ||
Node.js application by constructing a `FastBootServer` and using it as a | ||
middleware. | ||
```js | ||
var server = new FastBootServer({ | ||
distPath: 'path/to/dist' | ||
}); | ||
var app = express(); | ||
app.get('/*', server.middleware()); | ||
var listener = app.listen(process.env.PORT || 3000, function() { | ||
var host = listener.address().address; | ||
var port = listener.address().port; | ||
console.log('FastBoot running at http://' + host + ":" + port); | ||
}); | ||
``` | ||
You can also serve Ember's static assets (compiled JavaScript and CSS files) or public | ||
files (like images or fonts) without using a CDN by adding extra routes: | ||
```js | ||
app.use('/assets', express.static('dist/assets')); | ||
app.use('/images', express.static('dist/images')); | ||
app.use('/fonts', express.static('dist/fonts')); | ||
app.get('/*', server.middleware()); | ||
``` | ||
Run `fastboot` with the `DEBUG` environment variable set to `fastboot:*` | ||
for detailed logging. |
@@ -0,1 +1,3 @@ | ||
/* jshint expr:true */ | ||
var expect = require('chai').expect; | ||
@@ -12,3 +14,3 @@ var path = require('path'); | ||
}; | ||
var headers = new FastBootHeaders(headers); | ||
headers = new FastBootHeaders(headers); | ||
@@ -25,3 +27,3 @@ expect(headers.getAll('X-Test-Header')).to.deep.equal(['value1', 'value2']); | ||
}; | ||
var headers = new FastBootHeaders(headers); | ||
headers = new FastBootHeaders(headers); | ||
@@ -38,3 +40,3 @@ expect(headers.getAll('Host')).to.deep.equal([]); | ||
}; | ||
var headers = new FastBootHeaders(headers); | ||
headers = new FastBootHeaders(headers); | ||
@@ -51,3 +53,3 @@ expect(headers.get('X-Test-Header')).to.equal('value1'); | ||
}; | ||
var headers = new FastBootHeaders(headers); | ||
headers = new FastBootHeaders(headers); | ||
@@ -58,3 +60,3 @@ expect(headers.get('Host')).to.be.null; | ||
it('returns whether or not a header is present via has, regardless of case', function() { | ||
it('returns whether or not a header is present via has, regardless of casing', function() { | ||
var headers = { | ||
@@ -65,3 +67,3 @@ // Express concatenates repeated keys with ', ' | ||
}; | ||
var headers = new FastBootHeaders(headers); | ||
headers = new FastBootHeaders(headers); | ||
@@ -73,3 +75,84 @@ expect(headers.has('X-Test-Header')).to.be.true; | ||
}); | ||
it('appends entries onto a header, regardless of casing', function() { | ||
var headers = new FastBootHeaders(); | ||
expect(headers.has('x-foo')).to.be.false; | ||
headers.append('X-Foo', 'bar'); | ||
expect(headers.has('x-foo')).to.be.true; | ||
expect(headers.getAll('x-foo')).to.deep.equal(['bar']); | ||
headers.append('X-Foo', 'baz'); | ||
expect(headers.getAll('x-foo')).to.deep.equal(['bar', 'baz']); | ||
}); | ||
it('deletes entries onto a header, regardless of casing', function() { | ||
var headers = new FastBootHeaders(); | ||
headers.append('X-Foo', 'bar'); | ||
expect(headers.has('x-foo')).to.be.true; | ||
headers.delete('X-Foo'); | ||
expect(headers.has('x-foo')).to.be.false; | ||
}); | ||
it('returns an iterator for the header/value pairs when calling entries', function() { | ||
var headers = new FastBootHeaders(); | ||
headers.append('X-Foo', 'foo'); | ||
headers.append('X-Foo', 'baz'); | ||
headers.append('x-bar', 'bar'); | ||
var entriesIterator = headers.entries(); | ||
expect(entriesIterator.next()).to.deep.equal({ value: ['x-foo', 'foo'], done: false }); | ||
expect(entriesIterator.next()).to.deep.equal({ value: ['x-foo', 'baz'], done: false }); | ||
expect(entriesIterator.next()).to.deep.equal({ value: ['x-bar', 'bar'], done: false }); | ||
expect(entriesIterator.next()).to.deep.equal({ value: undefined, done: true }); | ||
}); | ||
it('returns an iterator for keys containing all the keys', function() { | ||
var headers = new FastBootHeaders(); | ||
headers.append('X-Foo', 'foo'); | ||
headers.append('X-Foo', 'baz'); | ||
headers.append('x-bar', 'bar'); | ||
var entriesIterator = headers.keys(); | ||
expect(entriesIterator.next()).to.deep.equal({ value: 'x-foo', done: false }); | ||
expect(entriesIterator.next()).to.deep.equal({ value: 'x-foo', done: false }); | ||
expect(entriesIterator.next()).to.deep.equal({ value: 'x-bar', done: false }); | ||
expect(entriesIterator.next()).to.deep.equal({ value: undefined, done: true }); | ||
}); | ||
it('sets a header, overwriting existing values, regardless of casing', function() { | ||
var headers = new FastBootHeaders(); | ||
expect(headers.getAll('x-foo')).to.deep.equal([]); | ||
expect(headers.getAll('x-bar')).to.deep.equal([]); | ||
headers.append('X-Foo', 'foo'); | ||
expect(headers.getAll('x-foo')).to.deep.equal(['foo']); | ||
headers.set('x-foo', 'bar'); | ||
expect(headers.getAll('X-foo')).to.deep.equal(['bar']); | ||
headers.set('X-Bar', 'baz'); | ||
expect(headers.getAll('x-bar')).to.deep.equal(['baz']); | ||
}); | ||
it('returns an iterator for values containing all the values', function() { | ||
var headers = new FastBootHeaders(); | ||
headers.append('X-Foo', 'foo'); | ||
headers.append('X-Foo', 'baz'); | ||
headers.append('x-bar', 'bar'); | ||
var entriesIterator = headers.values(); | ||
expect(entriesIterator.next()).to.deep.equal({ value: 'foo', done: false }); | ||
expect(entriesIterator.next()).to.deep.equal({ value: 'baz', done: false }); | ||
expect(entriesIterator.next()).to.deep.equal({ value: 'bar', done: false }); | ||
expect(entriesIterator.next()).to.deep.equal({ value: undefined, done: true }); | ||
}); | ||
}); | ||
var expect = require('chai').expect; | ||
var path = require('path'); | ||
var FastBootInfo = require('../lib/fastboot-info.js'); | ||
var FastBootResponse = require('../lib/fastboot-response.js'); | ||
var FastBootRequest = require('../lib/fastboot-request.js'); | ||
describe("FastBootInfo", function() { | ||
it("has a FastBootRequest", function() { | ||
var response = {}; | ||
var request = { | ||
var response; | ||
var request; | ||
var fastbootInfo; | ||
beforeEach(function () { | ||
response = {}; | ||
request = { | ||
cookie: "", | ||
@@ -17,7 +23,14 @@ protocol: "http", | ||
}; | ||
var fastbootInfo = new FastBootInfo(request, response); | ||
expect(fastbootInfo.request.protocol).to.equal("http"); | ||
fastbootInfo = new FastBootInfo(request, response); | ||
}); | ||
it("has a FastBootRequest", function() { | ||
expect(fastbootInfo.request).to.be.an.instanceOf(FastBootRequest); | ||
}); | ||
it("has a FastBootResponse", function() { | ||
expect(fastbootInfo.response).to.be.an.instanceOf(FastBootResponse); | ||
}); | ||
}); | ||
@@ -35,3 +35,3 @@ var expect = require('chai').expect; | ||
}; | ||
var hostWhitelist = ["example.com", "localhost:4200"] | ||
var hostWhitelist = ["example.com", "localhost:4200"]; | ||
var fastbootRequest = new FastBootRequest(request, hostWhitelist); | ||
@@ -56,3 +56,3 @@ | ||
}; | ||
var hostWhitelist = ["example.com", "localhost:4200"] | ||
var hostWhitelist = ["example.com", "localhost:4200"]; | ||
var fastbootRequest = new FastBootRequest(request, hostWhitelist); | ||
@@ -75,3 +75,3 @@ | ||
}; | ||
var hostWhitelist = ["example.com", "/localhost:\\d+/"] | ||
var hostWhitelist = ["example.com", "/localhost:\\d+/"]; | ||
var fastbootRequest = new FastBootRequest(request, hostWhitelist); | ||
@@ -78,0 +78,0 @@ |
var express = require('express'); | ||
var RSVP = require('rsvp'); | ||
var FastBootServer = require('../../lib/server.js'); | ||
var FastBoot = require('../../index'); | ||
@@ -17,3 +17,3 @@ function TestHTTPServer(options) { | ||
var options = this.options; | ||
var server = new FastBootServer(options); | ||
var server = new FastBoot(options); | ||
var self = this; | ||
@@ -23,3 +23,3 @@ | ||
return server.app.buildApp().then(function() { | ||
return server._app.buildAppInstance().then(function() { | ||
var app = express(); | ||
@@ -48,3 +48,3 @@ | ||
TestHTTPServer.prototype.withFastBootServer = function(cb) { | ||
TestHTTPServer.prototype.withFastBoot = function(cb) { | ||
return cb(this.server); | ||
@@ -51,0 +51,0 @@ }; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Install scripts
Supply chain riskInstall scripts are run when the package is installed. The majority of malware in npm is hidden in install scripts.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
17899912
51
213818
0
4
0
12
7
69
+ Addedexists-sync@0.0.3
+ Addedexists-sync@0.0.3(transitive)