Socket
Socket
Sign inDemoInstall

@hapi/hapi

Package Overview
Dependencies
Maintainers
1
Versions
48
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@hapi/hapi - npm Package Compare versions

Comparing version 18.4.0 to 19.0.0

102

lib/auth.js

@@ -17,12 +17,14 @@ 'use strict';

#core = null;
#schemes = {};
#strategies = {};
api = {};
settings = {
default: null // Strategy used as default if route has no auth settings
};
constructor(core) {
this._core = core;
this._schemes = {};
this._strategies = {};
this.settings = {
default: null // Strategy used as default if route has no auth settings
};
this.api = {};
this.#core = core;
}

@@ -33,6 +35,6 @@

Hoek.assert(name, 'Authentication scheme must have a name');
Hoek.assert(!this._schemes[name], 'Authentication scheme name already exists:', name);
Hoek.assert(!this.#schemes[name], 'Authentication scheme name already exists:', name);
Hoek.assert(typeof scheme === 'function', 'scheme must be a function:', name);
this._schemes[name] = scheme;
this.#schemes[name] = scheme;
}

@@ -44,8 +46,8 @@

Hoek.assert(typeof options === 'object', 'options must be an object');
Hoek.assert(!this._strategies[name], 'Authentication strategy name already exists');
Hoek.assert(!this.#strategies[name], 'Authentication strategy name already exists');
Hoek.assert(scheme, 'Authentication strategy', name, 'missing scheme');
Hoek.assert(this._schemes[scheme], 'Authentication strategy', name, 'uses unknown scheme:', scheme);
Hoek.assert(this.#schemes[scheme], 'Authentication strategy', name, 'uses unknown scheme:', scheme);
server = server._clone();
const strategy = this._schemes[scheme](server, options);
const strategy = this.#schemes[scheme](server, options);

@@ -59,3 +61,3 @@ Hoek.assert(strategy.authenticate, 'Invalid scheme:', name, 'missing authenticate() method');

this._strategies[name] = {
this.#strategies[name] = {
methods: strategy,

@@ -77,3 +79,3 @@ realm: server.realm

const routes = this._core.router.table();
const routes = this.#core.router.table();
for (const route of routes) {

@@ -87,3 +89,3 @@ route.rebuild();

Hoek.assert(name, 'Missing authentication strategy name');
const strategy = this._strategies[name];
const strategy = this.#strategies[name];
Hoek.assert(strategy, 'Unknown authentication strategy:', name);

@@ -118,3 +120,3 @@

const strategy = this._strategies[auth.strategy];
const strategy = this.#strategies[auth.strategy];
Hoek.assert(strategy, 'Unknown authentication strategy:', auth.strategy);

@@ -189,3 +191,3 @@

for (const name of options.strategies) {
const strategy = this._strategies[name];
const strategy = this.#strategies[name];
Hoek.assert(strategy, 'Unknown authentication strategy', name, 'in', path);

@@ -228,3 +230,3 @@

for (const name of config.strategies) {
const strategy = this._strategies[name];
const strategy = this.#strategies[name];
if (strategy.methods[type]) {

@@ -261,3 +263,3 @@ return true;

for (const name of config.strategies) {
const strategy = this._strategies[name];
const strategy = this.#strategies[name];

@@ -377,3 +379,3 @@ const bind = strategy.methods;

const auth = request._core.auth;
const strategy = auth._strategies[request.auth.strategy];
const strategy = auth.#strategies[request.auth.strategy];
Hoek.assert(strategy, 'Unknown authentication strategy:', request.auth.strategy);

@@ -398,3 +400,3 @@

return (setting === 'optional' ? undefined : Boom.unauthorized('Missing payload authentication'));
return setting === 'optional' ? undefined : Boom.unauthorized('Missing payload authentication');
}

@@ -412,3 +414,3 @@

const strategy = auth._strategies[request.auth.strategy];
const strategy = auth.#strategies[request.auth.strategy];
Hoek.assert(strategy, 'Unknown authentication strategy:', request.auth.strategy);

@@ -439,4 +441,4 @@

const prefix = value[0];
const type = (prefix === '+' ? 'required' : (prefix === '!' ? 'forbidden' : 'selection'));
const clean = (type === 'selection' ? value : value.slice(1));
const type = prefix === '+' ? 'required' : (prefix === '!' ? 'forbidden' : 'selection');
const clean = type === 'selection' ? value : value.slice(1);
scope[type] = scope[type] || [];

@@ -460,15 +462,16 @@ scope[type].push(clean);

result = result || {};
request.auth.isAuthenticated = !err;
// Unauthenticated
if (err) {
if (err) {
// Non-error response
if (err instanceof Error === false) {
request._log(['auth', 'unauthenticated', 'response', name], { statusCode: err.statusCode });
return err; // Non-error response
return err;
}
// Missing authenticated
if (err.isMissing) {
// Try next strategy
request._log(['auth', 'unauthenticated', 'missing', name], err);

@@ -478,24 +481,25 @@ errors.push(err.output.headers['WWW-Authenticate']);

}
}
if (config.mode === 'try') {
request.auth.isAuthenticated = false;
request.auth.strategy = name;
request.auth.credentials = result.credentials;
request.auth.artifacts = result.artifacts;
request.auth.error = err;
request._log(['auth', 'unauthenticated', 'try', name], err);
return;
}
request.auth.strategy = name;
request.auth.credentials = result.credentials;
request.auth.artifacts = result.artifacts;
request._log(['auth', 'unauthenticated', 'error', name], err);
throw err;
// Authenticated
if (!err) {
return;
}
// Authenticated
// Unauthenticated
const credentials = result.credentials;
request.auth.strategy = name;
request.auth.credentials = credentials;
request.auth.artifacts = result.artifacts;
request.auth.isAuthenticated = true;
request.auth.error = err;
if (config.mode === 'try') {
request._log(['auth', 'unauthenticated', 'try', name], err);
return;
}
request._log(['auth', 'unauthenticated', 'error', name], err);
throw err;
};

@@ -549,3 +553,3 @@

const count = typeof credentials.scope === 'string' ?
(scope[type].indexOf(credentials.scope) !== -1 ? 1 : 0) :
scope[type].indexOf(credentials.scope) !== -1 ? 1 : 0 :
Hoek.intersect(scope[type], credentials.scope).length;

@@ -552,0 +556,0 @@

@@ -17,16 +17,19 @@ 'use strict';

constructor() {
decoders = {
gzip: (options) => Zlib.createGunzip(options),
deflate: (options) => Zlib.createInflate(options)
};
this.encodings = ['identity', 'gzip', 'deflate'];
this._encoders = {
identity: null,
gzip: (options) => Zlib.createGzip(options),
deflate: (options) => Zlib.createDeflate(options)
};
encodings = ['identity', 'gzip', 'deflate'];
this._decoders = {
gzip: (options) => Zlib.createGunzip(options),
deflate: (options) => Zlib.createInflate(options)
};
encoders = {
identity: null,
gzip: (options) => Zlib.createGzip(options),
deflate: (options) => Zlib.createDeflate(options)
};
#common = null;
constructor() {
this._updateCommons();

@@ -37,7 +40,7 @@ }

this._common = new Map();
internals.common.forEach((header) => {
this.#common = new Map();
this._common.set(header, Accept.encoding(header, this.encodings));
});
for (const header of internals.common) {
this.#common.set(header, Accept.encoding(header, this.encodings));
}
}

@@ -47,5 +50,5 @@

Hoek.assert(this._encoders[encoding] === undefined, `Cannot override existing encoder for ${encoding}`);
Hoek.assert(this.encoders[encoding] === undefined, `Cannot override existing encoder for ${encoding}`);
Hoek.assert(typeof encoder === 'function', `Invalid encoder function for ${encoding}`);
this._encoders[encoding] = encoder;
this.encoders[encoding] = encoder;
this.encodings.unshift(encoding);

@@ -57,5 +60,5 @@ this._updateCommons();

Hoek.assert(this._decoders[encoding] === undefined, `Cannot override existing decoder for ${encoding}`);
Hoek.assert(this.decoders[encoding] === undefined, `Cannot override existing decoder for ${encoding}`);
Hoek.assert(typeof decoder === 'function', `Invalid decoder function for ${encoding}`);
this._decoders[encoding] = decoder;
this.decoders[encoding] = decoder;
}

@@ -66,3 +69,7 @@

const header = request.headers['accept-encoding'];
const common = this._common.get(header);
if (!header) {
return 'identity';
}
const common = this.#common.get(header);
if (common) {

@@ -113,3 +120,3 @@ return common;

const encoder = this._encoders[encoding];
const encoder = this.encoders[encoding];
Hoek.assert(encoder !== undefined, `Unknown encoding ${encoding}`);

@@ -116,0 +123,0 @@ return encoder(request.route.settings.compression[encoding]);

@@ -16,3 +16,3 @@ 'use strict';

const result = Joi.validate(options, internals[type]);
const result = internals[type].validate(options);

@@ -29,3 +29,3 @@ if (result.error) {

const settings = (options ? Object.assign({}, options) : {}); // Shallow cloned
const settings = options ? Object.assign({}, options) : {}; // Shallow cloned

@@ -68,3 +68,3 @@ if (settings.security === true) {

internals.event = Joi.object({
method: Joi.array().items(Joi.func()).single(),
method: Joi.array().items(Joi.function()).single(),
options: Joi.object({

@@ -81,3 +81,4 @@ before: Joi.array().items(Joi.string()).single(),

internals.exts = Joi.array().items(internals.event.keys({ type: Joi.string().required() })).single();
internals.exts = Joi.array()
.items(internals.event.keys({ type: Joi.string().required() })).single();

@@ -87,3 +88,3 @@

Joi.valid('error', 'log', 'ignore'),
Joi.func()
Joi.function()
])

@@ -130,7 +131,7 @@ .default('error');

files: Joi.object({
relativeTo: Joi.string().regex(/^([\/\.])|([A-Za-z]:\\)|(\\\\)/).default('.')
relativeTo: Joi.string().pattern(/^([\/\.])|([A-Za-z]:\\)|(\\\\)/).default('.')
})
.default(),
json: Joi.object({
replacer: Joi.alternatives(Joi.func(), Joi.array()).allow(null).default(null),
replacer: Joi.alternatives(Joi.function(), Joi.array()).allow(null).default(null),
space: Joi.number().allow(null).default(null),

@@ -152,3 +153,5 @@ suffix: Joi.string().allow(null).default(null),

})
.allow(false),
.default(false)
.allow(true, false)
.when('.', { is: true, then: Joi.object().strip() }),
allow: Joi.array().items(Joi.string()).single(),

@@ -170,13 +173,12 @@ override: Joi.string(),

disconnectStatusCode: Joi.number().integer().min(400).default(499),
emptyStatusCode: Joi.valid(200, 204).default(200),
emptyStatusCode: Joi.valid(200, 204).default(204),
failAction: internals.failAction,
modify: Joi.boolean(),
options: Joi.object().default(),
options: Joi.object(),
ranges: Joi.boolean().default(true),
sample: Joi.number().min(0).max(100).when('modify', { is: true, then: Joi.forbidden() }),
schema: Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(true, false),
status: Joi.object().pattern(/\d\d\d/, Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(true, false))
sample: Joi.number().min(0).max(100).when('modify', { then: Joi.forbidden() }),
schema: Joi.alternatives(Joi.object(), Joi.array(), Joi.function()).allow(true, false),
status: Joi.object().pattern(/\d\d\d/, Joi.alternatives(Joi.object(), Joi.array(), Joi.function()).allow(true, false))
})
.default()
.assert('options.stripUnknown', Joi.when('modify', { is: true, otherwise: false }), 'meet requirement of having peer modify set to true'),
.default(),
security: Joi.object({

@@ -227,10 +229,11 @@ hsts: Joi.alternatives([

validate: Joi.object({
headers: Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(null, true),
params: Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(null, true),
query: Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(null, false, true),
payload: Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(null, false, true),
state: Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(null, false, true),
headers: Joi.alternatives(Joi.object(), Joi.array(), Joi.function()).allow(null, true),
params: Joi.alternatives(Joi.object(), Joi.array(), Joi.function()).allow(null, true),
query: Joi.alternatives(Joi.object(), Joi.array(), Joi.function()).allow(null, false, true),
payload: Joi.alternatives(Joi.object(), Joi.array(), Joi.function()).allow(null, false, true),
state: Joi.alternatives(Joi.object(), Joi.array(), Joi.function()).allow(null, false, true),
failAction: internals.failAction,
errorFields: Joi.object(),
options: Joi.object().default()
options: Joi.object().default(),
validator: Joi.object()
})

@@ -260,4 +263,3 @@ .default()

load: Joi.object({
sampleInterval: Joi.number().integer().min(0).default(0),
concurrent: Joi.number().integer().min(0).default(0)
sampleInterval: Joi.number().integer().min(0).default(0)
})

@@ -274,8 +276,8 @@ .unknown()

Joi.number().integer().min(0), // TCP port
Joi.string().regex(/\//), // Unix domain socket
Joi.string().regex(/^\\\\\.\\pipe\\/) // Windows named pipe
Joi.string().pattern(/\//), // Unix domain socket
Joi.string().pattern(/^\\\\\.\\pipe\\/) // Windows named pipe
])
.allow(null),
query: Joi.object({
parser: Joi.func()
parser: Joi.function()
})

@@ -294,3 +296,3 @@ .default(),

]),
uri: Joi.string().regex(/[^/]$/)
uri: Joi.string().pattern(/[^/]$/)
});

@@ -306,3 +308,3 @@

internals.handler = Joi.alternatives([
Joi.func(),
Joi.function(),
Joi.object().length(1)

@@ -313,3 +315,3 @@ ]);

internals.route = Joi.object({
method: Joi.string().regex(/^[a-zA-Z0-9!#\$%&'\*\+\-\.^_`\|~]+$/).required(),
method: Joi.string().pattern(/^[a-zA-Z0-9!#\$%&'\*\+\-\.^_`\|~]+$/).required(),
path: Joi.string().required(),

@@ -329,5 +331,5 @@ rules: Joi.object(),

internals.pre = [
Joi.func(),
Joi.function(),
Joi.object({
method: Joi.alternatives(Joi.string(), Joi.func()).required(),
method: Joi.alternatives(Joi.string(), Joi.function()).required(),
assign: Joi.string(),

@@ -348,3 +350,3 @@ mode: Joi.valid('serial', 'parallel'),

],
pre: Joi.array().items(internals.pre.concat(Joi.array().items(internals.pre).min(1))),
pre: Joi.array().items(...internals.pre.concat(Joi.array().items(...internals.pre).min(1))),
tags: [

@@ -358,3 +360,3 @@ Joi.string(),

internals.cacheConfig = Joi.alternatives([
Joi.func(),
Joi.function(),
Joi.object({

@@ -364,5 +366,5 @@ name: Joi.string().invalid('_default'),

provider: [
Joi.func(),
Joi.function(),
{
constructor: Joi.func().required(),
constructor: Joi.function().required(),
options: Joi.object({

@@ -394,3 +396,3 @@ partition: Joi.string().default('hapi-cache')

bind: Joi.object().allow(null),
generateKey: Joi.func(),
generateKey: Joi.function(),
cache: internals.cachePolicy

@@ -402,3 +404,3 @@ });

name: Joi.string().required(),
method: Joi.func().required(),
method: Joi.function().required(),
options: Joi.object()

@@ -411,3 +413,3 @@ });

routes: Joi.object({
prefix: Joi.string().regex(/^\/.+/),
prefix: Joi.string().pattern(/^\/.+/),
vhost: internals.vhost

@@ -425,3 +427,3 @@ })

plugin: Joi.object({
register: Joi.func().required(),
register: Joi.function().required(),
name: Joi.string().when('pkg.name', { is: Joi.exist(), otherwise: Joi.required() }),

@@ -428,0 +430,0 @@ version: Joi.string(),

@@ -29,2 +29,3 @@ 'use strict';

const Toolkit = require('./toolkit');
const Validation = require('./validation');

@@ -51,6 +52,63 @@

actives = new WeakMap(); // Active requests being processed
app = {};
auth = new Auth(this);
caches = new Map(); // Cache clients
compression = new Compression();
controlled = null; // Other servers linked to the phases of this server
dependencies = []; // Plugin dependencies
events = new Podium(internals.events);
heavy = null;
info = null;
instances = new Set();
listener = null;
methods = new Methods(this); // Server methods
mime = null;
onConnection = null; // Used to remove event listener on stop
phase = 'stopped'; // 'stopped', 'initializing', 'initialized', 'starting', 'started', 'stopping', 'invalid'
plugins = {}; // Exposed plugin properties by name
registrations = {}; // Tracks plugin for dependency validation { name -> { version } }
registring = 0; // > 0 while register() is waiting for plugin callbacks
Request = class extends Request { };
requestCounter = { value: internals.counter.min, min: internals.counter.min, max: internals.counter.max };
root = null;
router = null;
settings = null;
sockets = null; // Track open sockets for graceful shutdown
started = false;
states = null;
toolkit = new Toolkit.Manager();
type = null;
validator = null;
extensionsSeq = 0; // Used to keep absolute order of extensions based on the order added across locations
extensions = {
server: {
onPreStart: new Ext('onPreStart', this),
onPostStart: new Ext('onPostStart', this),
onPreStop: new Ext('onPreStop', this),
onPostStop: new Ext('onPostStop', this)
},
route: {
onRequest: new Ext('onRequest', this),
onPreAuth: new Ext('onPreAuth', this),
onCredentials: new Ext('onCredentials', this),
onPostAuth: new Ext('onPostAuth', this),
onPreHandler: new Ext('onPreHandler', this),
onPostHandler: new Ext('onPostHandler', this),
onPreResponse: new Ext('onPreResponse', this)
}
};
decorations = {
handler: new Map(),
request: new Map(),
server: new Map(),
toolkit: new Map(),
requestApply: null,
public: { handler: [], request: [], server: [], toolkit: [] }
};
constructor(options) {
this.root = null; // Dispatch reference of the root server
const { settings, type } = internals.setup(options);

@@ -61,53 +119,14 @@

this.app = {};
this.auth = new Auth(this);
this.caches = new Map(); // Cache clients
this.compression = new Compression();
this.controlled = null; // Other servers linked to the phases of this server
this.decorations = { handler: [], request: [], server: [], toolkit: [] }; // Public decoration names
this.dependencies = []; // Plugin dependencies
this.events = new Podium(internals.events);
this.heavy = new Heavy(this.settings.load);
this.instances = new Set();
this.methods = new Methods(this); // Server methods
this.mime = new Mimos(this.settings.mime);
this.onConnection = null; // Used to remove event listener on stop
this.plugins = {}; // Exposed plugin properties by name
this.queue = new internals.Queue(this.settings.load);
this.registrations = {}; // Tracks plugin for dependency validation { name -> { version } }
this.registring = 0; // > 0 while register() is waiting for plugin callbacks
this.requestCounter = { value: internals.counter.min, min: internals.counter.min, max: internals.counter.max };
this.router = new Call.Router(this.settings.router);
this.phase = 'stopped'; // 'stopped', 'initializing', 'initialized', 'starting', 'started', 'stopping', 'invalid'
this.sockets = null; // Track open sockets for graceful shutdown
this.actives = new WeakMap(); // Active requests being processed
this.started = false;
this.states = new Statehood.Definitions(this.settings.state);
this.toolkit = new Toolkit();
this.extensionsSeq = 0; // Used to keep absolute order of extensions based on the order added across locations
this.extensions = {
server: {
onPreStart: new Ext('onPreStart', this),
onPostStart: new Ext('onPostStart', this),
onPreStop: new Ext('onPreStop', this),
onPostStop: new Ext('onPostStop', this)
},
route: {
onRequest: new Ext('onRequest', this),
onPreAuth: new Ext('onPreAuth', this),
onCredentials: new Ext('onCredentials', this),
onPostAuth: new Ext('onPostAuth', this),
onPreHandler: new Ext('onPreHandler', this),
onPostHandler: new Ext('onPostHandler', this),
onPreResponse: new Ext('onPreResponse', this)
}
};
this.Request = class extends Request { };
this._debug();
this._decorations = { handler: {}, request: {}, server: {}, toolkit: {}, requestApply: null };
this._initializeCache();
if (this.settings.routes.validate.validator) {
this.validator = Validation.validator(this.settings.routes.validate.validator);
}
this.listener = this._createListener();

@@ -120,20 +139,23 @@ this._initializeListener();

const debug = this.settings.debug;
if (!debug) {
return;
}
// Subscribe to server log events
if (this.settings.debug) {
const debug = (request, event) => {
const method = (event) => {
const data = event.error || event.data;
console.error('Debug:', event.tags.join(', '), data ? '\n ' + (data.stack || (typeof data === 'object' ? Hoek.stringify(data) : data)) : '');
};
const data = event.error || event.data;
console.error('Debug:', event.tags.join(', '), data ? '\n ' + (data.stack || (typeof data === 'object' ? Hoek.stringify(data) : data)) : '');
};
if (this.settings.debug.log) {
const filter = this.settings.debug.log.some((tag) => tag === '*') ? undefined : this.settings.debug.log;
this.events.on({ name: 'log', filter }, (event) => debug(null, event));
}
if (debug.log) {
const filter = debug.log.some((tag) => tag === '*') ? undefined : debug.log;
this.events.on({ name: 'log', filter }, method);
}
if (this.settings.debug.request) {
const filter = this.settings.debug.request.some((tag) => tag === '*') ? undefined : this.settings.debug.request;
this.events.on({ name: 'request', filter }, debug);
}
if (debug.request) {
const filter = debug.request.some((tag) => tag === '*') ? undefined : debug.request;
this.events.on({ name: 'request', filter }, (request, event) => method(event));
}

@@ -173,2 +195,13 @@ }

_counter() {
const next = ++this.requestCounter.value;
if (this.requestCounter.value > this.requestCounter.max) {
this.requestCounter.value = this.requestCounter.min;
}
return next - 1;
}
_createCache(configs) {

@@ -408,3 +441,6 @@

this.sockets.forEach((connection) => connection.destroy());
for (const connection of this.sockets) {
connection.destroy();
}
this.sockets.clear();

@@ -417,8 +453,7 @@ };

this.sockets.forEach((connection) => {
for (const connection of this.sockets) {
if (!this.actives.has(connection)) {
connection.end();
}
});
}
}

@@ -479,3 +514,5 @@

if (req.socket) {
if (this.settings.operations.cleanStop &&
req.socket) {
this.actives.set(req.socket, request);

@@ -500,3 +537,3 @@ const env = { core: this, req };

this.queue.add(request);
request._execute();
};

@@ -516,3 +553,3 @@ }

if (socket.readable) {
const request = this.actives.get(socket);
const request = this.settings.operations.cleanStop && this.actives.get(socket);
if (request) {

@@ -661,43 +698,1 @@ const error = Boom.badRequest();

};
internals.Queue = class {
constructor(options) {
this.settings = options;
this.active = 0;
this.queue = [];
}
add(request) {
if (this.settings.concurrent) {
this.queue.push(request);
this.next();
}
else {
request._execute();
}
}
next() {
if (this.queue.length &&
this.active < this.settings.concurrent) {
const request = this.queue.shift();
++this.active;
request._execute();
}
}
release() {
if (this.settings.concurrent) {
--this.active;
this.next();
}
}
};

@@ -12,10 +12,13 @@ 'use strict';

type = null;
nodes = null;
#core = null;
#routes = [];
#topo = new Topo.Sorter();
constructor(type, core) {
this._topo = new Topo();
this._core = core;
this._routes = [];
this.#core = core;
this.type = type;
this.nodes = null;
}

@@ -31,3 +34,3 @@

group: event.realm.plugin,
sort: this._core.extensionsSeq++
sort: this.#core.extensionsSeq++
};

@@ -43,10 +46,10 @@

this._topo.add(node, settings);
this.#topo.add(node, settings);
}
this.nodes = this._topo.nodes;
this.nodes = this.#topo.nodes;
// Notify routes
for (const route of this._routes) {
for (const route of this.#routes) {
route.rebuild(event);

@@ -60,7 +63,7 @@ }

for (const other of others) {
merge.push(other._topo);
merge.push(other.#topo);
}
this._topo.merge(merge);
this.nodes = (this._topo.nodes.length ? this._topo.nodes : null);
this.#topo.merge(merge);
this.nodes = this.#topo.nodes.length ? this.#topo.nodes : null;
}

@@ -70,3 +73,3 @@

this._routes.push(route);
this.#routes.push(route);
}

@@ -73,0 +76,0 @@

@@ -87,3 +87,3 @@ 'use strict';

const type = Object.keys(handler)[0];
const serverHandler = core._decorations.handler[type];
const serverHandler = core.decorations.handler.get(type);

@@ -105,3 +105,3 @@ Hoek.assert(serverHandler, 'Unknown handler:', type);

const type = Object.keys(handler)[0];
const serverHandler = route._core._decorations.handler[type];
const serverHandler = route._core.decorations.handler.get(type);

@@ -108,0 +108,0 @@ Hoek.assert(serverHandler, 'Unknown handler:', type);

@@ -106,3 +106,3 @@ 'use strict';

let header = await request._core.states.format(states);
let header = await request._core.states.format(states, request);
const existing = response.headers['set-cookie'];

@@ -109,0 +109,0 @@ if (existing) {

@@ -16,6 +16,9 @@ 'use strict';

methods = {};
#core = null;
constructor(core) {
this.core = core;
this.methods = {};
this.#core = core;
}

@@ -65,3 +68,3 @@

settings.cache.generateFunc = (id, flags) => bound(...id.args, flags);
const cache = this.core._cachePolicy(settings.cache, '#' + name);
const cache = this.#core._cachePolicy(settings.cache, '#' + name);

@@ -68,0 +71,0 @@ const func = function (...args) {

'use strict';
const Querystring = require('querystring');
const Url = require('url');

@@ -12,2 +13,3 @@

const Response = require('./response');
const Toolkit = require('./toolkit');
const Transmit = require('./transmit');

@@ -37,2 +39,3 @@

this._states = {};
this._url = null;
this._urlError = null;

@@ -42,3 +45,2 @@

this.headers = req.headers;
this.info = internals.info(this._core, req);
this.jsonp = null;

@@ -52,3 +54,3 @@ this.logs = [];

this.path = null;
this.payload = null;
this.payload = undefined;
this.plugins = options.plugins ? Object.assign({}, options.plugins) : {}; // Place for plugins to store state without conflicts with hapi, should be namespaced using plugin name (shallow cloned)

@@ -63,7 +65,9 @@ this.pre = {}; // Pre raw values

this.state = null;
this.url = null;
this.info = new internals.Info(this);
this.auth = {
isAuthenticated: false,
isAuthorized: false,
isInjected: options.auth ? true : false,
credentials: options.auth ? options.auth.credentials : null, // Special keys: 'app', 'user', 'scope'

@@ -76,6 +80,2 @@ artifacts: options.auth && options.auth.artifacts || null, // Scheme-specific artifacts

if (options.auth) {
this.auth.isInjected = true;
}
// Parse request url

@@ -92,5 +92,4 @@

if (server._core._decorations.requestApply) {
for (const property in server._core._decorations.requestApply) {
const assignment = server._core._decorations.requestApply[property];
if (server._core.decorations.requestApply) {
for (const [property, assignment] of server._core.decorations.requestApply.entries()) {
request[property] = assignment(request);

@@ -113,2 +112,15 @@ }

get url() {
if (this._urlError) {
return null;
}
if (this._url) {
return this._url;
}
return this._parseUrl(this.raw.req.url, this._core.settings.router);
}
_initializeUrl() {

@@ -138,35 +150,70 @@

this._setUrl(url, stripTrailingSlash);
this._urlError = null;
}
_setUrl(url, stripTrailingSlash) {
_setUrl(source, stripTrailingSlash) {
const base = url[0] === '/' ? `${this._core.info.protocol}://${this.info.host || `${this._core.info.host}:${this._core.info.port}`}` : '';
const url = this._parseUrl(source, { stripTrailingSlash, _fast: true });
this.query = this._parseQuery(url.searchParams);
this.path = url.pathname;
}
url = new Url.URL(base + url);
_parseUrl(source, options) {
// Apply path modifications
if (source[0] === '/') {
let path = this._core.router.normalize(url.pathname); // pathname excludes query
// Relative URL
if (stripTrailingSlash &&
path.length > 1 &&
path[path.length - 1] === '/') {
if (options._fast) {
const url = {
pathname: source,
searchParams: ''
};
path = path.slice(0, -1);
const q = source.indexOf('?');
const h = source.indexOf('#');
if (q !== -1 &&
(h === -1 || q < h)) {
url.pathname = source.slice(0, q);
const query = h === -1 ? source.slice(q + 1) : source.slice(q + 1, h);
url.searchParams = Querystring.parse(query);
}
else {
url.pathname = h === -1 ? source : source.slice(0, h);
}
this._normalizePath(url, options);
return url;
}
this._url = new Url.URL(`${this._core.info.protocol}://${this.info.host || `${this._core.info.host}:${this._core.info.port}`}${source}`);
}
else {
url.pathname = path;
// Absolute URI (proxied)
// Parse query (must be done before this.url is set in case query parsing throws)
this._url = new Url.URL(source);
this.info.hostname = this._url.hostname;
this.info.host = this._url.host;
}
this.query = this._parseQuery(url.searchParams);
this._normalizePath(this._url, options);
this._urlError = null;
// Store request properties
return this._url;
}
this.url = url;
this.path = path;
_normalizePath(url, options) {
this.info.hostname = url.hostname;
this.info.host = url.host;
let path = this._core.router.normalize(url.pathname);
if (options.stripTrailingSlash &&
path.length > 1 &&
path[path.length - 1] === '/') {
path = path.slice(0, -1);
}
url.pathname = path;
}

@@ -176,13 +223,19 @@

let query = Object.create(null);
// Flatten map
let query = Object.create(null);
for (let [key, value] of searchParams) {
const entry = query[key];
if (entry !== undefined) {
value = [].concat(entry, value);
if (searchParams instanceof Url.URLSearchParams) {
for (let [key, value] of searchParams) {
const entry = query[key];
if (entry !== undefined) {
value = [].concat(entry, value);
}
query[key] = value;
}
query[key] = value;
}
else {
query = Object.assign(query, searchParams);
}

@@ -330,3 +383,3 @@ // Custom parser

if (!response ||
response === this._core.toolkit.continue) { // Continue
response === Toolkit.symbols.continue) { // Continue

@@ -352,3 +405,3 @@ continue;

if (response === this._core.toolkit.continue) {
if (response === Toolkit.symbols.continue) {
continue;

@@ -422,3 +475,3 @@ }

if (response &&
response !== this._core.toolkit.continue) { // Continue
response !== Toolkit.symbols.continue) { // Continue

@@ -432,3 +485,3 @@ this._setResponse(response);

if (this.response === this._core.toolkit.close) {
if (this.response === Toolkit.symbols.close) {
this.raw.res.end(); // End the response in case it wasn't already closed

@@ -462,3 +515,2 @@ }

this._core.events.emit('response', this);
this._core.queue.release();
}

@@ -471,3 +523,3 @@

this.response !== response &&
(response.isBoom || this.response.source !== response.source)) {
this.response.source !== response.source) {

@@ -570,29 +622,46 @@ this.response._close(this);

internals.info = function (core, req) {
internals.Info = class {
const host = req.headers.host ? req.headers.host.trim() : '';
const received = Date.now();
constructor(request) {
const info = {
received,
remoteAddress: req.connection.remoteAddress,
remotePort: req.connection.remotePort || '',
referrer: req.headers.referrer || req.headers.referer || '',
host,
hostname: host.split(':')[0],
id: `${received}:${core.info.id}:${core.requestCounter.value++}`,
this._request = request;
const req = request.raw.req;
const host = req.headers.host ? req.headers.host.trim() : '';
const received = Date.now();
this.received = received;
this.referrer = req.headers.referrer || req.headers.referer || '';
this.host = host;
this.hostname = host.split(':')[0];
this.id = `${received}:${request._core.info.id}:${request._core._counter()}`;
this._remoteAddress = null;
this._remotePort = null;
// Assigned later
acceptEncoding: null,
cors: null,
responded: 0,
completed: 0
};
this.acceptEncoding = null;
this.cors = null;
this.responded = 0;
this.completed = 0;
}
if (core.requestCounter.value > core.requestCounter.max) {
core.requestCounter.value = core.requestCounter.min;
get remoteAddress() {
if (!this._remoteAddress) {
this._remoteAddress = this._request.raw.req.connection.remoteAddress;
}
return this._remoteAddress;
}
return info;
get remotePort() {
if (this._remotePort === null) {
this._remotePort = this._request.raw.req.connection.remotePort || '';
}
return this._remotePort;
}
};

@@ -599,0 +668,0 @@

@@ -111,3 +111,3 @@ 'use strict';

this._contentType = (typeof this.source === 'string' ? 'text/html' : 'application/json');
this._contentType = typeof this.source === 'string' ? 'text/html' : 'application/json';
}

@@ -714,3 +714,11 @@ }

this._prefix = '/**/' + variable + '('; // '/**/' prefix prevents CVE-2014-4671 security exploit
this._data = (this._data === null || Buffer.isBuffer(this._data)) ? this._data : this._data.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
if (this._data !== null &&
!Buffer.isBuffer(this._data)) {
this._data = this._data
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
}
this._suffix = ');';

@@ -717,0 +725,0 @@ }

@@ -40,6 +40,6 @@ 'use strict';

const path = (realm.modifiers.route.prefix ? realm.modifiers.route.prefix + (route.path !== '/' ? route.path : '') : route.path);
const path = realm.modifiers.route.prefix ? realm.modifiers.route.prefix + (route.path !== '/' ? route.path : '') : route.path;
Hoek.assert(path === '/' || path[path.length - 1] !== '/' || !core.settings.router.stripTrailingSlash, 'Path cannot end with a trailing slash when configured to strip:', route.method, route.path);
const vhost = (realm.modifiers.route.vhost || route.vhost);
const vhost = realm.modifiers.route.vhost || route.vhost;

@@ -68,3 +68,3 @@ // Set identifying members (assert)

this._assert(!route.rules || !config.rules, 'Route rules can only appear once'); // XOR
const rules = (route.rules || config.rules);
const rules = route.rules || config.rules;
const rulesConfig = internals.rules(rules, { method, path, vhost }, server);

@@ -90,3 +90,3 @@ delete config.rules;

const socketTimeout = (this.settings.timeout.socket === undefined ? 2 * 60 * 1000 : this.settings.timeout.socket);
const socketTimeout = this.settings.timeout.socket === undefined ? 2 * 60 * 1000 : this.settings.timeout.socket;
this._assert(!this.settings.timeout.server || !socketTimeout || this.settings.timeout.server < socketTimeout, 'Server timeout must be shorter than socket timeout');

@@ -133,3 +133,3 @@ this._assert(!this.settings.payload.timeout || !socketTimeout || this.settings.payload.timeout < socketTimeout, 'Payload timeout must be shorter than socket timeout');

else {
this.settings.payload.decoders = this._core.compression._decoders; // Reference the shared object to keep up to date
this.settings.payload.decoders = this._core.compression.decoders; // Reference the shared object to keep up to date
}

@@ -143,3 +143,3 @@

this.settings.auth = (this._special ? false : this._core.auth._setupRoute(this.settings.auth, path));
this.settings.auth = this._special ? false : this._core.auth._setupRoute(this.settings.auth, path);

@@ -199,6 +199,7 @@ // Cache

['headers', 'params', 'query', 'payload', 'state'].forEach((type) => {
const validator = this._validator();
validation[type] = Validation.compile(validation[type]);
});
for (const type of ['headers', 'params', 'query', 'payload', 'state']) {
validation[type] = Validation.compile(validation[type], validator);
}

@@ -220,5 +221,5 @@ if (this.settings.response.schema !== undefined ||

else {
this.settings.response.schema = Validation.compile(rule);
this.settings.response.schema = Validation.compile(rule, validator);
for (const code of statuses) {
this.settings.response.status[code] = Validation.compile(this.settings.response.status[code]);
this.settings.response.status[code] = Validation.compile(this.settings.response.status[code], validator);
}

@@ -236,3 +237,3 @@ }

if (this._special) {
this._postCycle = (this._extensions.onPreResponse.nodes ? [this._extensions.onPreResponse] : []);
this._postCycle = this._extensions.onPreResponse.nodes ? [this._extensions.onPreResponse] : [];
this._buildMarshalCycle();

@@ -382,2 +383,20 @@ return;

}
_validator() {
if (this.settings.validate.validator) {
return this.settings.validate.validator;
}
let realm = this.realm;
while (realm) {
if (realm.validator) {
return realm.validator;
}
realm = realm.parent;
}
return this._core.validator;
}
};

@@ -437,2 +456,6 @@

if (request.payload !== undefined) {
return internals.drain(request);
}
try {

@@ -450,7 +473,3 @@ const { payload, mime } = await Subtext.parse(request.raw.req, request._tap(), request.route.settings.payload);

await internals.drain(request);
request._isPayloadPending = false;
}
else {
request._isPayloadPending = true;
}

@@ -520,3 +539,3 @@ request.mime = err.mime;

if (realm._rules) {
const source = (!realm._rules.settings.validate ? rules : Joi.attempt(rules, realm._rules.settings.validate.schema, realm._rules.settings.validate.options));
const source = !realm._rules.settings.validate ? rules : Joi.attempt(rules, realm._rules.settings.validate.schema, realm._rules.settings.validate.options);
const config = realm._rules.processor(source, info);

@@ -523,0 +542,0 @@ if (config) {

@@ -15,2 +15,4 @@ 'use strict';

const Route = require('./route');
const Toolkit = require('./toolkit');
const Validation = require('./validation');

@@ -37,5 +39,5 @@

this.app = core.app;
this.auth = Object.create(this._core.auth);
this.auth = this._core.auth;
this.auth.strategy = this.auth._strategy.bind(this.auth, this);
this.decorations = core.decorations;
this.decorations = core.decorations.public;
this.cache = internals.cache(this);

@@ -67,3 +69,3 @@ this.events = core.events;

},
parent: (parent ? parent.realm : null),
parent: parent ? parent.realm : null,
plugin: name,

@@ -78,3 +80,4 @@ pluginOptions: {},

}
}
},
validator: null
};

@@ -84,4 +87,4 @@

for (const method of core.decorations.server) {
this[method] = core._decorations.server[method];
for (const [property, method] of core.decorations.server.entries()) {
this[property] = method;
}

@@ -118,3 +121,3 @@

Hoek.assert(this._core.decorations[type], 'Unknown decoration type:', type);
Hoek.assert(this._core.decorations.public[type], 'Unknown decoration type:', type);
Hoek.assert(property, 'Missing decoration property name');

@@ -126,3 +129,3 @@ Hoek.assert(typeof property === 'string' || typeof property === 'symbol', 'Decoration property must be a string or a symbol');

const existing = this._core._decorations[type][property];
const existing = this._core.decorations[type].get(property);
if (options.extend) {

@@ -151,7 +154,7 @@ Hoek.assert(type !== 'handler', 'Cannot extent handler decoration:', propertyName);

Hoek.assert(Request.reserved.indexOf(property) === -1, 'Cannot override built-in request interface decoration:', propertyName);
Hoek.assert(!Request.reserved.includes(property), 'Cannot override built-in request interface decoration:', propertyName);
if (options.apply) {
this._core._decorations.requestApply = this._core._decorations.requestApply || {};
this._core._decorations.requestApply[property] = method;
this._core.decorations.requestApply = this._core.decorations.requestApply || new Map();
this._core.decorations.requestApply.set(property, method);
}

@@ -166,3 +169,4 @@ else {

Hoek.assert(this._core.toolkit.reserved.indexOf(property) === -1, 'Cannot override built-in toolkit decoration:', propertyName);
Hoek.assert(!Toolkit.reserved.includes(property), 'Cannot override built-in toolkit decoration:', propertyName);
this._core.toolkit.decorate(property, method);
}

@@ -174,6 +178,6 @@ else {

if (typeof property === 'string') {
Hoek.assert(Object.getOwnPropertyNames(internals.Server.prototype).indexOf(property) === -1, 'Cannot override the built-in server interface method:', propertyName);
Hoek.assert(!Object.getOwnPropertyNames(internals.Server.prototype).includes(property), 'Cannot override the built-in server interface method:', propertyName);
}
else {
Hoek.assert(Object.getOwnPropertySymbols(internals.Server.prototype).indexOf(property) === -1, 'Cannot override the built-in server interface method:', propertyName);
Hoek.assert(!Object.getOwnPropertySymbols(internals.Server.prototype).includes(property), 'Cannot override the built-in server interface method:', propertyName);
}

@@ -187,4 +191,4 @@

this._core._decorations[type][property] = method;
this._core.decorations[type].push(property);
this._core.decorations[type].set(property, method);
this._core.decorations.public[type].push(property);
}

@@ -228,7 +232,16 @@

expose(key, value) {
expose(key, value, options = {}) {
Hoek.assert(this.realm.plugin, 'Cannot call expose() outside of a plugin');
const plugin = this.realm.plugin;
let plugin = this.realm.plugin;
if (plugin[0] === '@' &&
options.scope !== true) {
plugin = plugin.replace(/^\@([^\/]+)\//, ($0, $1) => {
return !options.scope ? '' : `${$1}__`;
});
}
this._core.plugins[plugin] = this._core.plugins[plugin] || {};

@@ -305,3 +318,3 @@

settings.authority = settings.authority || (this._core.info.host + ':' + this._core.info.port);
settings.authority = settings.authority || this._core.info.host + ':' + this._core.info.port;
}

@@ -534,2 +547,9 @@

validator(validator) {
Hoek.assert(!this.realm.validator, 'Validator already set');
this.realm.validator = Validation.validator(validator);
}
start() {

@@ -565,3 +585,3 @@

if (['initialized', 'starting', 'started'].indexOf(plugin._core.phase) !== -1) {
if (['initialized', 'starting', 'started'].includes(plugin._core.phase)) {
await Promise.all(clients.map((client) => client.start()));

@@ -568,0 +588,0 @@ }

@@ -21,3 +21,3 @@ 'use strict';

const team = new Teamwork();
const team = new Teamwork.Team();
stream[internals.team] = team;

@@ -24,0 +24,0 @@

@@ -10,15 +10,34 @@ 'use strict';

const internals = {
reserved: ['abandon', 'authenticated', 'close', 'context', 'continue', 'entity', 'redirect', 'realm', 'request', 'response', 'state', 'unauthenticated', 'unstate']
const internals = {};
exports.reserved = [
'abandon',
'authenticated',
'close',
'context',
'continue',
'entity',
'redirect',
'realm',
'request',
'response',
'state',
'unauthenticated',
'unstate'
];
exports.symbols = {
abandon: Symbol('abandon'),
close: Symbol('close'),
continue: Symbol('continue')
};
exports = module.exports = internals.Manager = class {
exports.Manager = class {
constructor() {
this.abandon = Symbol('abandon');
this.close = Symbol('close');
this.continue = Symbol('continue');
this.reserved = internals.reserved;
this._toolkit = internals.toolkit();
}

@@ -28,3 +47,3 @@

const h = new internals.Toolkit(request, this, options);
const h = new this._toolkit(request, options);
const bind = options.bind || null;

@@ -47,3 +66,3 @@

var response = await internals.Manager.timed(operation, options);
var response = await exports.timed(operation, options);
}

@@ -69,3 +88,3 @@ catch (err) {

if (options.continue &&
response === this.continue) {
response === exports.symbols.continue) {

@@ -97,2 +116,7 @@ if (options.continue === 'undefined') {

decorate(name, method) {
this._toolkit.prototype[name] = method;
}
failAction(request, failAction, err, options) {

@@ -116,21 +140,22 @@

}
};
static timed(method, options) {
if (!options.timeout) {
return method;
}
exports.timed = function (method, options) {
const timer = new Promise((resolve, reject) => {
if (!options.timeout) {
return method;
}
const handler = () => {
const timer = new Promise((resolve, reject) => {
reject(Boom.internal(`${options.name} timed out`));
};
const handler = () => {
setTimeout(handler, options.timeout);
});
reject(Boom.internal(`${options.name} timed out`));
};
return Promise.race([timer, method]);
}
setTimeout(handler, options.timeout);
});
return Promise.race([timer, method]);
};

@@ -156,75 +181,74 @@

internals.Toolkit = class {
internals.toolkit = function () {
constructor(request, manager, options) {
const Toolkit = class {
this.abandon = manager.abandon;
this.close = manager.close;
this.continue = manager.continue;
this.context = options.bind;
this.realm = options.realm;
this.request = request;
constructor(request, options) {
if (options.auth) {
this.authenticated = internals.authenticated;
this.unauthenticated = internals.unauthenticated;
}
this.context = options.bind;
this.realm = options.realm;
this.request = request;
for (const method of request._core.decorations.toolkit) {
this[method] = request._core._decorations.toolkit[method];
this._auth = options.auth;
}
}
response(result) {
response(result) {
Hoek.assert(!result || typeof result !== 'object' || typeof result.then !== 'function', 'Cannot wrap a promise');
Hoek.assert(result instanceof Error === false, 'Cannot wrap an error');
Hoek.assert(typeof result !== 'symbol', 'Cannot wrap a symbol');
Hoek.assert(!result || typeof result !== 'object' || typeof result.then !== 'function', 'Cannot wrap a promise');
Hoek.assert(result instanceof Error === false, 'Cannot wrap an error');
Hoek.assert(typeof result !== 'symbol', 'Cannot wrap a symbol');
return Response.wrap(result, this.request);
}
return Response.wrap(result, this.request);
}
redirect(location) {
redirect(location) {
return this.response('').redirect(location);
}
return this.response('').redirect(location);
}
entity(options) {
entity(options) {
Hoek.assert(options, 'Entity method missing required options');
Hoek.assert(options.etag || options.modified, 'Entity methods missing required options key');
Hoek.assert(options, 'Entity method missing required options');
Hoek.assert(options.etag || options.modified, 'Entity methods missing required options key');
this.request._entity = options;
this.request._entity = options;
const entity = Response.entity(options.etag, options);
if (Response.unmodified(this.request, entity)) {
return this.response().code(304).takeover();
const entity = Response.entity(options.etag, options);
if (Response.unmodified(this.request, entity)) {
return this.response().code(304).takeover();
}
}
}
state(name, value, options) {
state(name, value, options) {
this.request._setState(name, value, options);
}
this.request._setState(name, value, options);
}
unstate(name, options) {
unstate(name, options) {
this.request._clearState(name, options);
}
};
this.request._clearState(name, options);
}
authenticated(data) {
internals.authenticated = function (data) {
Hoek.assert(this._auth, 'Method not supported outside of authentication');
Hoek.assert(data && data.credentials, 'Authentication data missing credentials information');
Hoek.assert(data && data.credentials, 'Authentication data missing credentials information');
return new internals.Auth(null, data);
}
return new internals.Auth(null, data);
};
unauthenticated(error, data) {
Hoek.assert(this._auth, 'Method not supported outside of authentication');
Hoek.assert(!data || data.credentials, 'Authentication data missing credentials information');
internals.unauthenticated = function (error, data) {
return new internals.Auth(error, data);
}
};
Hoek.assert(!data || data.credentials, 'Authentication data missing credentials information');
Toolkit.prototype.abandon = exports.symbols.abandon;
Toolkit.prototype.close = exports.symbols.close;
Toolkit.prototype.continue = exports.symbols.continue;
return new internals.Auth(error, data);
return Toolkit;
};

@@ -231,0 +255,0 @@

@@ -149,3 +149,3 @@ 'use strict';

response.statusCode === 200 &&
request.route.settings.response.emptyStatusCode === 204) {
request.route.settings.response.emptyStatusCode !== 200) {

@@ -206,3 +206,3 @@ response.code(204);

return new Ammo.Stream(range);
return new Ammo.Clip(range);
};

@@ -245,3 +245,3 @@

const team = new Teamwork();
const team = new Teamwork.Team();

@@ -299,3 +299,3 @@ // Write payload

err = err || new Boom(`Request ${event}`, { statusCode: request.route.settings.response.disconnectStatusCode });
err = err || new Boom.Boom(`Request ${event}`, { statusCode: request.route.settings.response.disconnectStatusCode });
const error = internals.error(request, Boom.boomify(err));

@@ -302,0 +302,0 @@ request._setResponse(error);

@@ -11,4 +11,13 @@ 'use strict';

exports.compile = function (rule) {
exports.validator = function (validator) {
Hoek.assert(validator, 'Missing validator');
Hoek.assert(typeof validator.compile === 'function', 'Invalid validator compile method');
return validator;
};
exports.compile = function (rule, validator) {
// false - nothing allowed

@@ -40,3 +49,4 @@

return Joi.compile(rule);
Hoek.assert(validator, 'Cannot set uncompiled validation rules without configuring a validator');
return validator.compile(rule);
};

@@ -147,3 +157,3 @@

if (request.route.settings.response.sample) {
const currentSample = Math.ceil((Math.random() * 100));
const currentSample = Math.ceil(Math.random() * 100);
if (currentSample > request.route.settings.response.sample) {

@@ -215,3 +225,2 @@ return;

catch (err) {
return request._core.toolkit.failAction(request, request.route.settings.response.failAction, err, { tags: ['validation', 'response', 'error'] });

@@ -218,0 +227,0 @@ }

@@ -5,5 +5,8 @@ {

"homepage": "https://hapijs.com",
"version": "18.4.0",
"version": "19.0.0",
"repository": "git://github.com/hapijs/hapi",
"main": "lib/index.js",
"files": [
"lib"
],
"keywords": [

@@ -16,27 +19,27 @@ "framework",

"dependencies": {
"@hapi/accept": "3.x.x",
"@hapi/ammo": "3.x.x",
"@hapi/boom": "7.x.x",
"@hapi/bounce": "1.x.x",
"@hapi/call": "5.x.x",
"@hapi/catbox": "10.x.x",
"@hapi/catbox-memory": "4.x.x",
"@hapi/heavy": "6.x.x",
"@hapi/hoek": "8.x.x",
"@hapi/joi": "15.x.x",
"@hapi/mimos": "4.x.x",
"@hapi/podium": "3.x.x",
"@hapi/shot": "4.x.x",
"@hapi/somever": "2.x.x",
"@hapi/statehood": "6.x.x",
"@hapi/subtext": "6.x.x",
"@hapi/teamwork": "3.x.x",
"@hapi/topo": "3.x.x"
"@hapi/accept": "4.x.x",
"@hapi/ammo": "4.x.x",
"@hapi/boom": "9.x.x",
"@hapi/bounce": "2.x.x",
"@hapi/call": "7.x.x",
"@hapi/catbox": "11.x.x",
"@hapi/catbox-memory": "5.x.x",
"@hapi/heavy": "7.x.x",
"@hapi/hoek": "9.x.x",
"@hapi/joi": "17.x.x",
"@hapi/mimos": "5.x.x",
"@hapi/podium": "4.x.x",
"@hapi/shot": "5.x.x",
"@hapi/somever": "3.x.x",
"@hapi/statehood": "7.x.x",
"@hapi/subtext": "7.x.x",
"@hapi/teamwork": "4.x.x",
"@hapi/topo": "5.x.x"
},
"devDependencies": {
"@hapi/code": "6.x.x",
"@hapi/inert": "5.x.x",
"@hapi/joi-next-test": "npm:@hapi/joi@16.x.x",
"@hapi/lab": "20.x.x",
"@hapi/wreck": "15.x.x",
"@hapi/code": "8.x.x",
"@hapi/inert": "6.x.x",
"@hapi/joi-legacy-test": "npm:@hapi/joi@15.x.x",
"@hapi/lab": "22.x.x",
"@hapi/wreck": "17.x.x",
"@hapi/vision": "5.x.x",

@@ -43,0 +46,0 @@ "handlebars": "4.x.x"

<img src="https://raw.githubusercontent.com/hapijs/assets/master/images/hapi.png" width="400px" />
# @hapi/hapi
# The Simple, Secure Framework Developers Trust

@@ -8,1 +10,9 @@

### Visit the [hapi.dev](https://hapi.dev) Developer Portal for tutorials, documentation, and support
## Useful resources
- [Documentation and API](https://hapi.dev/)
- [Version status](https://hapi.dev/resources/status/#hapi) (builds, dependencies, node versions, licenses, eol)
- [Changelog](https://hapi.dev/resources/changelog/)
- [Project policies](https://hapi.dev/policies/)
- [Free and commercial support options](https://hapi.dev/support/)
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc