diff --git a/package-lock.json b/package-lock.json index 933fd5cb4..0da08d897 100644 --- a/package-lock.json +++ b/package-lock.json @@ -111,6 +111,290 @@ "to-fast-properties": "^2.0.0" } }, + "@hapi/accept": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@hapi/accept/-/accept-3.2.2.tgz", + "integrity": "sha512-UtXlTT59srtMr7ZRBzK2CvyWqFwlf78hPt9jEXqkwfbwiwRH1PRv/qkS8lgr5ZyoG6kfpU3xTgt2X91Yfe/6Yg==", + "requires": { + "@hapi/boom": "7.x.x", + "@hapi/hoek": "6.x.x" + } + }, + "@hapi/address": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.0.0.tgz", + "integrity": "sha512-mV6T0IYqb0xL1UALPFplXYQmR0twnXG0M6jUswpquqT2sD12BOiCiLy3EvMp/Fy7s3DZElC4/aPjEjo2jeZpvw==" + }, + "@hapi/ammo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@hapi/ammo/-/ammo-3.1.0.tgz", + "integrity": "sha512-iFQBEfm3WwWy8JdPQ8l6qXVLPtzmjITVfaxwl6dfoP8kKv6i2Uk43Ax+ShkNfOVyfEnNggqL2IyZTY3DaaRGNg==", + "requires": { + "@hapi/hoek": "6.x.x" + } + }, + "@hapi/b64": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-4.2.0.tgz", + "integrity": "sha512-hmfPC1aF7cP21489A/IWPC3s1GE+1eAteVwFcOWLwj0Pky8eHgvrXPSSko2IeCpxqOdZhYw71IFN8xKPdv3CtQ==", + "requires": { + "@hapi/hoek": "6.x.x" + } + }, + "@hapi/boom": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-7.4.2.tgz", + "integrity": "sha512-T2CYcTI0AqSvC6YC7keu/fh9LVSMzfoMLharBnPbOwmc+Cexj9joIc5yNDKunaxYq9LPuOwMS0f2B3S1tFQUNw==", + "requires": { + "@hapi/hoek": "6.x.x" + } + }, + "@hapi/bounce": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@hapi/bounce/-/bounce-1.3.0.tgz", + "integrity": "sha512-gF5W/9AL10h/06HEf1bi0FP6KxZZ8LC/yHtDuoACw+1HrULvigHfnBIaSPFJXeHI3V3g0EkJpt1UOW0NKB+m+w==", + "requires": { + "@hapi/boom": "7.x.x", + "@hapi/hoek": "6.x.x" + } + }, + "@hapi/bourne": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", + "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==" + }, + "@hapi/call": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/call/-/call-5.1.0.tgz", + "integrity": "sha512-CiVEXjD/jiIHBqufBW3pdedshEMjRmHtff7m1puot8j4MUmuKRbLlh0DB8fv6QqH/7/55pH1qgFj300r0WpyMw==", + "requires": { + "@hapi/boom": "7.x.x", + "@hapi/hoek": "6.x.x" + } + }, + "@hapi/catbox": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/@hapi/catbox/-/catbox-10.2.1.tgz", + "integrity": "sha512-u13BXlnmmrNUZssjTriRVTLuk6I/yUy5C1/Pia1+E2cpfd7o2/jmEvYdFgeS0Ft9QTz7WWhpXKlrguARUuohhQ==", + "requires": { + "@hapi/boom": "7.x.x", + "@hapi/hoek": "6.x.x", + "@hapi/joi": "15.x.x", + "@hapi/podium": "3.x.x" + } + }, + "@hapi/catbox-memory": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@hapi/catbox-memory/-/catbox-memory-4.1.0.tgz", + "integrity": "sha512-libCGyufOZaJu6uE9nVXw/u8tqOt4ifNIrOSAsDjzS+af3vPJyid8faOICqKCAh3E338UAsUe5AeYdezdsmtpg==", + "requires": { + "@hapi/boom": "7.x.x", + "@hapi/hoek": "6.x.x" + } + }, + "@hapi/content": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@hapi/content/-/content-4.1.0.tgz", + "integrity": "sha512-hv2Czsl49hnWDEfRZOFow/BmYbKyfEknmk3k83gOp6moFn5ceHB4xVcna8OwsGfy8dxO81lhpPy+JgQEaU4SWw==", + "requires": { + "@hapi/boom": "7.x.x" + } + }, + "@hapi/cryptiles": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-4.2.0.tgz", + "integrity": "sha512-P+ioMP1JGhwDOKPRuQls6sT/ln6Fk+Ks6d90mlBi6HcOu5itvdUiFv5Ynq2DvLadPDWaA43lwNxkfZrjE9s2MA==", + "requires": { + "@hapi/boom": "7.x.x" + } + }, + "@hapi/h2o2": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@hapi/h2o2/-/h2o2-8.3.0.tgz", + "integrity": "sha512-JKFqewDvVBXwhIHFIuFjtndzW5SDA1oi7qohwYW/igqfDdOAwYq9cYlpGVPg+KeeDCESDNJCl7bPQt+oQgirOw==", + "requires": { + "@hapi/boom": "7.x.x", + "@hapi/hoek": "6.x.x", + "@hapi/joi": "15.x.x", + "@hapi/wreck": "15.x.x" + } + }, + "@hapi/hapi": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@hapi/hapi/-/hapi-18.3.1.tgz", + "integrity": "sha512-gBiU9isWWezrg0ucX95Ph6AY6fUKZub3FxKapaleoFBJDOUcxTYiQR6Lha2zvHalIFoTl3K04O3Yr/5pD17QkQ==", + "requires": { + "@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": "6.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/heavy": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@hapi/heavy/-/heavy-6.2.0.tgz", + "integrity": "sha512-tzGU9cElY0IxRBudGB7tLFkdpBD8XQPfd6G7DSOnvHRK+q96UHGHn4t59Yd7kDpVucNkErWWYarsGx2KmKPkXA==", + "requires": { + "@hapi/boom": "7.x.x", + "@hapi/hoek": "6.x.x", + "@hapi/joi": "15.x.x" + } + }, + "@hapi/hoek": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-6.2.1.tgz", + "integrity": "sha512-+ryw4GU9pjr1uT6lBuErHJg3NYqzwJTvZ75nKuJijEzpd00Uqi6oiawTGDDf5Hl0zWmI7qHfOtaqB0kpQZJQzA==" + }, + "@hapi/iron": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-5.1.0.tgz", + "integrity": "sha512-+MK3tBPkEKd50SrDTRXa2DVvE0UTPFKxGbodlbQpNP9SVlxi+ZwA640VJtMNj84FZh81UUxda8AOLPRKFffnEA==", + "requires": { + "@hapi/b64": "4.x.x", + "@hapi/boom": "7.x.x", + "@hapi/cryptiles": "4.x.x", + "@hapi/hoek": "6.x.x" + } + }, + "@hapi/joi": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.0.3.tgz", + "integrity": "sha512-z6CesJ2YBwgVCi+ci8SI8zixoj8bGFn/vZb9MBPbSyoxsS2PnWYjHcyTM17VLK6tx64YVK38SDIh10hJypB+ig==", + "requires": { + "@hapi/address": "2.x.x", + "@hapi/hoek": "6.x.x", + "@hapi/topo": "3.x.x" + } + }, + "@hapi/mimos": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@hapi/mimos/-/mimos-4.1.0.tgz", + "integrity": "sha512-CkxOB15TFZDMl5tQ5qezKZvvBnkRYVc8YksNfA5TnqQMMsU7vGPyvuuNFqj+15bfEwHyM6qasxyQNdkX9B/cQw==", + "requires": { + "@hapi/hoek": "6.x.x", + "mime-db": "1.x.x" + } + }, + "@hapi/nigel": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@hapi/nigel/-/nigel-3.1.0.tgz", + "integrity": "sha512-IJyau32pz5Bf7pzUU/8AIn/SvPvhLMQcOel6kM7ECpKyPc895AwttSusRKfgTwfxZOEG6W8DnNv25gLtqrVFSg==", + "requires": { + "@hapi/hoek": "6.x.x", + "@hapi/vise": "3.x.x" + } + }, + "@hapi/pez": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@hapi/pez/-/pez-4.1.0.tgz", + "integrity": "sha512-c+AxL8/cCj+7FB+tzJ5FhWKYP8zF7/7mA3Ft3a5y7h6YT26qzhj5d2JY27jur30KaZbrZAd4ofXXkqvE/IpJlA==", + "requires": { + "@hapi/b64": "4.x.x", + "@hapi/boom": "7.x.x", + "@hapi/content": "4.x.x", + "@hapi/hoek": "6.x.x", + "@hapi/nigel": "3.x.x" + } + }, + "@hapi/podium": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@hapi/podium/-/podium-3.4.0.tgz", + "integrity": "sha512-IwyewAPGlCoq+g5536PKSDqSTfgpwbj+q4cBJpEUNqzwc5C5SM2stuFsULU7x1jKeWevfgWDoYWC75ML4IOYug==", + "requires": { + "@hapi/hoek": "6.x.x", + "@hapi/joi": "15.x.x" + } + }, + "@hapi/shot": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@hapi/shot/-/shot-4.1.0.tgz", + "integrity": "sha512-rpUU5cF08fqAZLLnue6Sy0osj1QMPbrYskehxtLFPdk7CwlPcu9N/wRtgu7vDHTQCKTkag6M8sjc8V8p8lSxpg==", + "requires": { + "@hapi/hoek": "6.x.x", + "@hapi/joi": "15.x.x" + } + }, + "@hapi/somever": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@hapi/somever/-/somever-2.1.0.tgz", + "integrity": "sha512-kMPewbpgLd0MSlNg0bjvq57Levozbg7c3O0idpWRxRgXfXBALNATLf8GRVbnMehYXAh7YRD2mR/91kginDtJ2Q==", + "requires": { + "@hapi/bounce": "1.x.x", + "@hapi/hoek": "6.x.x" + } + }, + "@hapi/statehood": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@hapi/statehood/-/statehood-6.1.0.tgz", + "integrity": "sha512-qc8Qq3kg0b3XK7siXf6DK0wp+rcOrXv336kIP6YrtD9TbQ45TsBobwKkUXB+4R3GCCQ8a6tOj8FR/9bdtjKJCA==", + "requires": { + "@hapi/boom": "7.x.x", + "@hapi/bounce": "1.x.x", + "@hapi/bourne": "1.x.x", + "@hapi/cryptiles": "4.x.x", + "@hapi/hoek": "6.x.x", + "@hapi/iron": "5.x.x", + "@hapi/joi": "15.x.x" + } + }, + "@hapi/subtext": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@hapi/subtext/-/subtext-6.1.0.tgz", + "integrity": "sha512-dNL4IspNciKUK9RJuArwyS1MO07ZU64z4JrCzY1+vRKczYqin8M5i34cpOrQNP3pD/A/6IbRcFg0Jl0G6pwjnA==", + "requires": { + "@hapi/boom": "7.x.x", + "@hapi/bourne": "1.x.x", + "@hapi/content": "4.x.x", + "@hapi/hoek": "6.x.x", + "@hapi/pez": "4.x.x", + "@hapi/wreck": "15.x.x" + } + }, + "@hapi/teamwork": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@hapi/teamwork/-/teamwork-3.3.0.tgz", + "integrity": "sha512-8lMcMkKvt182O/IPsqSDL9KVCsnZRXYKfvBywVOEDa2kCCbHe+lC/7NEu9tc5FYXTQl9uKSurAjyCY3sPP2PFQ==" + }, + "@hapi/topo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.0.tgz", + "integrity": "sha512-gZDI/eXOIk8kP2PkUKjWu9RW8GGVd2Hkgjxyr/S7Z+JF+0mr7bAlbw+DkTRxnD580o8Kqxlnba9wvqp5aOHBww==", + "requires": { + "@hapi/hoek": "6.x.x" + } + }, + "@hapi/vise": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@hapi/vise/-/vise-3.1.0.tgz", + "integrity": "sha512-DUDzV0D4iVO5atghsjGZtzaF0HVtRLcxcnH6rAONyH0stnoLiFloGEuP5nkbIPU0B9cgWTzTUsQPuNHBzxy9Yw==", + "requires": { + "@hapi/hoek": "6.x.x" + } + }, + "@hapi/wreck": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@hapi/wreck/-/wreck-15.0.1.tgz", + "integrity": "sha512-ByXQna/W1FZk7dg8NEhL79u4QkhzszRz76VpgyGstSH8bLM01a0C8RsxmUBgi6Tjkag5jA9kaEIhF9dLpMrtBw==", + "requires": { + "@hapi/boom": "7.x.x", + "@hapi/bourne": "1.x.x", + "@hapi/hoek": "6.x.x" + } + }, "@sinonjs/commons": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.4.0.tgz", @@ -147,30 +431,6 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, - "accept": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/accept/-/accept-2.1.4.tgz", - "integrity": "sha1-iHr1TO7lx/RDBGGXHsQAxh0JrLs=", - "requires": { - "boom": "5.x.x", - "hoek": "4.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "acorn": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", @@ -195,30 +455,6 @@ "uri-js": "^4.2.2" } }, - "ammo": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/ammo/-/ammo-2.0.4.tgz", - "integrity": "sha1-v4CqshFpjqePY+9efxE91dnokX8=", - "requires": { - "boom": "5.x.x", - "hoek": "4.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "ansi-colors": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", @@ -308,11 +544,6 @@ "ast-types-flow": "0.0.7" } }, - "b64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/b64/-/b64-3.0.3.tgz", - "integrity": "sha512-Pbeh0i6OLubPJdIdCepn8ZQHwN2MWznZHbHABSTEfQ706ie+yuxNSaPdqX1xRatT6WanaS1EazMiSg0NUW2XxQ==" - }, "babel-eslint": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz", @@ -345,19 +576,6 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "boom": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz", - "integrity": "sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==", - "requires": { - "hoek": "6.x.x" - } - }, - "bourne": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/bourne/-/bourne-1.1.2.tgz", - "integrity": "sha512-b2dgVkTZhkQirNMohgC00rWfpVqEi9y5tKM1k3JvoNx05ODtfQoPPd4js9CYFQoY0IM8LAmnJulEuWv74zjUOg==" - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -379,30 +597,6 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, - "call": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/call/-/call-4.0.2.tgz", - "integrity": "sha1-33b19R7o3Ui4VqyEAPfmnm1zmcQ=", - "requires": { - "boom": "5.x.x", - "hoek": "4.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -415,46 +609,6 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, - "catbox": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/catbox/-/catbox-7.1.5.tgz", - "integrity": "sha512-4fui5lELzqZ+9cnaAP/BcqXTH6LvWLBRtFhJ0I4FfgfXiSaZcf6k9m9dqOyChiTxNYtvLk7ZMYSf7ahMq3bf5A==", - "requires": { - "boom": "5.x.x", - "hoek": "4.x.x", - "joi": "10.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, - "catbox-memory": { - "version": "2.0.4", - "resolved": "http://registry.npmjs.org/catbox-memory/-/catbox-memory-2.0.4.tgz", - "integrity": "sha1-Qz4lWQLK9UIz0ShkKcj03xToItU=", - "requires": { - "hoek": "4.x.x" - }, - "dependencies": { - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "chai": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", @@ -557,29 +711,6 @@ "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", "dev": true }, - "content": { - "version": "3.0.7", - "resolved": "http://registry.npmjs.org/content/-/content-3.0.7.tgz", - "integrity": "sha512-LXtnSnvE+Z1Cjpa3P9gh9kb396qV4MqpfwKy777BOSF8n6nw2vAi03tHNl0/XRqZUyzVzY/+nMXOZVnEapWzdg==", - "requires": { - "boom": "5.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -593,18 +724,10 @@ "which": "^1.2.9" } }, - "cryptiles": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-4.1.3.tgz", - "integrity": "sha512-gT9nyTMSUC1JnziQpPbxKGBbUg8VL7Zn2NB4E1cJYvuXdElHrwxrV9bmltZGDzet45zSDGyYceueke1TjynGzw==", - "requires": { - "boom": "7.x.x" - } - }, "damerau-levenshtein": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz", - "integrity": "sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.5.tgz", + "integrity": "sha512-CBCRqFnpu715iPmw1KrdOrzRqbdFwQTwAWyyyYS42+iAgHCuXZ+/TdMgQkUENPomxEz9z1BEzuQU2Xw0kUuAgA==", "dev": true }, "debug": { @@ -1163,9 +1286,9 @@ } }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -1177,9 +1300,9 @@ } }, "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, "graceful-fs": { @@ -1194,104 +1317,6 @@ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, - "h2o2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/h2o2/-/h2o2-6.1.0.tgz", - "integrity": "sha1-Ky5/zKDjZlyUl2ReMgOvme2QM/E=", - "requires": { - "boom": "5.x.x", - "hoek": "4.x.x", - "joi": "10.x.x", - "wreck": "12.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, - "hapi": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/hapi/-/hapi-16.7.0.tgz", - "integrity": "sha512-UeMX1LMWmHEIgMlwZGK/3lhI7X0VRvOioVply0Y9qF+/O5woGdQzNB8ZmDnLOBjnB6bdWWHyo5DEamuCsE1vmg==", - "requires": { - "accept": "2.x.x", - "ammo": "2.x.x", - "boom": "5.x.x", - "call": "4.x.x", - "catbox": "7.x.x", - "catbox-memory": "2.x.x", - "cryptiles": "3.x.x", - "heavy": "4.x.x", - "hoek": "4.x.x", - "iron": "4.x.x", - "items": "2.x.x", - "joi": "11.x.x", - "mimos": "3.x.x", - "podium": "1.x.x", - "shot": "3.x.x", - "somever": "1.x.x", - "statehood": "5.x.x", - "subtext": "5.x.x", - "topo": "2.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "cryptiles": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.4.tgz", - "integrity": "sha512-8I1sgZHfVwcSOY6mSGpVU3lw/GSIZvusg8dD2+OGehCJpOhQRLNcH0qb9upQnOH4XhgxxFJSg6E2kx95deb1Tw==", - "requires": { - "boom": "5.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - }, - "isemail": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", - "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", - "requires": { - "punycode": "2.x.x" - } - }, - "joi": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-11.4.0.tgz", - "integrity": "sha512-O7Uw+w/zEWgbL6OcHbyACKSj0PkQeUgmehdoXVSxt92QFCq4+1390Rwh5moI2K/OgC7D8RHRZqHZxT2husMJHA==", - "requires": { - "hoek": "4.x.x", - "isemail": "3.x.x", - "topo": "2.x.x" - } - } - } - }, - "hapi-cors-headers": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/hapi-cors-headers/-/hapi-cors-headers-1.0.3.tgz", - "integrity": "sha512-U/y+kpVLUJ0y86fEk8yleou9C1T5wFopcWQjuxKdMXzCcymTjfSqGz59waqvngUs1SbeXav/y8Ga9C0G0L1MGg==" - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -1319,36 +1344,6 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, - "heavy": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/heavy/-/heavy-4.0.4.tgz", - "integrity": "sha1-NskTNsAMz+hSyqTRUwhjNc0vAOk=", - "requires": { - "boom": "5.x.x", - "hoek": "4.x.x", - "joi": "10.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, - "hoek": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", - "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==" - }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", @@ -1446,39 +1441,6 @@ "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "dev": true }, - "iron": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/iron/-/iron-4.0.5.tgz", - "integrity": "sha1-TwQszri5c480a1mqc0yDqJvDFCg=", - "requires": { - "boom": "5.x.x", - "cryptiles": "3.x.x", - "hoek": "4.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "cryptiles": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.4.tgz", - "integrity": "sha512-8I1sgZHfVwcSOY6mSGpVU3lw/GSIZvusg8dD2+OGehCJpOhQRLNcH0qb9upQnOH4XhgxxFJSg6E2kx95deb1Tw==", - "requires": { - "boom": "5.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -1545,40 +1507,12 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, - "isemail": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-2.2.1.tgz", - "integrity": "sha1-A1PT2aYpUQgMJiwqoKQrjqjp4qY=" - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "items": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/items/-/items-2.1.2.tgz", - "integrity": "sha512-kezcEqgB97BGeZZYtX/MA8AG410ptURstvnz5RAgyFZ8wQFPMxHY8GpTq+/ZHKT3frSlIthUq7EvLt9xn3TvXg==" - }, - "joi": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-10.6.0.tgz", - "integrity": "sha512-hBF3LcqyAid+9X/pwg+eXjD2QBZI5eXnBFJYaAkH4SK3mp9QSRiiQnDYlmlz5pccMvnLcJRS4whhDOTCkmsAdQ==", - "requires": { - "hoek": "4.x.x", - "isemail": "2.x.x", - "items": "2.x.x", - "topo": "2.x.x" - }, - "dependencies": { - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -1814,9 +1748,9 @@ } }, "mime-db": { - "version": "1.39.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.39.0.tgz", - "integrity": "sha512-DTsrw/iWVvwHH+9Otxccdyy0Tgiil6TWK/xhfARJZF/QFhwOgZgOIvA2/VIGpM8U7Q8z5nDmdDWC6tuVMJNibw==" + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" }, "mimic-fn": { "version": "1.2.0", @@ -1824,22 +1758,6 @@ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, - "mimos": { - "version": "3.0.3", - "resolved": "http://registry.npmjs.org/mimos/-/mimos-3.0.3.tgz", - "integrity": "sha1-uRCQcq03jCty9qAQHEPd+ys2ZB8=", - "requires": { - "hoek": "4.x.x", - "mime-db": "1.x.x" - }, - "dependencies": { - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -1913,6 +1831,20 @@ "locate-path": "^3.0.0" } }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -1981,22 +1913,6 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, - "nigel": { - "version": "2.0.2", - "resolved": "http://registry.npmjs.org/nigel/-/nigel-2.0.2.tgz", - "integrity": "sha1-k6GGb7DFLYc5CqdeKxYfS1x15bE=", - "requires": { - "hoek": "4.x.x", - "vise": "2.x.x" - }, - "dependencies": { - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "nise": { "version": "1.4.10", "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.10.tgz", @@ -2284,33 +2200,6 @@ "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", "dev": true }, - "pez": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/pez/-/pez-2.1.5.tgz", - "integrity": "sha1-XsLMYlAMw+tCNtSkFM9aF7XrUAc=", - "requires": { - "b64": "3.x.x", - "boom": "5.x.x", - "content": "3.x.x", - "hoek": "4.x.x", - "nigel": "2.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -2326,23 +2215,6 @@ "find-up": "^2.1.0" } }, - "podium": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/podium/-/podium-1.3.0.tgz", - "integrity": "sha512-ZIujqk1pv8bRZNVxwwwq0BhXilZ2udycQT3Kp8ah3f3TcTmVg7ILJsv/oLf47gRa2qeiP584lNq+pfvS9U3aow==", - "requires": { - "hoek": "4.x.x", - "items": "2.x.x", - "joi": "10.x.x" - }, - "dependencies": { - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -2379,7 +2251,8 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true }, "react-is": { "version": "16.8.6", @@ -2470,9 +2343,9 @@ } }, "rxjs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.1.tgz", - "integrity": "sha512-y0j31WJc83wPu31vS1VlAFW5JGrnGC+j+TtGAa1fRQphy48+fDYiDmX8tjGloToEsMkxnouOg/1IzXGKkJnZMg==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -2515,22 +2388,6 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, - "shot": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/shot/-/shot-3.4.2.tgz", - "integrity": "sha1-Hlw/bysmZJrcQvfrNQIUpaApHWc=", - "requires": { - "hoek": "4.x.x", - "joi": "10.x.x" - }, - "dependencies": { - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -2563,21 +2420,6 @@ "is-fullwidth-code-point": "^2.0.0" } }, - "somever": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/somever/-/somever-1.0.1.tgz", - "integrity": "sha512-PCDMBcega4n7wuBUKmkiXidF3cOwtHHGg2qJYl0Rkw7StZqORoCgqce7HUuWNta/NAiQhwLDezNnTANxEWPCGA==", - "requires": { - "hoek": "4.x.x" - }, - "dependencies": { - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -2622,61 +2464,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "statehood": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/statehood/-/statehood-5.0.4.tgz", - "integrity": "sha512-6/feFLqqHylvA/dHwJA0DgXvbEcKgbhRUeljsuu6+cIr8PO88nax7Wc+celZlPTncqT2arsxXL8P329Q1yfe9Q==", - "requires": { - "boom": "5.x.x", - "bourne": "1.x.x", - "cryptiles": "3.x.x", - "hoek": "4.x.x", - "iron": "4.x.x", - "items": "2.x.x", - "joi": "12.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "cryptiles": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.4.tgz", - "integrity": "sha512-8I1sgZHfVwcSOY6mSGpVU3lw/GSIZvusg8dD2+OGehCJpOhQRLNcH0qb9upQnOH4XhgxxFJSg6E2kx95deb1Tw==", - "requires": { - "boom": "5.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - }, - "isemail": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", - "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", - "requires": { - "punycode": "2.x.x" - } - }, - "joi": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-12.0.0.tgz", - "integrity": "sha512-z0FNlV4NGgjQN1fdtHYXf5kmgludM65fG/JlXzU6+rwkt9U5UWuXVYnXa2FpK0u6+qBuCmrm5byPNuiiddAHvQ==", - "requires": { - "hoek": "4.x.x", - "isemail": "3.x.x", - "topo": "2.x.x" - } - } - } - }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -2714,34 +2501,6 @@ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, - "subtext": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/subtext/-/subtext-5.0.1.tgz", - "integrity": "sha512-zH/jaUKJ/bkrTpEe3zuTFIRnqAwv5xcGpXA2JaxEc30KRAT4k78jZnRqM45snjBSZAuvpI8chRUh1VZprcUVfw==", - "requires": { - "boom": "5.x.x", - "bourne": "1.x.x", - "content": "3.x.x", - "hoek": "4.x.x", - "pez": "2.x.x", - "wreck": "12.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -2752,9 +2511,9 @@ } }, "table": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/table/-/table-5.2.3.tgz", - "integrity": "sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/table/-/table-5.3.3.tgz", + "integrity": "sha512-3wUNCgdWX6PNpOe3amTTPWPuF6VGvgzjKCaO1snFj0z7Y3mUPWf5+zDtxUVGispJkDECPmR29wbzh6bVMOHbcw==", "dev": true, "requires": { "ajv": "^6.9.1", @@ -2818,21 +2577,6 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, - "topo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/topo/-/topo-2.0.2.tgz", - "integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=", - "requires": { - "hoek": "4.x.x" - }, - "dependencies": { - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "trim-newlines": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", @@ -2889,21 +2633,6 @@ "resolved": "https://registry.npmjs.org/velocityjs/-/velocityjs-1.1.3.tgz", "integrity": "sha512-7cC2jgKt6AuSaAaJvvTkFFLuYJzKWTYHldPcRVCqR8e6bbx8iOweSTMcTjOmY/RedgINrlWG5m/SZxHJGna8CQ==" }, - "vise": { - "version": "2.0.2", - "resolved": "http://registry.npmjs.org/vise/-/vise-2.0.2.tgz", - "integrity": "sha1-awjo+0y3bjpQzW3Q7DczjoEaDTk=", - "requires": { - "hoek": "4.x.x" - }, - "dependencies": { - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -2987,30 +2716,6 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "wreck": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/wreck/-/wreck-12.5.1.tgz", - "integrity": "sha512-l5DUGrc+yDyIflpty1x9XuMj1ehVjC/dTbF3/BasOO77xk0EdEa4M/DuOY8W88MQDAD0fEDqyjc8bkIMHd2E9A==", - "requires": { - "boom": "5.x.x", - "hoek": "4.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - } - } - }, "write": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", diff --git a/package.json b/package.json index 9b78301e6..6b189353a 100644 --- a/package.json +++ b/package.json @@ -116,11 +116,10 @@ "Dustin Belliston (https://github.com/dwbelliston)" ], "dependencies": { - "boom": "^7.3.0", - "cryptiles": "^4.1.3", - "h2o2": "^6.1.0", - "hapi": "^16.7.0", - "hapi-cors-headers": "^1.0.3", + "@hapi/boom": "^7.4.2", + "@hapi/cryptiles": "^4.2.0", + "@hapi/h2o2": "^8.3.0", + "@hapi/hapi": "^18.3.1", "js-string-escape": "^1.0.1", "jsonpath-plus": "^0.16.0", "jsonschema": "^1.2.4", diff --git a/src/createAuthScheme.js b/src/createAuthScheme.js index b2dbc9f34..eedf313ef 100644 --- a/src/createAuthScheme.js +++ b/src/createAuthScheme.js @@ -1,4 +1,4 @@ -const Boom = require('boom'); +const Boom = require('@hapi/boom'); const createLambdaContext = require('./createLambdaContext'); const functionHelper = require('./functionHelper'); @@ -33,7 +33,7 @@ function createAuthScheme( // Create Auth Scheme return () => ({ - authenticate(request, reply) { + authenticate(request, h) { process.env = Object.assign({}, serverless.service.provider.environment, authFun.environment, process.env); console.log(''); // Just to make things a little pretty serverlessLog(`Running Authorization function for ${request.method} ${request.path} (λ: ${authFunName})`); @@ -112,74 +112,76 @@ function createAuthScheme( catch (err) { debugLog(`create authorization function handler error: ${err}`); - return reply(Boom.badImplementation(null, `Error while loading ${authFunName}: ${err.message}`)); + throw Boom.badImplementation(null, `Error while loading ${authFunName}: ${err.message}`); } - let done = false; - // Creat the Lambda Context for the Auth function - const lambdaContext = createLambdaContext(authFun, serverless.service.provider, (err, result, fromPromise) => { - if (done) { - const warning = fromPromise - ? `Warning: Auth function '${authFunName}' returned a promise and also uses a callback!\nThis is problematic and might cause issues in your lambda.` - : `Warning: callback called twice within Auth function '${authFunName}'!`; + return new Promise((resolve, reject) => { + let done = false; + // Creat the Lambda Context for the Auth function + const lambdaContext = createLambdaContext(authFun, serverless.service.provider, (err, result, fromPromise) => { + if (done) { + const warning = fromPromise + ? `Warning: Auth function '${authFunName}' returned a promise and also uses a callback!\nThis is problematic and might cause issues in your lambda.` + : `Warning: callback called twice within Auth function '${authFunName}'!`; - serverlessLog(warning); + serverlessLog(warning); - return; - } + return; + } - done = true; + done = true; - // Return an unauthorized response - const onError = error => { - serverlessLog(`Authorization function returned an error response: (λ: ${authFunName})`, error); + // Return an unauthorized response + const onError = error => { + serverlessLog(`Authorization function returned an error response: (λ: ${authFunName})`, error); - return reply(Boom.unauthorized('Unauthorized')); - }; + return reject(Boom.unauthorized('Unauthorized')); + }; - if (err) { - return onError(err); - } + if (err) { + return onError(err); + } - const onSuccess = policy => { - // Validate that the policy document has the principalId set - if (!policy.principalId) { - serverlessLog(`Authorization response did not include a principalId: (λ: ${authFunName})`, err); + const onSuccess = policy => { + // Validate that the policy document has the principalId set + if (!policy.principalId) { + serverlessLog(`Authorization response did not include a principalId: (λ: ${authFunName})`, err); - return reply(Boom.forbidden('No principalId set on the Response')); - } + return reject(Boom.forbidden('No principalId set on the Response')); + } - if (!authCanExecuteResource(policy.policyDocument, event.methodArn)) { - serverlessLog(`Authorization response didn't authorize user to access resource: (λ: ${authFunName})`, err); + if (!authCanExecuteResource(policy.policyDocument, event.methodArn)) { + serverlessLog(`Authorization response didn't authorize user to access resource: (λ: ${authFunName})`, err); - return reply(Boom.forbidden('User is not authorized to access this resource')); - } + return reject(Boom.forbidden('User is not authorized to access this resource')); + } - serverlessLog(`Authorization function returned a successful response: (λ: ${authFunName})`, policy); + serverlessLog(`Authorization function returned a successful response: (λ: ${authFunName})`, policy); - // Set the credentials for the rest of the pipeline - return reply.continue({ credentials: { user: policy.principalId, context: policy.context, usageIdentifierKey: policy.usageIdentifierKey } }); - }; + // Set the credentials for the rest of the pipeline + return resolve(h.authenticated({ credentials: { user: policy.principalId, context: policy.context, usageIdentifierKey: policy.usageIdentifierKey } })); + }; - if (result && typeof result.then === 'function' && typeof result.catch === 'function') { - debugLog('Auth function returned a promise'); - result.then(onSuccess).catch(onError); - } - else if (result instanceof Error) { - onError(result); - } - else { - onSuccess(result); - } - }); + if (result && typeof result.then === 'function' && typeof result.catch === 'function') { + debugLog('Auth function returned a promise'); + result.then(onSuccess).catch(onError); + } + else if (result instanceof Error) { + onError(result); + } + else { + onSuccess(result); + } + }); - const x = handler(event, lambdaContext, lambdaContext.done); + const x = handler(event, lambdaContext, lambdaContext.done); - // Promise support - if (!done) { - if (x && typeof x.then === 'function' && typeof x.catch === 'function') x.then(lambdaContext.succeed).catch(lambdaContext.fail); - else if (x instanceof Error) lambdaContext.fail(x); - } + // Promise support + if (!done) { + if (x && typeof x.then === 'function' && typeof x.catch === 'function') x.then(lambdaContext.succeed).catch(lambdaContext.fail); + else if (x instanceof Error) lambdaContext.fail(x); + } + }); }, }); } diff --git a/src/index.js b/src/index.js old mode 100644 new mode 100755 index 71a670309..47b053c62 --- a/src/index.js +++ b/src/index.js @@ -1,13 +1,12 @@ // Node dependencies +const crypto = require('crypto'); const fs = require('fs'); const path = require('path'); const { exec } = require('child_process'); // External dependencies -const Hapi = require('hapi'); -const h2o2 = require('h2o2'); -const corsHeaders = require('hapi-cors-headers'); -const crypto = require('crypto'); +const hapi = require('@hapi/hapi'); +const h2o2 = require('@hapi/h2o2'); // Internal lib const debugLog = require('./debugLog'); @@ -137,7 +136,7 @@ class Offline { enforceSecureCookies: { usage: 'Enforce secure cookies', }, - providedRuntime: { + providedRuntime: { usage: 'Sets the provided runtime for lambdas', }, disableModelValidation: { @@ -321,33 +320,25 @@ class Offline { } _createServer() { - // Hapijs server creation - this.server = new Hapi.Server({ - connections: { - router: { - stripTrailingSlash: !this.options.preserveTrailingSlash, // removes trailing slashes on incoming paths. - }, - }, - }); - - this.server.register(h2o2, err => err && this.serverlessLog(err)); - - const connectionOptions = { + const serverOptions = { host: this.options.host, port: this.options.port, + router: { + stripTrailingSlash: !this.options.preserveTrailingSlash, // removes trailing slashes on incoming paths. + }, }; const httpsDir = this.options.httpsProtocol; // HTTPS support if (typeof httpsDir === 'string' && httpsDir.length > 0) { - connectionOptions.tls = { + serverOptions.tls = { key: fs.readFileSync(path.resolve(httpsDir, 'key.pem'), 'ascii'), cert: fs.readFileSync(path.resolve(httpsDir, 'cert.pem'), 'ascii'), }; } - connectionOptions.state = this.options.enforceSecureCookies ? { + serverOptions.state = this.options.enforceSecureCookies ? { isHttpOnly: true, isSecure: true, isSameSite: false, @@ -357,11 +348,36 @@ class Offline { isSameSite: false, }; - // Passes the configuration object to the server - this.server.connection(connectionOptions); + // Hapijs server creation + this.server = hapi.server(serverOptions); + + this.server.register(h2o2).catch(err => err && this.serverlessLog(err)); // Enable CORS preflight response - this.server.ext('onPreResponse', corsHeaders); + this.server.ext('onPreResponse', (request, h) => { + if (request.headers.origin) { + const response = request.response.isBoom ? request.response.output : request.response; + + response.headers['access-control-allow-origin'] = request.headers.origin; + response.headers['access-control-allow-credentials'] = 'true'; + + if (request.method === 'options') { + response.statusCode = 200; + response.headers['access-control-expose-headers'] = 'content-type, content-length, etag'; + response.headers['access-control-max-age'] = 60 * 10; + + if (request.headers['access-control-request-headers']) { + response.headers['access-control-allow-headers'] = request.headers['access-control-request-headers']; + } + + if (request.headers['access-control-request-method']) { + response.headers['access-control-allow-methods'] = request.headers['access-control-request-method']; + } + } + } + + return h.continue; + }); } _createRoutes() { @@ -503,7 +519,7 @@ class Offline { method: routeMethod, path: fullPath, config: routeConfig, - handler: (request, reply) => { // Here we go + handler: (request, h) => { // Here we go // Payload processing const encoding = utils.detectEncoding(request); @@ -541,14 +557,14 @@ class Offline { // Check for APIKey if ((protectedRoutes.includes(`${routeMethod}#${fullPath}`) || protectedRoutes.includes(`ANY#${fullPath}`)) && !this.options.noAuth) { - const errorResponse = response => response({ message: 'Forbidden' }).code(403).type('application/json').header('x-amzn-ErrorType', 'ForbiddenException'); + const errorResponse = () => h.response({ message: 'Forbidden' }).code(403).type('application/json').header('x-amzn-ErrorType', 'ForbiddenException'); if ('x-api-key' in request.headers) { const requestToken = request.headers['x-api-key']; if (requestToken !== this.options.apiKey) { debugLog(`Method ${method} of function ${funName} token ${requestToken} not valid`); - return errorResponse(reply); + return errorResponse(); } } else if (request.auth && request.auth.credentials && 'usageIdentifierKey' in request.auth.credentials) { @@ -556,13 +572,13 @@ class Offline { if (usageIdentifierKey !== this.options.apiKey) { debugLog(`Method ${method} of function ${funName} token ${usageIdentifierKey} not valid`); - return errorResponse(reply); + return errorResponse(); } } else { debugLog(`Missing x-api-key on private function ${funName}`); - return errorResponse(reply); + return errorResponse(); } } // Shared mutable state is the root of all evil they say @@ -570,8 +586,7 @@ class Offline { this.requests[requestId] = { done: false }; this.currentRequestId = requestId; - // Holds the response to do async op - const response = reply.response().hold(); + const response = h.response(); const contentType = request.mime || defaultContentType; // default request template to '' if we don't have a definition pushed in from serverless or endpoint @@ -662,324 +677,326 @@ class Offline { debugLog('event:', event); - // We create the context, its callback (context.done/succeed/fail) will send the HTTP response - const lambdaContext = createLambdaContext(fun, this.service.provider, (err, data, fromPromise) => { - // Everything in this block happens once the lambda function has resolved - debugLog('_____ HANDLER RESOLVED _____'); - - // User should not call context.done twice - if (this.requests[requestId].done) { - this.printBlankLine(); - const warning = fromPromise - ? `Warning: handler '${funName}' returned a promise and also uses a callback!\nThis is problematic and might cause issues in your lambda.` - : `Warning: context.done called twice within handler '${funName}'!`; - this.serverlessLog(warning); - debugLog('requestId:', requestId); - - return; - } + return new Promise(resolve => { + // We create the context, its callback (context.done/succeed/fail) will send the HTTP response + const lambdaContext = createLambdaContext(fun, this.service.provider, (err, data, fromPromise) => { + // Everything in this block happens once the lambda function has resolved + debugLog('_____ HANDLER RESOLVED _____'); - this.requests[requestId].done = true; - - let result = data; - let responseName = 'default'; - const responseContentType = endpoint.responseContentType; - const contentHandling = endpoint.contentHandling; - - /* RESPONSE SELECTION (among endpoint's possible responses) */ - - // Failure handling - let errorStatusCode = 0; - if (err) { - // Since the --useSeparateProcesses option loads the handler in - // a separate process and serverless-offline communicates with it - // over IPC, we are unable to catch JavaScript unhandledException errors - // when the handler code contains bad JavaScript. Instead, we "catch" - // it here and reply in the same way that we would have above when - // we lazy-load the non-IPC handler function. - if (this.options.useSeparateProcesses && err.ipcException) { - return this._reply500(response, `Error while loading ${funName}`, err); + // User should not call context.done twice + if (this.requests[requestId].done) { + this.printBlankLine(); + const warning = fromPromise + ? `Warning: handler '${funName}' returned a promise and also uses a callback!\nThis is problematic and might cause issues in your lambda.` + : `Warning: context.done called twice within handler '${funName}'!`; + this.serverlessLog(warning); + debugLog('requestId:', requestId); + + return; } - const errorMessage = (err.message || err).toString(); + this.requests[requestId].done = true; + + let result = data; + let responseName = 'default'; + const responseContentType = endpoint.responseContentType; + const contentHandling = endpoint.contentHandling; + + /* RESPONSE SELECTION (among endpoint's possible responses) */ + + // Failure handling + let errorStatusCode = 0; + if (err) { + // Since the --useSeparateProcesses option loads the handler in + // a separate process and serverless-offline communicates with it + // over IPC, we are unable to catch JavaScript unhandledException errors + // when the handler code contains bad JavaScript. Instead, we "catch" + // it here and reply in the same way that we would have above when + // we lazy-load the non-IPC handler function. + if (this.options.useSeparateProcesses && err.ipcException) { + return resolve(this._reply500(response, `Error while loading ${funName}`, err)); + } - const re = /\[(\d{3})]/; - const found = errorMessage.match(re); - if (found && found.length > 1) { - errorStatusCode = found[1]; - } - else { - errorStatusCode = '500'; - } + const errorMessage = (err.message || err).toString(); - // Mocks Lambda errors - result = { - errorMessage, - errorType: err.constructor.name, - stackTrace: this._getArrayStackTrace(err.stack), - }; + const re = /\[(\d{3})]/; + const found = errorMessage.match(re); + if (found && found.length > 1) { + errorStatusCode = found[1]; + } + else { + errorStatusCode = '500'; + } - this.serverlessLog(`Failure: ${errorMessage}`); + // Mocks Lambda errors + result = { + errorMessage, + errorType: err.constructor.name, + stackTrace: this._getArrayStackTrace(err.stack), + }; - if (result.stackTrace) { - debugLog(result.stackTrace.join('\n ')); - } + this.serverlessLog(`Failure: ${errorMessage}`); + + if (result.stackTrace) { + debugLog(result.stackTrace.join('\n ')); + } - for (const key in endpoint.responses) { - if (key !== 'default' && errorMessage.match(`^${endpoint.responses[key].selectionPattern || key}$`)) { - responseName = key; - break; + for (const key in endpoint.responses) { + if (key !== 'default' && errorMessage.match(`^${endpoint.responses[key].selectionPattern || key}$`)) { + responseName = key; + break; + } } } - } - debugLog(`Using response '${responseName}'`); - const chosenResponse = endpoint.responses[responseName]; + debugLog(`Using response '${responseName}'`); + const chosenResponse = endpoint.responses[responseName]; - /* RESPONSE PARAMETERS PROCCESSING */ + /* RESPONSE PARAMETERS PROCCESSING */ - const responseParameters = chosenResponse.responseParameters; + const responseParameters = chosenResponse.responseParameters; - if (responseParameters) { + if (responseParameters) { - const responseParametersKeys = Object.keys(responseParameters); + const responseParametersKeys = Object.keys(responseParameters); - debugLog('_____ RESPONSE PARAMETERS PROCCESSING _____'); - debugLog(`Found ${responseParametersKeys.length} responseParameters for '${responseName}' response`); + debugLog('_____ RESPONSE PARAMETERS PROCCESSING _____'); + debugLog(`Found ${responseParametersKeys.length} responseParameters for '${responseName}' response`); - responseParametersKeys.forEach(key => { + responseParametersKeys.forEach(key => { - // responseParameters use the following shape: "key": "value" - const value = responseParameters[key]; - const keyArray = key.split('.'); // eg: "method.response.header.location" - const valueArray = value.split('.'); // eg: "integration.response.body.redirect.url" + // responseParameters use the following shape: "key": "value" + const value = responseParameters[key]; + const keyArray = key.split('.'); // eg: "method.response.header.location" + const valueArray = value.split('.'); // eg: "integration.response.body.redirect.url" - debugLog(`Processing responseParameter "${key}": "${value}"`); + debugLog(`Processing responseParameter "${key}": "${value}"`); - // For now the plugin only supports modifying headers - if (key.startsWith('method.response.header') && keyArray[3]) { + // For now the plugin only supports modifying headers + if (key.startsWith('method.response.header') && keyArray[3]) { - const headerName = keyArray.slice(3).join('.'); - let headerValue; - debugLog('Found header in left-hand:', headerName); + const headerName = keyArray.slice(3).join('.'); + let headerValue; + debugLog('Found header in left-hand:', headerName); - if (value.startsWith('integration.response')) { - if (valueArray[2] === 'body') { + if (value.startsWith('integration.response')) { + if (valueArray[2] === 'body') { - debugLog('Found body in right-hand'); - headerValue = (valueArray[3] ? jsonPath(result, valueArray.slice(3).join('.')) : result).toString(); + debugLog('Found body in right-hand'); + headerValue = (valueArray[3] ? jsonPath(result, valueArray.slice(3).join('.')) : result).toString(); + } + else { + this.printBlankLine(); + this.serverlessLog(`Warning: while processing responseParameter "${key}": "${value}"`); + this.serverlessLog(`Offline plugin only supports "integration.response.body[.JSON_path]" right-hand responseParameter. Found "${value}" instead. Skipping.`); + this.logPluginIssue(); + this.printBlankLine(); + } } else { - this.printBlankLine(); - this.serverlessLog(`Warning: while processing responseParameter "${key}": "${value}"`); - this.serverlessLog(`Offline plugin only supports "integration.response.body[.JSON_path]" right-hand responseParameter. Found "${value}" instead. Skipping.`); - this.logPluginIssue(); - this.printBlankLine(); + headerValue = value.match(/^'.*'$/) ? value.slice(1, -1) : value; // See #34 } + // Applies the header; + debugLog(`Will assign "${headerValue}" to header "${headerName}"`); + response.header(headerName, headerValue); + } else { - headerValue = value.match(/^'.*'$/) ? value.slice(1, -1) : value; // See #34 + this.printBlankLine(); + this.serverlessLog(`Warning: while processing responseParameter "${key}": "${value}"`); + this.serverlessLog(`Offline plugin only supports "method.response.header.PARAM_NAME" left-hand responseParameter. Found "${key}" instead. Skipping.`); + this.logPluginIssue(); + this.printBlankLine(); } - // Applies the header; - debugLog(`Will assign "${headerValue}" to header "${headerName}"`); - response.header(headerName, headerValue); - - } - else { - this.printBlankLine(); - this.serverlessLog(`Warning: while processing responseParameter "${key}": "${value}"`); - this.serverlessLog(`Offline plugin only supports "method.response.header.PARAM_NAME" left-hand responseParameter. Found "${key}" instead. Skipping.`); - this.logPluginIssue(); - this.printBlankLine(); - } - }); - } + }); + } - let statusCode = 200; + let statusCode = 200; - if (integration === 'lambda') { + if (integration === 'lambda') { - const endpointResponseHeaders = (endpoint.response && endpoint.response.headers) || {}; + const endpointResponseHeaders = (endpoint.response && endpoint.response.headers) || {}; - Object.keys(endpointResponseHeaders) - .filter(key => typeof endpointResponseHeaders[key] === 'string' && /^'.*?'$/.test(endpointResponseHeaders[key])) - .forEach(key => response.header(key, endpointResponseHeaders[key].slice(1, endpointResponseHeaders[key].length - 1))); + Object.keys(endpointResponseHeaders) + .filter(key => typeof endpointResponseHeaders[key] === 'string' && /^'.*?'$/.test(endpointResponseHeaders[key])) + .forEach(key => response.header(key, endpointResponseHeaders[key].slice(1, endpointResponseHeaders[key].length - 1))); - /* LAMBDA INTEGRATION RESPONSE TEMPLATE PROCCESSING */ + /* LAMBDA INTEGRATION RESPONSE TEMPLATE PROCCESSING */ - // If there is a responseTemplate, we apply it to the result - const responseTemplates = chosenResponse.responseTemplates; + // If there is a responseTemplate, we apply it to the result + const responseTemplates = chosenResponse.responseTemplates; - if (typeof responseTemplates === 'object') { - const responseTemplatesKeys = Object.keys(responseTemplates); + if (typeof responseTemplates === 'object') { + const responseTemplatesKeys = Object.keys(responseTemplates); - if (responseTemplatesKeys.length) { + if (responseTemplatesKeys.length) { - // BAD IMPLEMENTATION: first key in responseTemplates - const responseTemplate = responseTemplates[responseContentType]; + // BAD IMPLEMENTATION: first key in responseTemplates + const responseTemplate = responseTemplates[responseContentType]; - if (responseTemplate && responseTemplate !== '\n') { + if (responseTemplate && responseTemplate !== '\n') { - debugLog('_____ RESPONSE TEMPLATE PROCCESSING _____'); - debugLog(`Using responseTemplate '${responseContentType}'`); + debugLog('_____ RESPONSE TEMPLATE PROCCESSING _____'); + debugLog(`Using responseTemplate '${responseContentType}'`); - try { - const reponseContext = createVelocityContext(request, this.velocityContextOptions, result); - result = renderVelocityTemplateObject({ root: responseTemplate }, reponseContext).root; - } - catch (error) { - this.serverlessLog(`Error while parsing responseTemplate '${responseContentType}' for lambda ${funName}:`); - console.log(error.stack); + try { + const reponseContext = createVelocityContext(request, this.velocityContextOptions, result); + result = renderVelocityTemplateObject({ root: responseTemplate }, reponseContext).root; + } + catch (error) { + this.serverlessLog(`Error while parsing responseTemplate '${responseContentType}' for lambda ${funName}:`); + console.log(error.stack); + } } } } - } - /* LAMBDA INTEGRATION HAPIJS RESPONSE CONFIGURATION */ + /* LAMBDA INTEGRATION HAPIJS RESPONSE CONFIGURATION */ - statusCode = errorStatusCode !== 0 ? errorStatusCode : (chosenResponse.statusCode || 200); + statusCode = errorStatusCode !== 0 ? errorStatusCode : (chosenResponse.statusCode || 200); - if (!chosenResponse.statusCode) { - this.printBlankLine(); - this.serverlessLog(`Warning: No statusCode found for response "${responseName}".`); - } + if (!chosenResponse.statusCode) { + this.printBlankLine(); + this.serverlessLog(`Warning: No statusCode found for response "${responseName}".`); + } - response.header('Content-Type', responseContentType, { - override: false, // Maybe a responseParameter set it already. See #34 - }); + response.header('Content-Type', responseContentType, { + override: false, // Maybe a responseParameter set it already. See #34 + }); - response.statusCode = statusCode; + response.statusCode = statusCode; - if (contentHandling === 'CONVERT_TO_BINARY') { - response.encoding = 'binary'; - response.source = Buffer.from(result, 'base64'); - response.variety = 'buffer'; - } - else { - if (result && result.body && typeof result.body !== 'string') { - return this._reply500(response, 'According to the API Gateway specs, the body content must be stringified. Check your Lambda response and make sure you are invoking JSON.stringify(YOUR_CONTENT) on your body object', {}); + if (contentHandling === 'CONVERT_TO_BINARY') { + response.encoding = 'binary'; + response.source = Buffer.from(result, 'base64'); + response.variety = 'buffer'; + } + else { + if (result && result.body && typeof result.body !== 'string') { + return this._reply500(response, 'According to the API Gateway specs, the body content must be stringified. Check your Lambda response and make sure you are invoking JSON.stringify(YOUR_CONTENT) on your body object', {}); + } + response.source = result; } - response.source = result; } - } - else if (integration === 'lambda-proxy') { - - /* LAMBDA PROXY INTEGRATION HAPIJS RESPONSE CONFIGURATION */ + else if (integration === 'lambda-proxy') { - response.statusCode = statusCode = result.statusCode || 200; + /* LAMBDA PROXY INTEGRATION HAPIJS RESPONSE CONFIGURATION */ - const headers = {}; - if (result.headers) { - Object.keys(result.headers).forEach(header => { - headers[header] = (headers[header] || []).concat(result.headers[header]); - }); - } - if (result.multiValueHeaders) { - Object.keys(result.multiValueHeaders).forEach(header => { - headers[header] = (headers[header] || []).concat(result.multiValueHeaders[header]); - }); - } + response.statusCode = statusCode = result.statusCode || 200; - debugLog('headers', headers); - - Object.keys(headers).forEach(header => { - if (header.toLowerCase() === 'set-cookie') { - headers[header].forEach(headerValue => { - const cookieName = headerValue.slice(0, headerValue.indexOf('=')); - const cookieValue = headerValue.slice(headerValue.indexOf('=') + 1); - reply.state(cookieName, cookieValue, { encoding: 'none', strictHeader: false }); + const headers = {}; + if (result.headers) { + Object.keys(result.headers).forEach(header => { + headers[header] = (headers[header] || []).concat(result.headers[header]); }); } - else { - headers[header].forEach(headerValue => { - // it looks like Hapi doesn't support multiple headers with the same name, - // appending values is the closest we can come to the AWS behavior. - response.header(header, headerValue, { append: true }); + if (result.multiValueHeaders) { + Object.keys(result.multiValueHeaders).forEach(header => { + headers[header] = (headers[header] || []).concat(result.multiValueHeaders[header]); }); } - }); - response.header('Content-Type', 'application/json', { override: false, duplicate: false }); + debugLog('headers', headers); - if (typeof result.body !== 'undefined') { - if (result.isBase64Encoded) { - response.encoding = 'binary'; - response.source = Buffer.from(result.body, 'base64'); - response.variety = 'buffer'; - } - else { - if (result.body && typeof result.body !== 'string') { - return this._reply500(response, 'According to the API Gateway specs, the body content must be stringified. Check your Lambda response and make sure you are invoking JSON.stringify(YOUR_CONTENT) on your body object', {}); + Object.keys(headers).forEach(header => { + if (header.toLowerCase() === 'set-cookie') { + headers[header].forEach(headerValue => { + const cookieName = headerValue.slice(0, headerValue.indexOf('=')); + const cookieValue = headerValue.slice(headerValue.indexOf('=') + 1); + h.state(cookieName, cookieValue, { encoding: 'none', strictHeader: false }); + }); + } + else { + headers[header].forEach(headerValue => { + // it looks like Hapi doesn't support multiple headers with the same name, + // appending values is the closest we can come to the AWS behavior. + response.header(header, headerValue, { append: true }); + }); + } + }); + + response.header('Content-Type', 'application/json', { override: false, duplicate: false }); + + if (typeof result.body !== 'undefined') { + if (result.isBase64Encoded) { + response.encoding = 'binary'; + response.source = Buffer.from(result.body, 'base64'); + response.variety = 'buffer'; + } + else { + if (result.body && typeof result.body !== 'string') { + return this._reply500(response, 'According to the API Gateway specs, the body content must be stringified. Check your Lambda response and make sure you are invoking JSON.stringify(YOUR_CONTENT) on your body object', {}); + } + response.source = result.body; } - response.source = result.body; } } - } - // Log response - let whatToLog = result; + // Log response + let whatToLog = result; - try { - whatToLog = JSON.stringify(result); - } - catch (error) { - // nothing - } - finally { - if (this.options.printOutput) this.serverlessLog(err ? `Replying ${statusCode}` : `[${statusCode}] ${whatToLog}`); - debugLog('requestId:', requestId); - } + try { + whatToLog = JSON.stringify(result); + } + catch (error) { + // nothing + } + finally { + if (this.options.printOutput) this.serverlessLog(err ? `Replying ${statusCode}` : `[${statusCode}] ${whatToLog}`); + debugLog('requestId:', requestId); + } - // Bon voyage! - response.send(); - }); + // Bon voyage! + resolve(response); + }); - // Now we are outside of createLambdaContext, so this happens before the handler gets called: + // Now we are outside of createLambdaContext, so this happens before the handler gets called: - // We cannot use Hapijs's timeout feature because the logic above can take a significant time, so we implement it ourselves - this.requests[requestId].timeout = this.options.noTimeout ? null : setTimeout( - this._replyTimeout.bind(this, response, funName, funOptions.funTimeout, requestId), - funOptions.funTimeout - ); + // We cannot use Hapijs's timeout feature because the logic above can take a significant time, so we implement it ourselves + this.requests[requestId].timeout = this.options.noTimeout ? null : setTimeout( + this._replyTimeout.bind(this, response, resolve, funName, funOptions.funTimeout, requestId), + funOptions.funTimeout + ); - // If request body validation is enabled, validate body against the request model. - if (requestBodyValidationModel && !this.options.disableModelValidation) { + // If request body validation is enabled, validate body against the request model. + if (requestBodyValidationModel && !this.options.disableModelValidation) { + try { + requestBodyValidator.validate(requestBodyValidationModel, event.body); + } + catch (error) { + // When request body validation fails, APIG will return back 400 as detailed in: + // https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-method-request-validation.html + return resolve(this._replyError(400, response, `Invalid request body for '${funName}' handler`, error)); + } + } + + // Finally we call the handler + debugLog('_____ CALLING HANDLER _____'); + + let x; try { - requestBodyValidator.validate(requestBodyValidationModel, event.body); + x = handler(event, lambdaContext, lambdaContext.done); + + // Promise support + if (!this.requests[requestId].done) { + if (x && typeof x.then === 'function' && typeof x.catch === 'function') x.then(lambdaContext.succeed).catch(lambdaContext.fail); + else if (x instanceof Error) lambdaContext.fail(x); + } } catch (error) { - // When request body validation fails, APIG will return back 400 as detailed in: - // https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-method-request-validation.html - return this._replyError(400, response, `Invalid request body for '${funName}' handler`, error); + return resolve(this._reply500(response, `Uncaught error in your '${funName}' handler`, error)); } - } - - // Finally we call the handler - debugLog('_____ CALLING HANDLER _____'); - - let x; - try { - x = handler(event, lambdaContext, lambdaContext.done); + finally { + const cleanup = () => { + this._clearTimeout(requestId); + delete this.requests[requestId]; + }; - // Promise support - if (!this.requests[requestId].done) { - if (x && typeof x.then === 'function' && typeof x.catch === 'function') x.then(lambdaContext.succeed).catch(lambdaContext.fail); - else if (x instanceof Error) lambdaContext.fail(x); + if (x && typeof x.then === 'function' && typeof x.catch === 'function') x.then(cleanup, cleanup); + else setTimeout(cleanup, 0); } - } - catch (error) { - return this._reply500(response, `Uncaught error in your '${funName}' handler`, error); - } - finally { - const cleanup = () => { - this._clearTimeout(requestId); - delete this.requests[requestId]; - }; - - if (x && typeof x.then === 'function' && typeof x.catch === 'function') x.then(cleanup, cleanup); - else setTimeout(cleanup, 0); - } + }); }, }); }); @@ -1095,15 +1112,16 @@ class Offline { }; /* eslint-enable no-param-reassign */ this.serverlessLog('Replying error in handler'); - response.send(); + + return response; } _reply500(response, message, err) { // APIG replies 200 by default on failures - this._replyError(200, response, message, err); + return this._replyError(200, response, message, err); } - _replyTimeout(response, funName, funTimeout, requestId) { + _replyTimeout(response, resolve, funName, funTimeout, requestId) { if (this.currentRequestId !== requestId) return; this.serverlessLog(`Replying timeout after ${funTimeout}ms`); @@ -1111,7 +1129,7 @@ class Offline { response.statusCode = 503; response.source = `[Serverless-Offline] Your λ handler '${funName}' timed out after ${funTimeout}ms.`; /* eslint-enable no-param-reassign */ - response.send(); + resolve(response); } _clearTimeout(requestId) { @@ -1167,7 +1185,7 @@ class Offline { method: routeMethod, path: fullPath, config: routeConfig, - handler: (request, reply) => { + handler: (request, h) => { const params = request.params; let resultUri = proxyUriInUse; @@ -1180,7 +1198,8 @@ class Offline { } this.serverlessLog(`PROXY ${request.method} ${request.url.path} -> ${resultUri}`); - reply.proxy({ uri: resultUri, passThrough: true }); + + return h.proxy({ uri: resultUri, passThrough: true }); }, }); }); @@ -1194,17 +1213,19 @@ class Offline { method: '*', path: '/{p*}', config: { cors: this.options.corsConfig }, - handler: (request, reply) => { - const response = reply({ + handler: (request, h) => { + const response = h.response({ statusCode: 404, error: 'Serverless-offline: route not found.', currentRoute: `${request.method} - ${request.path}`, - existingRoutes: this.server.table()[0].table + existingRoutes: this.server.table() .filter(route => route.path !== '/{p*}') // Exclude this (404) route .sort((a, b) => a.path <= b.path ? -1 : 1) // Sort by path .map(route => `${route.method} - ${route.path}`), // Human-friendly result }); response.statusCode = 404; + + return response; }, }); } diff --git a/test/integration/offline.js b/test/integration/offline.js old mode 100644 new mode 100755 index be39ac340..51e9719ae --- a/test/integration/offline.js +++ b/test/integration/offline.js @@ -21,7 +21,7 @@ describe('Offline', () => { offline.inject({ method: 'GET', url: '/magic', - }, res => { + }).then(res => { expect(res.statusCode).to.eq(404); }); }); @@ -57,7 +57,7 @@ describe('Offline', () => { offline.inject({ method: 'GET', url: '/fn2', - }, res => { + }).then(res => { expect(res.statusCode).to.eq(403); expect(res.payload).to.eq(JSON.stringify({ message: 'Forbidden' })); expect(res.headers).to.have.property('x-amzn-errortype', 'ForbiddenException'); @@ -70,7 +70,7 @@ describe('Offline', () => { method: 'GET', url: '/fn2', headers: { 'x-api-key': 'random string' }, - }, res => { + }).then(res => { expect(res.statusCode).to.eq(403); expect(res.payload).to.eq(JSON.stringify({ message: 'Forbidden' })); expect(res.headers).to.have.property('x-amzn-errortype', 'ForbiddenException'); @@ -84,7 +84,7 @@ describe('Offline', () => { url: '/fn2', headers: { 'x-api-key': validToken }, }; - offline.inject(handler, res => { + offline.inject(handler).then(res => { expect(res.statusCode).to.eq(200); expect(res.payload).to.eq(JSON.stringify({ message: 'Private Function Executed Correctly' })); done(); @@ -123,7 +123,7 @@ describe('Offline', () => { offline.inject({ method: 'GET', url: '/fn3', - }, res => { + }).then(res => { expect(res.statusCode).to.eq(200); done(); }); @@ -134,7 +134,7 @@ describe('Offline', () => { method: 'GET', url: '/fn3', headers: { 'x-api-key': validToken }, - }, res => { + }).then(res => { expect(res.statusCode).to.eq(200); done(); }); @@ -160,7 +160,7 @@ describe('Offline', () => { }], }, (event, context, cb) => cb(null, 'Hello World')).toObject(); - offline.inject('/index', res => { + offline.inject('/index').then(res => { expect(res.headers['content-type']).to.contains('text/html'); expect(res.statusCode).to.eq(200); done(); @@ -186,7 +186,7 @@ describe('Offline', () => { }], }, (event, context, cb) => cb(new Error('Internal Server Error'))).toObject(); - offline.inject('/index', res => { + offline.inject('/index').then(res => { expect(res.headers['content-type']).to.contains('text/html'); expect(res.statusCode).to.satisfy(status => status === 500 || status === '500'); done(); @@ -211,7 +211,7 @@ describe('Offline', () => { }], }, (event, context, cb) => cb(new Error('[401] Unauthorized'))).toObject(); - offline.inject('/index', res => { + offline.inject('/index').then(res => { expect(res.headers['content-type']).to.contains('text/html'); expect(res.statusCode).to.satisfy(status => status === 401 || status === '401'); done(); @@ -235,7 +235,7 @@ describe('Offline', () => { method: 'GET', url: '/fn1', payload: { data: 'data' }, - }, res => { + }).then(res => { expect(res.headers).to.have.property('content-type').which.contains('application/json'); done(); }); @@ -261,7 +261,7 @@ describe('Offline', () => { 'content-type': 'application/json', }, payload: { data: 'data' }, - }, res => { + }).then(res => { expect(res.headers).to.have.property('content-type').which.contains('application/json'); done(); }); @@ -287,7 +287,7 @@ describe('Offline', () => { 'content-type': 'application/vnd.api+json', }, payload: { data: 'data' }, - }, res => { + }).then(res => { // console.log(res); expect(res.headers).to.have.property('content-type', 'application/vnd.api+json'); done(); @@ -307,7 +307,7 @@ describe('Offline', () => { offline.inject({ method: 'GET', url: '/fn1', - }, res => { + }).then(res => { expect(res.headers).to.have.property('content-type').which.contains('application/json'); done(); }); @@ -325,7 +325,7 @@ describe('Offline', () => { offline.inject({ method: 'GET', url: '/fn3', - }, res => { + }).then(res => { expect(res.statusCode).to.eq(201); done(); }); @@ -343,7 +343,7 @@ describe('Offline', () => { offline.inject({ method: 'GET', url: '/fn1', - }, res => { + }).then(res => { expect(res.statusCode).to.eq(201); done(); }); @@ -387,7 +387,7 @@ describe('Offline', () => { offline.inject({ method: 'GET', url: '/fn1', - }, res => { + }).then(res => { expect(res.headers).to.have.property('set-cookie'); expect(res.headers['set-cookie'].some(header => header.includes('foo=bar'))).to.be.true(); expect(res.headers['set-cookie'].some(header => header.includes('floo=baz'))).to.be.true(); @@ -409,7 +409,7 @@ describe('Offline', () => { offline.inject({ method: 'GET', url: '/fn1', - }, res => { + }).then(res => { expect(res.payload).to.eq('Hello World'); done(); }); @@ -425,7 +425,7 @@ describe('Offline', () => { statusCode: 200, body: 'Hello', })).toObject(); - offline.inject('/test/some/matching/route', res => { + offline.inject('/test/some/matching/route').then(res => { expect(res.statusCode).to.eq(200); expect(res.payload).to.eq('Hello'); done(); @@ -489,7 +489,7 @@ describe('Offline', () => { url: '/fn2', payload: rawBody, }; - offline.inject(handler, res => { + offline.inject(handler).then(res => { expect(res.statusCode).to.eq(200); expect(res.payload).to.eq(JSON.stringify({ message: 'JSON body was not stripped of newlines or tabs' })); done(); @@ -505,7 +505,7 @@ describe('Offline', () => { 'content-type': 'application/json', }, }; - offline.inject(handler, res => { + offline.inject(handler).then(res => { expect(res.statusCode).to.eq(200); expect(res.payload).to.eq(JSON.stringify({ message: 'JSON body was not stripped of newlines or tabs' })); done(); @@ -539,7 +539,7 @@ describe('Offline', () => { method: 'GET', url: '/index', payload: { data: 'input' }, - }, res => { + }).then(res => { expect(res.headers).to.have.property('content-type').which.contains('application/json'); expect(res.statusCode).to.eq(200); expect(res.payload).to.eq('{"message":"Hello World"}'); @@ -567,7 +567,7 @@ describe('Offline', () => { method: 'GET', url: '/index', payload: { data: 'input' }, - }, res => { + }).then(res => { expect(res.headers).to.have.property('content-type').which.contains('application/json'); expect(res.statusCode).to.eq(200); expect(res.payload).to.eq('{"message":"Hello World"}'); @@ -586,7 +586,7 @@ describe('Offline', () => { offline.inject({ method: 'HEAD', url: '/fn1', - }, res => { + }).then(res => { expect(res.statusCode).to.eq(404); done(); }); @@ -604,7 +604,7 @@ describe('Offline', () => { offline.inject({ method: 'HEAD', url: '/fn1', - }, res => { + }).then(res => { expect(res.statusCode).to.eq(204); done(); }); @@ -631,7 +631,7 @@ describe('Offline', () => { }], }, (event, context, cb) => cb(null, {})).toObject(); - offline.inject('/headers', res => { + offline.inject('/headers').then(res => { expect(res.statusCode).to.eq(200); expect(res.headers).to.have.property('custom-header-1', 'first value'); expect(res.headers).to.have.property('custom-header-2', 'Second Value'); @@ -658,7 +658,7 @@ describe('Offline', () => { }], }, (event, context, cb) => cb(null, {})).toObject(); - offline.inject('/headers', res => { + offline.inject('/headers').then(res => { expect(res.statusCode).to.eq(200); expect(res.headers).not.to.have.property('custom-header-1'); expect(res.headers).not.to.have.property('custom-header-2'); @@ -684,7 +684,7 @@ describe('Offline', () => { }], }, (event, context, cb) => cb(null, {})).toObject(); - offline.inject('/headers', res => { + offline.inject('/headers').then(res => { expect(res.statusCode).to.eq(200); expect(res.headers).not.to.have.property('custom-header-1'); expect(res.headers).not.to.have.property('custom-header-2'); @@ -706,7 +706,7 @@ describe('Offline', () => { headers: { Cookie: 'a.strange.cookie.with.newline.at.the.end=yummie123utuiwi-32432fe3-f3e2e32\n', }, - }, res => { + }).then(res => { expect(res.statusCode).to.eq(400); done(); }); @@ -725,7 +725,7 @@ describe('Offline', () => { headers: { Cookie: 'a.strange.cookie.with.newline.at.the.end=yummie123utuiwi-32432fe3-f3e2e32\n', }, - }, res => { + }).then(res => { expect(res.statusCode).to.eq(200); done(); }); @@ -744,7 +744,7 @@ describe('Offline', () => { url: '/fn2', headers: { }, - }, res => { + }).then(res => { res.headers['set-cookie'].forEach(v => expect(v.match(/httponly/i)).to.eq(null)); done(); }); @@ -760,7 +760,7 @@ describe('Offline', () => { url: '/fn3', headers: { }, - }, res => { + }).then(res => { res.headers['set-cookie'].forEach(v => expect(v.match(/secure/i)).to.eq(null)); done(); }); @@ -776,7 +776,7 @@ describe('Offline', () => { url: '/fn4', headers: { }, - }, res => { + }).then(res => { res.headers['set-cookie'].forEach(v => expect(v.match(/samesite/i)).to.eq(null)); done(); });