diff --git a/package-lock.json b/package-lock.json index 007806b..f2ae87c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,9 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { + "@financial-times/n-logger": "^10.3.0", "isomorphic-fetch": "^2.0.0", + "mockery": "^2.1.0", "n-eager-fetch": "^5.1.0" }, "devDependencies": { @@ -431,6 +433,20 @@ "node-fetch": "^1.6.3" } }, + "node_modules/@financial-times/n-fetch/node_modules/@financial-times/n-logger": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@financial-times/n-logger/-/n-logger-5.7.2.tgz", + "integrity": "sha512-MoTlTU5Zqge5ZeoHYbdfFAxKsMxBfrmWRD60QrUb3O+RBHtTkjySYX0lSP2SZQ7FbiVw/sYJokouvz/DYnDXVQ==", + "dev": true, + "dependencies": { + "isomorphic-fetch": "^2.2.1", + "request": "^2.83.0", + "winston": "^2.4.0" + }, + "engines": { + "node": ">=6.1.0" + } + }, "node_modules/@financial-times/n-gage": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/@financial-times/n-gage/-/n-gage-8.3.2.tgz", @@ -839,17 +855,37 @@ } }, "node_modules/@financial-times/n-logger": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/@financial-times/n-logger/-/n-logger-5.7.2.tgz", - "integrity": "sha1-tR/WW6c4FdklaEQUl2yQOIUZsU8=", - "dev": true, + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@financial-times/n-logger/-/n-logger-10.3.0.tgz", + "integrity": "sha512-2mAU1JxAp+9J2rjxNbAumir9Fz7nhtFRBNTwqACtllmCqf4r8UjqimftWxTU3t/888wU0ujUHFvOFI7zX03ahw==", + "hasInstallScript": true, "dependencies": { - "isomorphic-fetch": "^2.2.1", - "request": "^2.83.0", + "json-stringify-safe": "^5.0.1", + "node-fetch": "^2.6.7", "winston": "^2.4.0" }, "engines": { - "node": ">=6.1.0" + "node": "14.x || 16.x || 18.x", + "npm": "7.x || 8.x" + } + }, + "node_modules/@financial-times/n-logger/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, "node_modules/@financial-times/n-pa11y-config": { @@ -2555,7 +2591,7 @@ "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, "engines": { "node": ">=0.8" @@ -2588,7 +2624,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, "node_modules/autoprefixer": { @@ -2628,7 +2664,7 @@ "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true, "engines": { "node": "*" @@ -3103,7 +3139,7 @@ "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, "node_modules/chai": { @@ -3723,7 +3759,7 @@ "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, "dependencies": { "assert-plus": "^1.0.0" @@ -3950,7 +3986,7 @@ "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "engines": { "node": ">=0.4.0" @@ -4178,7 +4214,7 @@ "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, "dependencies": { "jsbn": "~0.1.0", @@ -4741,7 +4777,7 @@ "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true, "engines": [ "node >=0.6.0" @@ -4907,7 +4943,7 @@ "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, "engines": { "node": "*" @@ -5038,7 +5074,7 @@ "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "dependencies": { "assert-plus": "^1.0.0" @@ -5300,7 +5336,7 @@ "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true, "engines": { "node": ">=4" @@ -5449,7 +5485,7 @@ "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, "dependencies": { "assert-plus": "^1.0.0", @@ -6373,7 +6409,7 @@ "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, "node_modules/jsesc": { @@ -6423,9 +6459,9 @@ "dev": true }, "node_modules/json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "dev": true }, "node_modules/json-schema-traverse": { @@ -6473,18 +6509,18 @@ } }, "node_modules/jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, - "engines": [ - "node >=0.6.0" - ], "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", - "json-schema": "0.2.3", + "json-schema": "0.4.0", "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" } }, "node_modules/jszip": { @@ -7280,21 +7316,21 @@ } }, "node_modules/mime-db": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", - "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.32", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", - "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "dependencies": { - "mime-db": "1.49.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -7495,6 +7531,11 @@ "node": ">=0.10.0" } }, + "node_modules/mockery": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mockery/-/mockery-2.1.0.tgz", + "integrity": "sha512-9VkOmxKlWXoDO/h1jDZaS4lH33aWfRiJiNT/tKj+8OGzrcFDLo8d0syGdbsc3Bc4GvRXPb+NMMvojotmuGJTvA==" + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -7550,40 +7591,6 @@ "npm": "7.x || 8.x" } }, - "node_modules/n-eager-fetch/node_modules/@financial-times/n-logger": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/@financial-times/n-logger/-/n-logger-10.2.0.tgz", - "integrity": "sha512-7mjjYNSMklnTky+WLhFqdFvT6VBM+QOHkMnfoclqv0YoJlatY/oP8MtfeufxXqGBzGJrRH90xbq0Qs1InracXQ==", - "hasInstallScript": true, - "dependencies": { - "json-stringify-safe": "^5.0.1", - "node-fetch": "^2.6.0", - "winston": "^2.4.0" - }, - "engines": { - "node": "14.x || 16.x", - "npm": "7.x || 8.x" - } - }, - "node_modules/n-eager-fetch/node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -8463,7 +8470,7 @@ "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "dev": true }, "node_modules/picomatch": { @@ -8816,9 +8823,9 @@ "dev": true }, "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, "node_modules/pump": { @@ -8874,9 +8881,9 @@ } }, "node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true, "engines": { "node": ">=0.6" @@ -10924,9 +10931,9 @@ } }, "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", "dev": true, "dependencies": { "asn1": "~0.2.3", @@ -12173,7 +12180,7 @@ "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "dependencies": { "safe-buffer": "^5.0.1" @@ -12528,7 +12535,7 @@ "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "engines": [ "node >=0.6.0" @@ -13245,6 +13252,19 @@ "@financial-times/n-logger": "^5.5.3", "http-errors": "^1.6.1", "node-fetch": "^1.6.3" + }, + "dependencies": { + "@financial-times/n-logger": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@financial-times/n-logger/-/n-logger-5.7.2.tgz", + "integrity": "sha512-MoTlTU5Zqge5ZeoHYbdfFAxKsMxBfrmWRD60QrUb3O+RBHtTkjySYX0lSP2SZQ7FbiVw/sYJokouvz/DYnDXVQ==", + "dev": true, + "requires": { + "isomorphic-fetch": "^2.2.1", + "request": "^2.83.0", + "winston": "^2.4.0" + } + } } }, "@financial-times/n-gage": { @@ -13568,14 +13588,23 @@ } }, "@financial-times/n-logger": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/@financial-times/n-logger/-/n-logger-5.7.2.tgz", - "integrity": "sha1-tR/WW6c4FdklaEQUl2yQOIUZsU8=", - "dev": true, + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@financial-times/n-logger/-/n-logger-10.3.0.tgz", + "integrity": "sha512-2mAU1JxAp+9J2rjxNbAumir9Fz7nhtFRBNTwqACtllmCqf4r8UjqimftWxTU3t/888wU0ujUHFvOFI7zX03ahw==", "requires": { - "isomorphic-fetch": "^2.2.1", - "request": "^2.83.0", + "json-stringify-safe": "^5.0.1", + "node-fetch": "^2.6.7", "winston": "^2.4.0" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + } } }, "@financial-times/n-pa11y-config": { @@ -14951,7 +14980,7 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true }, "assertion-error": { @@ -14975,7 +15004,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, "autoprefixer": { @@ -15002,7 +15031,7 @@ "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true }, "aws4": { @@ -15343,7 +15372,7 @@ "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, "chai": { @@ -15815,7 +15844,7 @@ "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, "requires": { "assert-plus": "^1.0.0" @@ -15982,7 +16011,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true }, "denodeify": { @@ -16178,7 +16207,7 @@ "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, "requires": { "jsbn": "~0.1.0", @@ -16638,7 +16667,7 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true }, "eyes": { @@ -16775,7 +16804,7 @@ "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true }, "form-data": { @@ -16878,7 +16907,7 @@ "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "requires": { "assert-plus": "^1.0.0" @@ -17082,7 +17111,7 @@ "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true }, "har-validator": { @@ -17191,7 +17220,7 @@ "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, "requires": { "assert-plus": "^1.0.0", @@ -17824,7 +17853,7 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, "jsesc": { @@ -17865,9 +17894,9 @@ "dev": true }, "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "dev": true }, "json-schema-traverse": { @@ -17907,14 +17936,14 @@ } }, "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", - "json-schema": "0.2.3", + "json-schema": "0.4.0", "verror": "1.10.0" } }, @@ -18603,18 +18632,18 @@ } }, "mime-db": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", - "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true }, "mime-types": { - "version": "2.1.32", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", - "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "requires": { - "mime-db": "1.49.0" + "mime-db": "1.52.0" } }, "mimic-fn": { @@ -18771,6 +18800,11 @@ } } }, + "mockery": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mockery/-/mockery-2.1.0.tgz", + "integrity": "sha512-9VkOmxKlWXoDO/h1jDZaS4lH33aWfRiJiNT/tKj+8OGzrcFDLo8d0syGdbsc3Bc4GvRXPb+NMMvojotmuGJTvA==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -18812,26 +18846,6 @@ "@financial-times/n-logger": "^10.2.0", "isomorphic-fetch": "^2.1.1", "npm-prepublish": "^1.2.2" - }, - "dependencies": { - "@financial-times/n-logger": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/@financial-times/n-logger/-/n-logger-10.2.0.tgz", - "integrity": "sha512-7mjjYNSMklnTky+WLhFqdFvT6VBM+QOHkMnfoclqv0YoJlatY/oP8MtfeufxXqGBzGJrRH90xbq0Qs1InracXQ==", - "requires": { - "json-stringify-safe": "^5.0.1", - "node-fetch": "^2.6.0", - "winston": "^2.4.0" - } - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - } } }, "natural-compare": { @@ -19519,7 +19533,7 @@ "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "dev": true }, "picomatch": { @@ -19783,9 +19797,9 @@ "dev": true }, "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, "pump": { @@ -19837,9 +19851,9 @@ } }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true }, "queue": { @@ -21479,9 +21493,9 @@ } }, "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", "dev": true, "requires": { "asn1": "~0.2.3", @@ -22441,7 +22455,7 @@ "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "requires": { "safe-buffer": "^5.0.1" @@ -22716,7 +22730,7 @@ "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "requires": { "assert-plus": "^1.0.0", diff --git a/package.json b/package.json index 635cfe6..875c9bf 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,9 @@ "lib": "./lib" }, "dependencies": { + "@financial-times/n-logger": "^10.3.0", "isomorphic-fetch": "^2.0.0", + "mockery": "^2.1.0", "n-eager-fetch": "^5.1.0" }, "devDependencies": { diff --git a/src/poller.js b/src/poller.js index 5be5858..fad76c2 100644 --- a/src/poller.js +++ b/src/poller.js @@ -1,11 +1,12 @@ 'use strict'; const errors = require('./errors'); +const logger = require('@financial-times/n-logger').default; require ('isomorphic-fetch'); module.exports = EventEmitter => { - return class Poller extends EventEmitter { + class Poller extends EventEmitter { constructor (config) { super (); @@ -16,6 +17,7 @@ module.exports = EventEmitter => { this.url = config.url; this.options = config.options || {}; this.data = config.defaultData; + this.state = Poller.states.INITIAL; this.options.timeout = this.options.timeout || 4000; this.options.headers = this.options.headers || {}; @@ -102,19 +104,48 @@ module.exports = EventEmitter => { }) .then (async s => { this.data = await this.parseData (s); + this.setState (Poller.states.FRESH); this.emit ('data', this.data); }) .catch ((err) => { + if (this.state === Poller.states.INITIAL) { + this.setState (Poller.states.ERRORING, err); + } else { + this.setState (Poller.states.STALE, err); + } this.emit ('error', err); }); } - getData () { - if (this.error) { - throw this.error; + setState (state, error) { + this.state = state; + if (state === Poller.states.ERRORING) { + logger.error ( + 'Poller is serving default data. It was unable to fetch fresh data', + { event: 'POLLER_DATA_DEFAULT' }, + error + ); } + if (state === Poller.states.STALE) { + logger.warn ( + 'Poller is serving stale data. It was unable to fetch fresh data', + { event: 'POLLER_DATA_STALE' }, + error + ); + } + } + getData () { return this.data; } }; + + Poller.states = { + INITIAL: 'initial', + ERRORING: 'erroring', + STALE: 'stale', + FRESH: 'fresh' + }; + + return Poller; }; diff --git a/tests/poller.spec.js b/tests/poller.spec.js index 39eb902..9a93f0d 100644 --- a/tests/poller.spec.js +++ b/tests/poller.spec.js @@ -1,12 +1,25 @@ /* global it, describe, xit */ +const mockery = require ('mockery'); const chai = require ('chai'); -const Poller = require ('../src/server'); const sinon = require ('sinon'); const nock = require ('nock'); const expect = chai.expect; const HttpError = require('../src/errors').HttpError; +mockery.enable ({ + warnOnReplace: false, + warnOnUnregistered: false +}); + +const mockLogger = { + error: sinon.stub(), + warn: sinon.stub() +}; +mockery.registerMock ('@financial-times/n-logger', { default: mockLogger }); + +const Poller = require ('../src/server'); + describe ('Poller', function () { it ('Should exist', function () { @@ -168,55 +181,29 @@ describe ('Poller', function () { }); - it ('Should throw from getData when fetch has received an HTTP error', function (done) { + it ('Should return defaultData if the server errors after the poller autostarts without listening for errors', function (done) { const ft = nock ('http://example.com') .get ('/') .reply (503, {}); - const p = new Poller({ - url: 'http://example.com' - }); - - p.fetch (); - - setTimeout (function () { - expect (ft.isDone ()).to.be.true; // ensure Nock has been used - expect (function () { - p.getData (); - }).to.throw ('HTTP Error 503 Service Unavailable'); - done (); - }, 10); - - }); - - it ('Should return data from getData when fetch has received an HTTP error followed by a success', function (done) { - - const ft = nock ('http://example.com'); + const defaultData = [1, 2, 3] const p = new Poller({ - url: 'http://example.com' + url: 'http://example.com', + defaultData, + autostart: true, }); - ft.get ('/').reply (503, '

error

'); - - p.fetch (); + const eventEmitterStub = sinon.stub (p, 'emit'); setTimeout (function () { - expect (ft.isDone ()).to.be.true; // ensure Nock has been used - expect (function () { - p.getData (); - }).to.throw ('HTTP Error 503 Service Unavailable'); - - ft.get ('/').reply (200, '

website

') - - p.fetch() - - setTimeout (function () { - expect (p.getData ()).to.equal ('

website

'); - done (); - }, 10); - + expect (p.getData()).to.deep.equal(defaultData); + expect (ft.isDone()).to.be.true; // ensure Nock has been used + expect (eventEmitterStub.calledOnce).to.be.true; + expect (eventEmitterStub.getCall (0).args[0]).to.equal ('error'); + expect(eventEmitterStub.getCall (0).args[1]).to.be.an.instanceOf(HttpError); + done (); }, 10); }); @@ -420,4 +407,107 @@ describe ('Poller', function () { p.start ({initialRequest:true}); }); + describe('state management and logging', () => { + let poller; + + beforeEach(() => { + mockLogger.error.reset(); + mockLogger.warn.reset(); + poller = new Poller({ + url: 'http://example.com/states', + defaultData: { isDefaultData: true } + }); + }); + + it('should have a state of "initial"', () => { + expect(poller.state).to.equal('initial'); + }); + + it('should have default data', () => { + expect(poller.getData()).to.deep.equal({ isDefaultData: true }); + }); + + describe('when the first fetch resolves', () => { + + beforeEach(async () => { + nock('http://example.com') + .get('/states') + .once() + .reply(200, { isOriginalData: true }); + await poller.fetch(); + }); + + it('should have a state of "fresh"', () => { + expect(poller.state).to.equal('fresh'); + }); + + it('should have fresh data', () => { + expect(poller.getData()).to.deep.equal({ isOriginalData: true }); + }); + + it('should not log errors or warnings', () => { + expect(mockLogger.error.callCount).to.equal(0); + expect(mockLogger.warn.callCount).to.equal(0); + }); + + describe('when the second fetch rejects', () => { + + beforeEach(async () => { + nock('http://example.com') + .get('/states') + .once() + .reply(500, { isDataFromError: true }); + await poller.fetch(); + }); + + it('should have a state of "stale"', () => { + expect(poller.state).to.equal('stale'); + }); + + it('should have stale data', () => { + expect(poller.getData()).to.deep.equal({ isOriginalData: true }); + }); + + it('should log a warning message', () => { + expect(mockLogger.warn.callCount).to.equal(1); + const args = mockLogger.warn.getCall(0).args; + expect(args[0]).to.equal('Poller is serving stale data. It was unable to fetch fresh data'); + expect(args[1]).to.deep.equal({ event: 'POLLER_DATA_STALE' }); + expect(args[2]).to.be.instanceOf(HttpError); + }); + + }); + + }); + + describe('when the first fetch rejects', () => { + + beforeEach(async () => { + nock('http://example.com') + .get('/states') + .once() + .reply(500, { isDataFromError: true }); + await poller.fetch(); + }); + + it('should have a state of "erroring"', () => { + expect(poller.state).to.equal('erroring'); + }); + + it('should have default data', () => { + expect(poller.getData()).to.deep.equal({ isDefaultData: true }); + }); + + it('should log an error message', () => { + expect(mockLogger.error.callCount).to.equal(1); + const args = mockLogger.error.getCall(0).args; + expect(args[0]).to.equal('Poller is serving default data. It was unable to fetch fresh data'); + expect(args[1]).to.deep.equal({ event: 'POLLER_DATA_DEFAULT' }); + expect(args[2]).to.be.instanceOf(HttpError); + }); + + }); + + }); + });