Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

celebrate

Package Overview
Dependencies
Maintainers
1
Versions
55
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

celebrate - npm Package Compare versions

Comparing version 10.1.0 to 11.0.0-rc1

lib/constants.js

20

lib/index.d.ts

@@ -9,3 +9,12 @@ import { ErrorRequestHandler, RequestHandler } from 'express';

declare namespace Celebrate {
declare enum Segments {
PARAMS="params",
HEADERS="headers",
QUERY="query",
COOKIES="cookies",
SIGNEDCOOKIES="signedCookies",
BODY="body"
}
/**

@@ -62,11 +71,6 @@ * Creates a Celebrate middleware function.

/**
* Format a joi error into a standard object
* The standard error used by Celebrate
*/
function format(err: ValidationResult<object>,
source: "params" | "headers" | "query" | "cookies" | "signedCookies" | "body",
opts?: { celebrated: boolean }): {
meta: {
source: "params" | "headers" | "query" | "cookies" | "signedCookies" | "body"
},
joi: ValidationError,
declare class CelebrateError {
constructor(error: ValidationError, segment: Segments, opts?: { celebrated: boolean }) {}
}

@@ -73,0 +77,0 @@ }

208

lib/index.js
const Assert = require('assert');
const Joi = require('@hapi/joi');
const EscapeHtml = require('escape-html');
const get = require('lodash.get');
const {
middlewareSchema, celebrateSchema, sourceSchema, optSchema,
middlewareSchema,
celebrateSchema,
sourceSchema,
optSchema,
} = require('./schema');
const { segments } = require('./constants');
const CELEBRATED = Symbol('celebrated');
const DEFAULT_JOI_OPTIONS = {
escapeHtml: true,
const internals = {
CELEBRATED: Symbol('celebrated'),
DEFAULT_FORMAT_OPTIONS: {
celebrated: true,
},
};
const DEFAULT_FORMAT_OPTIONS = {
celebrated: true,
};
const _format = (error, source, opts) => ({
[CELEBRATED]: opts.celebrated,
joi: error,
meta: { source },
});
const format = (err, source, opts = { celebrated: false }) => {
Assert.ok(get(err, 'error.isJoi', false));
let result = Joi.validate(source, sourceSchema);
Assert.ifError(result.error);
result = Joi.validate(opts, optSchema);
Assert.ifError(result.error);
const {
error,
} = err;
return _format(error, source, opts);
internals.CelebrateError = class extends Error {
constructor(joiError, segment, opts) {
super(joiError.message);
this.joi = joiError;
this.meta = { source: segment };
this[internals.CELEBRATED] = opts.celebrated;
}
};
const validateSource = (source) => ({
celebrateOpts,
joiOpts,
internals.validateSource = (segment, spec) => ({
config,
req,
rules,
}) => {
const spec = rules.get(source);
if (!spec) { return null; }
const result = Joi.validate(req[source], spec, celebrateOpts.reqContext ? {
...joiOpts,
context: req,
} : joiOpts);
const {
value,
error,
} = result;
if (value !== undefined) {
Object.defineProperty(req, source, {
}) => new Promise((resolve, reject) => {
spec.validateAsync(req[segment], config).then(({ value }) => {
resolve({
value,
segment,
});
}
if (error) {
return _format(error, source, DEFAULT_FORMAT_OPTIONS);
}
return null;
};
}).catch((e) => reject(new internals.CelebrateError(
e,
segment,
internals.DEFAULT_FORMAT_OPTIONS,
)));
});
const validateHeaders = validateSource('headers');
const validateParams = validateSource('params');
const validateQuery = validateSource('query');
const validateCookies = validateSource('cookies');
const validateSignedCookies = validateSource('signedCookies');
const validateBody = validateSource('body');
const maybeValidateBody = (config, callback) => {
const method = config.req.method.toLowerCase();
internals.maybeValidateBody = (segment, spec) => (opts) => {
const method = opts.req.method.toLowerCase();
if (method === 'get' || method === 'head') {
return null;
return Promise.resolve({
value: null,
segment,
});
}
return validateBody(config, callback);
return internals.validateSource(segment, spec)(opts);
};
const REQ_VALIDATIONS = [
validateHeaders,
validateParams,
validateQuery,
validateCookies,
validateSignedCookies,
maybeValidateBody,
];
// Map of segments to validation functions.
// The key order is the order validations will run in.
internals.REQ_VALIDATIONS = new Map([
[segments.HEADERS, internals.validateSource],
[segments.PARAMS, internals.validateSource],
[segments.QUERY, internals.validateSource],
[segments.COOKIES, internals.validateSource],
[segments.SIGNEDCOOKIES, internals.validateSource],
[segments.BODY, internals.maybeValidateBody],
]);
const isCelebrate = (err) => {
if (err != null && typeof err === 'object') {
return err[CELEBRATED] || false;
// ⚠️ steps is mutated in this function
internals.check = (steps, opts) => {
const validateFn = steps.shift();
if (validateFn) {
return validateFn(opts).then(({ value, segment }) => {
if (value != null) {
Object.defineProperty(opts.req, segment, {
value,
});
}
return internals.check(steps, opts);
});
}
return false;
// If we get here, all the promises have resolved
// and so we have a final resolve to end the recursion
return Promise.resolve(null);
};
const celebrate = (schema, joiOptions = {}, celebrateOptions = {}) => {
let result = Joi.validate(schema, middlewareSchema);
exports.celebrate = (schema, joiOpts = {}, celebrateOptions = {}) => {
let result = middlewareSchema.validate(schema);
Assert.ifError(result.error);
result = Joi.validate(celebrateOptions, celebrateSchema);
result = celebrateSchema.validate(celebrateOptions);
Assert.ifError(result.error);
const rules = new Map();
const joiOpts = { ...DEFAULT_JOI_OPTIONS, ...joiOptions };
Object.entries(schema).forEach(([key, value]) => rules.set(key, Joi.compile(value)));
// We want a fresh copy of steps since `internals.check` mutates the array
const steps = [];
internals.REQ_VALIDATIONS.forEach((validateFn, segment) => {
const spec = schema[segment];
if (spec) {
steps.push(validateFn(segment, Joi.compile(spec)));
}
});
const middleware = (req, res, next) => {
let stepNumber = 0;
let err = null;
const config = {
const finalConfig = celebrateOptions.reqContext ? {
...joiOpts,
context: req,
warnings: true,
} : {
...joiOpts,
warnings: true,
};
return internals.check(steps, {
config: finalConfig,
req,
joiOpts,
rules,
celebrateOpts: celebrateOptions,
};
do {
const step = REQ_VALIDATIONS[stepNumber];
err = step(config);
stepNumber += 1;
} while (stepNumber <= REQ_VALIDATIONS.length - 1 && err === null);
next(err);
})
.then(next)
.catch(next);
};

@@ -131,5 +124,12 @@

const errors = () => (err, req, res, next) => {
exports.isCelebrate = (err) => {
if (err != null && typeof err === 'object') {
return err[internals.CELEBRATED] || false;
}
return false;
};
exports.errors = () => (err, req, res, next) => {
// If this isn't a Celebrate error, send it to the next error handler
if (!isCelebrate(err)) {
if (!exports.isCelebrate(err)) {
return next(err);

@@ -162,8 +162,14 @@ }

module.exports = {
celebrate,
errors,
Joi,
isCelebrate,
format,
exports.CelebrateError = (error, segment, opts = { celebrated: false }) => {
Assert.ok(error.isJoi);
let result = sourceSchema.validate(segment);
Assert.ifError(result.error);
result = optSchema.validate(opts);
Assert.ifError(result.error);
return new internals.CelebrateError(error, segment, opts);
};
exports.Joi = Joi;
exports.Segments = segments;
const Joi = require('@hapi/joi');
const { segments } = require('./constants');
exports.middlewareSchema = Joi.object({
headers: Joi.any(),
params: Joi.any(),
query: Joi.any(),
cookies: Joi.any(),
signedCookies: Joi.any(),
body: Joi.any(),
[segments.HEADERS]: Joi.any(),
[segments.PARAMS]: Joi.any(),
[segments.QUERY]: Joi.any(),
[segments.COOKIES]: Joi.any(),
[segments.SIGNEDCOOKIES]: Joi.any(),
[segments.BODY]: Joi.any(),
}).required().min(1);

@@ -16,3 +17,10 @@

exports.sourceSchema = Joi.string().valid(['headers', 'params', 'query', 'cookies', 'signedCookies', 'body']);
exports.sourceSchema = Joi.string().valid(
segments.HEADERS,
segments.PARAMS,
segments.QUERY,
segments.COOKIES,
segments.SIGNEDCOOKIES,
segments.BODY,
);

@@ -19,0 +27,0 @@ exports.optSchema = Joi.object({

{
"name": "celebrate",
"version": "10.1.0",
"version": "11.0.0-rc1",
"description": "A joi validation middleware for Express.",

@@ -32,5 +32,4 @@ "main": "lib/index.js",

"dependencies": {
"@hapi/joi": "15.x.x",
"escape-html": "1.0.3",
"lodash.get": "4.4.x"
"@hapi/joi": "16.x.x",
"escape-html": "1.0.3"
},

@@ -40,3 +39,3 @@ "devDependencies": {

"@types/express": "4.x.x",
"@types/hapi__joi": "15.x.x",
"@types/hapi__joi": "16.x.x",
"artificial": "1.x.x",

@@ -43,0 +42,0 @@ "benchmark": "2.1.x",

@@ -49,4 +49,5 @@ [![celebrate](https://github.com/arb/celebrate/raw/master/images/logo.svg?sanitize=1)](https://www.npmjs.org/package/celebrate)

- [`Joi`](#joi)
- [`Segments`](#segments)
- [`CelebrateError(err, segment, [opts])`](#celebrateerrorerr-segment-opts)
- [`isCelebrate(err)`](#iscelebrateerr)
- [`format(err, source, [opts])`](#formaterr-source-opts)
- [Validation Order](#validation-order)

@@ -73,3 +74,3 @@ - [Issues](#issues)

const BodyParser = require('body-parser');
const { celebrate, Joi, errors } = require('celebrate');
const { celebrate, Joi, errors, Segments } = require('celebrate');

@@ -80,3 +81,3 @@ const app = express();

app.post('/signup', celebrate({
body: Joi.object().keys({
[Segments.BODY]: Joi.object().keys({
name: Joi.string().required(),

@@ -86,3 +87,3 @@ age: Joi.number().integer(),

}),
query: {
[Segments.QUERY]: {
token: Joi.string().token().required()

@@ -100,3 +101,3 @@ }

const express = require('express');
const { celebrate, Joi, errors } = require('celebrate');
const { celebrate, Joi, errors, Segments } = require('celebrate');
const app = express();

@@ -107,3 +108,3 @@

app.use(celebrate({
headers: Joi.object({
[Segments.HEADERS]: Joi.object({
token: Joi.string().required().regex(/abc\d{3}/)

@@ -125,4 +126,4 @@ }).unknown()

- `schema` - an `object` where `key` can be one of `'params'`, `'headers'`, `'query'`, `'cookies'`, `'signedCookies'` and `'body'` and the `value` is a [joi](https://github.com/hapijs/joi/blob/master/API.md) validation schema. Only the keys specified will be validated against the incoming request object. If you omit a key, that part of the `req` object will not be validated. A schema must contain at least one valid key.
- `[joiOptions]` - optional `object` containing joi [options](https://github.com/hapijs/joi/blob/master/API.md#validatevalue-schema-options-callback) that are passed directly into the `validate` function. Defaults to `{ escapeHtml: true }`.
- `schema` - an `object` where `key` can be one of the values from [`Segments`](#segments) and the `value` is a [joi](https://github.com/hapijs/joi/blob/master/API.md) validation schema. Only the keys specified will be validated against the incoming request object. If you omit a key, that part of the `req` object will not be validated. A schema must contain at least one valid key.
- `[joiOptions]` - optional `object` containing joi [options](https://github.com/hapijs/joi/blob/master/API.md#anyvalidatevalue-options) that are passed directly into the `validate` function. Defaults to `{ warnings: true }`.
- `[celebrateOptions]` - an optional `object` with the following keys. Defaults to `{}`.

@@ -137,6 +138,3 @@ - `reqContext` - `bool` value that instructs joi to use the incoming `req` object as the `context` value during joi validation. If set, this will trump the value of `joiOptions.context`. This is useful if you want to validate part of the request object against another part of the request object. See the tests for more details.

Errors origintating from `celebrate()` are objects with the following keys:
- `joi` - The full [joi error object](https://github.com/hapijs/joi/blob/master/API.md#errors).
- `meta` - On `object` with the following keys:
- `source` - A `string` indicating the step where the validation failed. Will be one of `'params'`, `'headers'`, `'query'`, `'cookies'`, `'signedCookies'`, or `'body'`
Errors origintating from `celebrate()` are [`CelebrateError`](#celebrateerrorerr-segment-opts)) objects.

@@ -147,16 +145,24 @@ ### `Joi`

### `isCelebrate(err)`
### `Segments`
Returns `true` if the provided `err` object originated from the `celebrate` middleware, and `false` otherwise. Useful if you want to write your own error handler for celebrate errors.
An enum containing all the segments of `req` objects that celebrate *can* valiate against.
- `err` - an error object
```js
{
BODY: 'body',
COOKIES: 'cookies',
HEADERS: 'headers',
PARAMS: 'params',
QUERY: 'query',
SIGNEDCOOKIES: 'signedCookies',
}
```
### `format(err, source, [opts])`
### `CelebrateError(err, segment, [opts])`
A factory function for creating celebrate errors.
Formats the incomming values into the shape of celebrate [errors](#errors())
- `err` - a Joi validation error object
- `source` - A `string` indicating the step where the validation failed. Will be one of `'params'`, `'headers'`, `'query'`, `'cookies'`, `'signedCookies'`, or `'body'`
- `segment` - A [`Segment`](#segments) indicating the step where the validation failed.
- `[opts]` - optional `object` with the following keys
- `celebrated` - `bool` that, when `true`, adds `Symbol('celebrated'): true` to the result object. This indicates this error as originating from `celebrate`. You'd likely want to set this to `true` if you want the celebrate error handler to handle errors originating from the `format` function that you call in user-land code. Defaults to `false`.
- `celebrated` - `bool` that, when `true`, adds `Symbol('celebrated'): true` to the result object. This indicates this error as originating from `celebrate`. You'd likely want to set this to `true` if you want the celebrate error handler to handle errors originating from the `format` function that you call in user-land code. Defaults to `false`.
<details>

@@ -167,6 +173,12 @@ <summary>Sample usage</summary>

const result = Joi.validate(req.params.id, Joi.string().valid('foo'), { abortEarly: false });
const err = format(result, 'params');
const err = CelebrateError(result.error, Segments.PARAMS);
```
</details>
### `isCelebrate(err)`
Returns `true` if the provided `err` object originated from the `celebrate` middleware, and `false` otherwise. Useful if you want to write your own error handler for celebrate errors.
- `err` - an error object
## Validation Order

@@ -173,0 +185,0 @@

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