cache-headers
Advanced tools
Comparing version 1.0.0 to 1.1.0
@@ -7,10 +7,7 @@ 'use strict'; | ||
var url = _interopDefault(require('fast-url-parser')); | ||
var url = _interopDefault(require('url')); | ||
var globject = _interopDefault(require('globject')); | ||
var slasher = _interopDefault(require('glob-slasher')); | ||
var regular = _interopDefault(require('regular')); | ||
var isEmpty = _interopDefault(require('lodash.isempty')); | ||
var moment_src_lib_moment_moment = require('moment/src/lib/moment/moment'); | ||
var moment_src_lib_locale_locale = require('moment/src/lib/locale/locale'); | ||
var moment_src_lib_format_format = require('moment/src/lib/format/format'); | ||
var regular = _interopDefault(require('regular')); | ||
@@ -22,2 +19,5 @@ /** | ||
var KEY_LAST_MODIFIED = 'lastModified'; | ||
var KEY_STALE_IF_ERROR = 'staleError'; | ||
var KEY_STALE_WHILE_REVALIDATE = 'staleRevalidate'; | ||
var KEY_SURROGATE_CONTROL = 'maxAge'; | ||
@@ -35,5 +35,2 @@ | ||
// Mon, 01, Jan 2016, 00:00:00 UTC | ||
var defaultDateFormat = 'ddd, DD MMM YYYY HH:mm:ss z'; | ||
/** | ||
@@ -43,3 +40,3 @@ * @param {*} val The value to check if it is an actual object. Arrays are not considered objects in this case | ||
*/ | ||
function isNonEmptyObject(val) { | ||
function isValidObject(val) { | ||
return !Array.isArray(val) && (typeof val === 'undefined' ? 'undefined' : _typeof(val)) === 'object' && !isEmpty(val); | ||
@@ -58,16 +55,5 @@ } | ||
/** | ||
* @param {object} [time] Date object | ||
* @return {object} moment object in UTC format | ||
*/ | ||
function getUtcTime() { | ||
var time = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Date(); | ||
return moment_src_lib_moment_moment.createUTC(time); | ||
} | ||
/** | ||
* Format a UTC Date value | ||
* @param {object} options | ||
* @param {number} [options.date=now()] UTC time format. A JavaScript date must be passed in, not a moment date object | ||
* @param {string} [options.dateFormat=defaultDateFormat] Primarily used for testing | ||
* @param {number} [options.date=new Date()] UTC time format. A JavaScript date object | ||
* @return {string} header date string in GMT format | ||
@@ -78,14 +64,11 @@ */ | ||
var _options$date = options.date, | ||
date = _options$date === undefined ? moment_src_lib_moment_moment.now() : _options$date, | ||
_options$dateFormat = options.dateFormat, | ||
dateFormat = _options$dateFormat === undefined ? defaultDateFormat : _options$dateFormat; | ||
// keeping this here if we want to | ||
// support setting locales in the future | ||
date = _options$date === undefined ? new Date() : _options$date; | ||
var locale = { key: undefined, config: undefined }; | ||
// need to set locale before formatting | ||
moment_src_lib_locale_locale.updateLocale(locale.key, locale.config); | ||
var formatted = moment_src_lib_format_format.formatMoment(getUtcTime(date), dateFormat); | ||
// do browsers require using GMT instead of UTC? | ||
return formatted.replace('UTC', 'GMT'); | ||
if (date && date.toString() === 'Invalid Date' || !date) { | ||
// covers if the following are passed in: | ||
// new Date('invalid_date_string') | ||
// date = null | ||
date = new Date(); | ||
} | ||
return date.toUTCString(); | ||
} | ||
@@ -157,5 +140,3 @@ | ||
*/ | ||
function generateBrowserCacheHeader() { | ||
var setPrivate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; | ||
function generateBrowserCacheHeader(setPrivate) { | ||
if (setPrivate) { | ||
@@ -202,4 +183,3 @@ return PRIVATE_VALUE + ', ' + NO_CACHE_NO_STORE; | ||
*/ | ||
function generateCacheControl() { | ||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
function generateCacheControl(options) { | ||
var _options$staleRevalid = options.staleRevalidate, | ||
@@ -234,4 +214,3 @@ staleRevalidate = _options$staleRevalid === undefined ? false : _options$staleRevalid, | ||
*/ | ||
function generateSurrogateControl() { | ||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
function generateSurrogateControl(options) { | ||
var _options$setPrivate2 = options.setPrivate, | ||
@@ -266,4 +245,3 @@ setPrivate = _options$setPrivate2 === undefined ? false : _options$setPrivate2; | ||
function generateLastModifiedHeader() { | ||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
function generateLastModifiedHeader(options) { | ||
var _options$lastModified = options.lastModified, | ||
@@ -313,3 +291,3 @@ lastModified = _options$lastModified === undefined ? false : _options$lastModified; | ||
res.set(headerData.name, headerData.value); | ||
} else if (isNonEmptyObject(headerData)) { | ||
} else { | ||
res.set(headerData); | ||
@@ -340,37 +318,35 @@ } | ||
* {{@link module:cacheControl#generate}} for acceptable values | ||
* @memberof index | ||
* @param {object} [config] | ||
* @param {object} [config.cacheSettings=undefined] Cache settings to override the default `paths` settings | ||
* @param {object} [config.paths] Cache settings with glob path patterns | ||
* @param {object} pathsConfig Cache settings with glob path patterns | ||
* @return {Function} | ||
*/ | ||
function middleware(config) { | ||
var _ref = config || {}, | ||
cacheSettings = _ref.cacheSettings, | ||
paths = _ref.paths; | ||
function setupInitialCacheHeaders(pathsConfig) { | ||
pathsConfig = pathsConfig || {}; | ||
return function (req, res, next) { | ||
// current path (prefixed with a slash) | ||
var pathname = slasher(url.parse(req.originalUrl).pathname); | ||
var pathname = url.parse(req.originalUrl).pathname; | ||
var cacheValues = globject(slasher(paths || {}, { value: false })); | ||
var values = cacheValues(slasher(pathname)); | ||
/** | ||
* Takes a pathname and returns the first config whose glob key matches | ||
* | ||
* @param pathname - pathname prefixed with slash | ||
* @function | ||
*/ | ||
var getCacheConfig = globject(slasher(pathsConfig, { value: false })); | ||
if (isNonEmptyObject(cacheSettings)) { | ||
// override default cacheValue settings | ||
values = generateAllCacheHeaders(cacheSettings); | ||
} else if (isNonEmptyObject(values)) { | ||
values = generateAllCacheHeaders(values); | ||
} else if (values === false) { | ||
var _generateAllCacheHead; | ||
// options by default are set to config | ||
var options = getCacheConfig(pathname); | ||
values = generateAllCacheHeaders((_generateAllCacheHead = {}, _defineProperty(_generateAllCacheHead, KEY_SURROGATE_CONTROL, 0), _defineProperty(_generateAllCacheHead, 'setPrivate', true), _generateAllCacheHead)); | ||
} else if (isNumberLike(values)) { | ||
if (options === false) { | ||
var _options; | ||
// current path doesn't match any glob key in pathsConfig | ||
options = (_options = {}, _defineProperty(_options, KEY_SURROGATE_CONTROL, 0), _defineProperty(_options, 'setPrivate', true), _options); | ||
} else if (isNumberLike(options)) { | ||
// catch `0` before !cacheValue check | ||
// make sure to convert value to actual number | ||
values = generateAllCacheHeaders(_defineProperty({}, KEY_SURROGATE_CONTROL, Number(values))); | ||
} else if (!values || isEmpty(values)) { | ||
values = generateAllCacheHeaders(); | ||
options = _defineProperty({}, KEY_SURROGATE_CONTROL, Number(options)); | ||
} | ||
setHeader(res, values); | ||
setHeader(res, generateAllCacheHeaders(options)); | ||
@@ -381,4 +357,33 @@ next(); | ||
/** | ||
* | ||
* {{@link module:cacheControl#generate}} for acceptable values | ||
* @param {object} overrideConfig cacheSettings to override default | ||
* @returns {function(*, *=, *)} | ||
*/ | ||
function overrideCacheHeaders(overrideConfig) { | ||
return function (req, res, next) { | ||
var options = overrideConfig; | ||
if (overrideConfig === false) { | ||
var _options3; | ||
options = (_options3 = {}, _defineProperty(_options3, KEY_SURROGATE_CONTROL, 0), _defineProperty(_options3, 'setPrivate', true), _options3); | ||
} | ||
if (isValidObject(options)) { | ||
setHeader(res, generateAllCacheHeaders(options)); | ||
} | ||
next(); | ||
}; | ||
} | ||
exports.setAdditionalHeaders = setAdditionalHeaders; | ||
exports.middleware = middleware; | ||
exports.setupInitialCacheHeaders = setupInitialCacheHeaders; | ||
exports.overrideCacheHeaders = overrideCacheHeaders; | ||
exports.KEY_LAST_MODIFIED = KEY_LAST_MODIFIED; | ||
exports.KEY_STALE_IF_ERROR = KEY_STALE_IF_ERROR; | ||
exports.KEY_STALE_WHILE_REVALIDATE = KEY_STALE_WHILE_REVALIDATE; | ||
exports.KEY_SURROGATE_CONTROL = KEY_SURROGATE_CONTROL; | ||
exports.ONE_MINUTE = ONE_MINUTE; | ||
@@ -385,0 +390,0 @@ exports.TEN_MINUTES = TEN_MINUTES; |
{ | ||
"name": "cache-headers", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "Generate browser and cdn cache header values", | ||
"main": "dist/index.js", | ||
"nyc": { | ||
"check-coverage": true, | ||
"extension": [ | ||
".js" | ||
], | ||
"require": [ | ||
"babel-register" | ||
], | ||
"branches": 83, | ||
"functions": 100, | ||
"lines": 100, | ||
"statements": 100, | ||
"sourceMap": false, | ||
"instrument": false | ||
}, | ||
"scripts": { | ||
"test": "NODE_ENV=test mocha", | ||
"test": "NODE_ENV=test jest --forceExit --no-cache", | ||
"compile": "rm -rf ./dist && NODE_ENV=build rollup -c", | ||
"coverage": "NODE_ENV=test nyc --reporter=lcov --reporter=text yarn test", | ||
"docs": "rm -rf ./docs && esdoc -c ./esdoc.json", | ||
"lint": "dibslint --root=./src -e --git --warnings", | ||
"precommit": "dibslint --git --warnings -e", | ||
"prepublish": "yarn run coverage && yarn run compile", | ||
"lint": "dibslint --root=./src --es6 --git --warnings", | ||
"precommit": "dibslint --es6 --git --warnings", | ||
"prepublish": "yarn run compile", | ||
"updatedocs": "rm -rf ./docs && yarn run docs && git add ./docs && git commit -n -m 'updated docs v${npm show . version}'", | ||
@@ -34,2 +18,22 @@ "generatedist": "./generate.sh compile dist", | ||
}, | ||
"jest": { | ||
"collectCoverage": true, | ||
"coverageDirectory": "<rootDir>/__coverage__", | ||
"coverageThreshold": { | ||
"global": { | ||
"branches": 100, | ||
"functions": 100, | ||
"lines": 100, | ||
"statements": 100 | ||
} | ||
}, | ||
"setupFiles": [ | ||
"<rootDir>/__tests__/testHelper.js" | ||
], | ||
"testPathIgnorePatterns": [ | ||
"/node_modules/", | ||
"<rootDir>/__tests__/registerBabel.js", | ||
"<rootDir>/__tests__/testHelper.js" | ||
] | ||
}, | ||
"keywords": [ | ||
@@ -54,3 +58,2 @@ "cache control", | ||
"devDependencies": { | ||
"async": "^1.5.0", | ||
"babel-cli": "^6.1.2", | ||
@@ -60,7 +63,7 @@ "babel-core": "^6.1.2", | ||
"babel-preset-es2015": "^6.1.2", | ||
"core-js": "^1.2.6", | ||
"core-js": "^2.4.1", | ||
"del": "^2.2.0", | ||
"dibslint": "^1.4.2", | ||
"dibslint": "^2.2.7", | ||
"eslint": "^2.13.1", | ||
"express": "^4.13.3", | ||
"fast-url-parser": "^1.1.3", | ||
"glob-slasher": "^1.0.1", | ||
@@ -71,7 +74,5 @@ "globject": "^1.0.1", | ||
"husky": "^0.11.9", | ||
"jest": "^20.0.1", | ||
"lodash.isempty": "^3.0.4", | ||
"mocha": "^2.3.3", | ||
"moment": "^2.15.2", | ||
"mr-doc": "^3.0.7", | ||
"nyc": "^8.4.0", | ||
"regular": "^0.1.6", | ||
@@ -81,13 +82,13 @@ "rollup": "^0.36.3", | ||
"rollup-plugin-commonjs": "^5.0.5", | ||
"supertest": "^1.1.0" | ||
"supertest": "^3.0.0" | ||
}, | ||
"peerDependencies": { | ||
"core-js": "^1.2.6", | ||
"fast-url-parser": "^1.1.3", | ||
"core-js": "^2.4.1" | ||
}, | ||
"dependencies": { | ||
"glob-slasher": "^1.0.1", | ||
"globject": "^1.0.1", | ||
"lodash.isempty": "^3.0.4", | ||
"moment": "^2.15.2", | ||
"regular": "^0.1.6" | ||
} | ||
} |
166
README.md
@@ -11,2 +11,4 @@ # Cache Headers | ||
```sh | ||
$ yarn add cache-headers | ||
// with npm | ||
$ npm install --save cache-headers | ||
@@ -17,2 +19,5 @@ ``` | ||
```sh | ||
$ yarn | ||
$ yarn test | ||
// with npm | ||
$ npm install | ||
@@ -24,3 +29,3 @@ $ npm test | ||
### App-level middleware | ||
### App-level setup middleware | ||
@@ -31,18 +36,11 @@ ```es6 | ||
const cache = require('cache-headers'); | ||
const cacheOptions = { | ||
const pathsConfig = { | ||
paths: { | ||
'/**/generic': { | ||
maxAge: 'TEN_MINUTES', | ||
sMaxAge: 'ONE_DAY', | ||
staleRevalidate: 'ONE_HOUR', | ||
staleError: 'ONE_HOUR' | ||
}, | ||
'/short-cached/route': { | ||
maxAge: 60, | ||
sMaxAge: 600 | ||
}, | ||
'/default/values': {}, | ||
'/user/route': false, | ||
'/**': { | ||
maxAge: 600 | ||
} | ||
'/**': 60 | ||
} | ||
@@ -53,25 +51,23 @@ }; | ||
app.use(cache.middleware(cacheOptions)); | ||
app.use(cache.setupInitialCacheHeaders(pathsConfig)); | ||
// rest of app setup | ||
``` | ||
With the example above, the `Cache-Control` header is set as follows when a user hits these different site routes: | ||
- `/**/generic` (any route ending in `generic`): `Cache-Control: max-age=600, s-maxage=84600, stale-while-revalidate=3600, stale-if-error=3600` | ||
- `/cached/route`: `Cache-Control: max-age=60, s-maxage=600` | ||
- `/user/route`: `Cache-Control: no-cache, max-age=0` | ||
- `/**` (any other route not listed): `Cache-Control: max-age=600` | ||
- `/**/generic` (any route ending in `generic`) | ||
- `Cache-Control: no-cache, no-store, must-revalidate, stale-while-revalidate=3600, stale-if-error=3600` | ||
- `Surrogate-Control: maxAge=600` | ||
- `/default/values` | ||
- `Cache-Control: no-cache, no-store, must-revalidate` | ||
- `Surrogate-Control: maxAge=600` | ||
- `/user/route` | ||
- `Cache-Control: private, no-cache, no-store, must-revalidate` | ||
- `Surrogate-Control: maxAge=0` | ||
- `/**` (any other route not listed) | ||
- `Cache-Control: no-cache, no-store, must-revalidate` | ||
- `Surrogate-Control: maxAge=60` | ||
Alternatively for `no-cache`, the following could be used: | ||
```js | ||
'/user/route': { | ||
setNoCache: true | ||
} | ||
``` | ||
### Router-level middleware | ||
Taking the app-level setup above, you can additionally override the default `paths` initially set in the `cacheOptions`. | ||
Taking the app-level setup above, you can additionally override the default `pathsConfig` initially set. | ||
```es6 | ||
@@ -81,12 +77,10 @@ const express = require('express'); | ||
const cache = require('cache-headers'); | ||
const cacheOptions = { | ||
cacheSettings: { | ||
"maxAge": 2000 | ||
} | ||
const overrideConfig = { | ||
"maxAge": 2000 | ||
}; | ||
// app.use(cache.middleware(cacheOptions)) is loaded prior to this route, therefore running by default | ||
// app.use(cache.setupInitialCacheHeaders(pathsConfig)) is loaded prior to this route, therefore running by default | ||
// and any subsequent call to set the header is then overwritten | ||
router.get('/endswith/generic', cache.middleware(cacheOptions), (req, res, next) => { | ||
router.get('/endswith/generic', cache.overrideCacheHeaders(overrideConfig), (req, res, next) => { | ||
// do route-y stuff | ||
@@ -98,21 +92,26 @@ next(); | ||
Rather than set the original headers defined in the `paths` config in the app-level setup (for the `/**/generic` path), this will output the following: `Cache-Control: max-age=2000` | ||
Rather than set the original headers defined in the `pathsConfig` config in the app-level setup (for the `/**/generic` path), this will output the following: | ||
``` | ||
Cache-Control: no-cache, no-store, must-revalidate | ||
Surrogate-Control: maxAge=2000 | ||
``` | ||
## API | ||
### cache.middleware (all properties optional) | ||
### `cache.setupInitialCacheHeaders(pathsConfig)` | ||
```js | ||
{ | ||
cacheSettings: { | ||
maxAge: number|string, | ||
sMaxAge: number|string, | ||
staleRevalidate: number|string, | ||
staleError: number|string | ||
}, | ||
paths: { | ||
'/glob/**/path': object|boolean=false | ||
} | ||
'/glob/**/path': object|string|boolean=false | ||
} | ||
``` | ||
The following are acceptable keys to use if an object is passed in | ||
| key | type | description | default | | ||
| --- | ---- | ----------- | ------- | | ||
| `lastModified` | string | set `Last-Modified Header` | current date | | ||
| `maxAge` | string, number | number or string representing a number for `Surrogate-Control: max-age` (forced to `0` if `setPrivate=true`) | `TEN_MINUTES` (600 seconds) | | ||
| `setPrivate` | boolean | should add `Cache-Control: private` (if set to `true` forces `Surrogate-Control: maxAge=0`) | false | | ||
| `staleError` | string, number | number or string representing a number for `Cache-Control: stale-if-error` | | | ||
| `staleRevalidate` | string, number | number or string representing a number for `Cache-Control: stale-while-revalidate` | | | ||
The following are acceptable values to use if a string is passed in for cache values: | ||
@@ -128,6 +127,79 @@ | ||
If no options are passed in, the default value set is `Cache-Control: max-age=600` | ||
The following are acceptable values to use if a boolean is passed in | ||
- `false` - this is equivalent to passing `{ setPrivate: true, maxAge: 0 }` | ||
If no options are passed in, the default value set is | ||
``` | ||
Cache-Control: no-cache, no-store, must-revalidate | ||
Surrogate-Control: max-age=600 | ||
``` | ||
### `cache.overrideCacheHeaders(overrideConfig)` | ||
```js | ||
{ | ||
lastModified: string, | ||
maxAge: number|string, | ||
setPrivate: boolean, | ||
staleError: number|string, | ||
staleRevalidate: number|string | ||
} | ||
``` | ||
| key | type | description | default | | ||
| --- | ---- | ----------- | ------- | | ||
| `lastModified` | string | set `Last-Modified Header` | current date | | ||
| `maxAge` | string, number | number or string representing a number for `Surrogate-Control: max-age` (forced to `0` if `setPrivate=true`) | `TEN_MINUTES` (600 seconds) | | ||
| `setPrivate` | boolean | should add `Cache-Control: private` (if set to `true` forces `Surrogate-Control: maxAge=0`) | false | | ||
| `staleError` | string, number | number or string representing a number for `Cache-Control: stale-if-error` | | | ||
| `staleRevalidate` | string, number | number or string representing a number for `Cache-Control: stale-while-revalidate` | | | ||
## Recipes | ||
#### Private Pages | ||
Options for pages that are intended for a single user and should not be cached. | ||
```js | ||
{ | ||
setPrivate: true | ||
} | ||
``` | ||
Headers Output: | ||
``` | ||
'Cache-Control': 'private, no-cache, no-store, must-revalidate' | ||
'Surrogate-Control': 'maxAge=0' | ||
'Pragma': 'no-cache' | ||
'Expires': 0 | ||
'Last-Modified': (NOW) | ||
``` | ||
#### Browser/Server Cached Pages | ||
Options for pages that are intended for all users and should be cached in both the browser and the server. | ||
```js | ||
{ | ||
maxAge: 'ONE_WEEK', // cache on server | ||
staleError: 'ONE_MONTH', // cache on browser if server returns error | ||
staleRevalidate: 'TEN_MINUTES' // cache on browser for 10 min | ||
} | ||
``` | ||
Headers Output: | ||
``` | ||
'Cache-Control': 'no-cache, no-store, must-revalidate, stale-while-revalidate=600, stale-if-error=2592000' | ||
'Surrogate-Control': 'maxAge=604800' | ||
'Pragma': 'no-cache' | ||
'Expires': 0 | ||
'Last-Modified': (NOW) | ||
``` | ||
## Additional notes on header use / specification | ||
- `Cache-Control` | ||
- `private` - response intended for single user and should not be cached | ||
- `no-cache, no-store, must-revalidate` - turns off browser caching | ||
- `stale-while-revalidate={seconds}` - use stale version for up to `{seconds}` while re-fetching latest version background | ||
- `stale-if-error={seconds}` - use stale version if re-fetch fails within `{seconds}` of response becoming stale | ||
- `Surrogate-Control` | ||
- takes priority over `Cache-Control`, but is stripped so browsers don't see it | ||
- `max-age={seconds}` - how long the response can be considered fresh | ||
*(For more information on `Surrogate-Control`/`Cache-Control` headers read [Fastly Cache Control Tutorials](https://docs.fastly.com/guides/tutorials/cache-control-tutorial) and [W3 Specification](https://www.w3.org/TR/edge-arch/).)* | ||
## Contributing | ||
All code additions and bugfixes must be accompanied by unit tests. Tests are run with mocha and | ||
All code additions and bugfixes must be accompanied by unit tests. Tests are run with jest and | ||
written with the node [`assert`][assert] module. | ||
@@ -138,2 +210,4 @@ | ||
[eslint-rules]: https://github.com/1stdibs/eslint-config-1stdibs | ||
@@ -140,0 +214,0 @@ [babel]: https://babeljs.io/ |
@@ -36,3 +36,3 @@ import {isNumberLike, formatDate} from './utils'; | ||
*/ | ||
function generateBrowserCacheHeader(setPrivate = false) { | ||
function generateBrowserCacheHeader(setPrivate) { | ||
if (setPrivate) { | ||
@@ -79,3 +79,3 @@ return `${PRIVATE_VALUE}, ${NO_CACHE_NO_STORE}`; | ||
*/ | ||
function generateCacheControl(options = {}) { | ||
function generateCacheControl(options) { | ||
const { | ||
@@ -108,3 +108,3 @@ staleRevalidate = false, | ||
*/ | ||
function generateSurrogateControl(options = {}) { | ||
function generateSurrogateControl(options) { | ||
const { | ||
@@ -140,3 +140,3 @@ // private should only be used for user-specific pages. ie account pages | ||
function generateLastModifiedHeader(options = {}) { | ||
function generateLastModifiedHeader(options) { | ||
let {lastModified = false} = options; | ||
@@ -143,0 +143,0 @@ |
@@ -11,6 +11,5 @@ /** | ||
import url from 'fast-url-parser'; | ||
import url from 'url'; | ||
import globject from 'globject'; | ||
import slasher from 'glob-slasher'; | ||
import isEmpty from 'lodash.isempty'; | ||
import { | ||
@@ -20,4 +19,5 @@ KEY_SURROGATE_CONTROL | ||
import { generateAllCacheHeaders } from './cacheControl'; | ||
import { isNumberLike, isNonEmptyObject } from './utils'; | ||
import { isNumberLike, isValidObject } from './utils'; | ||
export * from './headerTypes'; | ||
export * from './timeValues'; | ||
@@ -36,3 +36,3 @@ | ||
res.set(headerData.name, headerData.value); | ||
} else if (isNonEmptyObject(headerData)) { | ||
} else { | ||
res.set(headerData); | ||
@@ -59,37 +59,38 @@ } | ||
* {{@link module:cacheControl#generate}} for acceptable values | ||
* @memberof index | ||
* @param {object} [config] | ||
* @param {object} [config.cacheSettings=undefined] Cache settings to override the default `paths` settings | ||
* @param {object} [config.paths] Cache settings with glob path patterns | ||
* @param {object} pathsConfig Cache settings with glob path patterns | ||
* @return {Function} | ||
*/ | ||
export function middleware(config) { | ||
export function setupInitialCacheHeaders(pathsConfig) { | ||
pathsConfig = pathsConfig || {}; | ||
const { cacheSettings, paths } = config || {}; | ||
return (req, res, next) => { | ||
// current path (prefixed with a slash) | ||
const pathname = slasher(url.parse(req.originalUrl).pathname); | ||
const pathname = url.parse(req.originalUrl).pathname; | ||
const cacheValues = globject(slasher(paths || {}, {value: false})); | ||
let values = cacheValues(slasher(pathname)); | ||
/** | ||
* Takes a pathname and returns the first config whose glob key matches | ||
* | ||
* @param pathname - pathname prefixed with slash | ||
* @function | ||
*/ | ||
const getCacheConfig = globject(slasher(pathsConfig, { value: false })); | ||
if (isNonEmptyObject(cacheSettings)) { | ||
// override default cacheValue settings | ||
values = generateAllCacheHeaders(cacheSettings); | ||
} else if (isNonEmptyObject(values)) { | ||
values = generateAllCacheHeaders(values); | ||
} else if (values === false) { | ||
values = generateAllCacheHeaders({ | ||
// options by default are set to config | ||
let options = getCacheConfig(pathname); | ||
if (options === false) { | ||
// current path doesn't match any glob key in pathsConfig | ||
options = { | ||
[KEY_SURROGATE_CONTROL]: 0, | ||
setPrivate: true | ||
}); | ||
} else if (isNumberLike(values)) { | ||
}; | ||
} else if (isNumberLike(options)) { | ||
// catch `0` before !cacheValue check | ||
// make sure to convert value to actual number | ||
values = generateAllCacheHeaders({ [KEY_SURROGATE_CONTROL]: Number(values) }); | ||
} else if (!values || isEmpty(values)) { | ||
values = generateAllCacheHeaders(); | ||
options = { | ||
[KEY_SURROGATE_CONTROL]: Number(options) | ||
}; | ||
} | ||
setHeader(res, values); | ||
setHeader(res, generateAllCacheHeaders(options)); | ||
@@ -99,1 +100,26 @@ next(); | ||
} | ||
/** | ||
* | ||
* {{@link module:cacheControl#generate}} for acceptable values | ||
* @param {object} overrideConfig cacheSettings to override default | ||
* @returns {function(*, *=, *)} | ||
*/ | ||
export function overrideCacheHeaders(overrideConfig) { | ||
return (req, res, next) => { | ||
let options = overrideConfig; | ||
if (overrideConfig === false) { | ||
options = { | ||
[KEY_SURROGATE_CONTROL]: 0, | ||
setPrivate: true | ||
}; | ||
} | ||
if (isValidObject(options)) { | ||
setHeader(res, generateAllCacheHeaders(options)); | ||
} | ||
next(); | ||
}; | ||
} |
@@ -11,11 +11,5 @@ /** | ||
import {now, createUTC as utc} from 'moment/src/lib/moment/moment'; | ||
import {updateLocale} from 'moment/src/lib/locale/locale'; | ||
import {formatMoment} from 'moment/src/lib/format/format'; | ||
import regular from 'regular'; | ||
import isEmpty from 'lodash.isempty'; | ||
// Mon, 01, Jan 2016, 00:00:00 UTC | ||
const defaultDateFormat = 'ddd, DD MMM YYYY HH:mm:ss z'; | ||
/** | ||
@@ -25,3 +19,3 @@ * @param {*} val The value to check if it is an actual object. Arrays are not considered objects in this case | ||
*/ | ||
export function isNonEmptyObject(val) { | ||
export function isValidObject(val) { | ||
return !Array.isArray(val) && typeof val === 'object' && !isEmpty(val); | ||
@@ -40,29 +34,16 @@ } | ||
/** | ||
* @param {object} [time] Date object | ||
* @return {object} moment object in UTC format | ||
*/ | ||
function getUtcTime(time = new Date()) { | ||
return utc(time); | ||
} | ||
/** | ||
* Format a UTC Date value | ||
* @param {object} options | ||
* @param {number} [options.date=now()] UTC time format. A JavaScript date must be passed in, not a moment date object | ||
* @param {string} [options.dateFormat=defaultDateFormat] Primarily used for testing | ||
* @param {number} [options.date=new Date()] UTC time format. A JavaScript date object | ||
* @return {string} header date string in GMT format | ||
*/ | ||
export function formatDate(options = {}) { | ||
const { | ||
date = now(), | ||
dateFormat = defaultDateFormat | ||
} = options; | ||
// keeping this here if we want to | ||
// support setting locales in the future | ||
const locale = {key: undefined, config: undefined}; | ||
// need to set locale before formatting | ||
updateLocale(locale.key, locale.config); | ||
const formatted = formatMoment(getUtcTime(date), dateFormat); | ||
// do browsers require using GMT instead of UTC? | ||
return formatted.replace('UTC', 'GMT'); | ||
let {date = new Date()} = options; | ||
if ((date && date.toString() === 'Invalid Date') || !date) { | ||
// covers if the following are passed in: | ||
// new Date('invalid_date_string') | ||
// date = null | ||
date = new Date(); | ||
} | ||
return date.toUTCString(); | ||
} |
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
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
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
825623
5
22
2488
210
1
62
+ Addedglob-slasher@^1.0.1
+ Addedglobject@^1.0.1
+ Addedlodash.isempty@^3.0.4
+ Addedregular@^0.1.6
+ Addedcore-js@2.6.12(transitive)
- Removedcore-js@1.2.7(transitive)
- Removedfast-url-parser@1.1.3(transitive)
- Removedmoment@2.30.1(transitive)
- Removedpunycode@1.4.1(transitive)