diff --git a/README.md b/README.md index a691e1a..33774c2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

Kill the Newsletter!

Convert email newsletters into Atom feeds

-

Convert email newsletters into Atom feeds

+

Convert email newsletters into Atom feeds

Source Continuous Integration diff --git a/package-lock.json b/package-lock.json index 0875792..a3c6756 100644 --- a/package-lock.json +++ b/package-lock.json @@ -685,74 +685,6 @@ "chalk": "^3.0.0" } }, - "@oozcitak/dom": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-1.15.5.tgz", - "integrity": "sha512-L6v3Mwb0TaYBYgeYlIeBaHnc+2ZEaDSbFiRm5KmqZQSoBlbPlf+l6aIH/sD5GUf2MYwULw00LT7+dOnEuAEC0A==", - "requires": { - "@oozcitak/infra": "1.0.5", - "@oozcitak/url": "1.0.0", - "@oozcitak/util": "8.0.0" - }, - "dependencies": { - "@oozcitak/util": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.0.0.tgz", - "integrity": "sha512-+9Hq6yuoq/3TRV/n/xcpydGBq2qN2/DEDMqNTG7rm95K6ZE2/YY/sPyx62+1n8QsE9O26e5M1URlXsk+AnN9Jw==" - } - } - }, - "@oozcitak/infra": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-1.0.5.tgz", - "integrity": "sha512-o+zZH7M6l5e3FaAWy3ojaPIVN5eusaYPrKm6MZQt0DKNdgXa2wDYExjpP0t/zx+GoQgQKzLu7cfD8rHCLt8JrQ==", - "requires": { - "@oozcitak/util": "8.0.0" - }, - "dependencies": { - "@oozcitak/util": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.0.0.tgz", - "integrity": "sha512-+9Hq6yuoq/3TRV/n/xcpydGBq2qN2/DEDMqNTG7rm95K6ZE2/YY/sPyx62+1n8QsE9O26e5M1URlXsk+AnN9Jw==" - } - } - }, - "@oozcitak/url": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-1.0.0.tgz", - "integrity": "sha512-LGrMeSxeLzsdaitxq3ZmBRVOrlRRQIgNNci6L0VRnOKlJFuRIkNm4B+BObXPCJA6JT5bEJtrrwjn30jueHJYZQ==", - "requires": { - "@oozcitak/infra": "1.0.3", - "@oozcitak/util": "1.0.2" - }, - "dependencies": { - "@oozcitak/infra": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-1.0.3.tgz", - "integrity": "sha512-9O2wxXGnRzy76O1XUxESxDGsXT5kzETJPvYbreO4mv6bqe1+YSuux2cZTagjJ/T4UfEwFJz5ixanOqB0QgYAag==", - "requires": { - "@oozcitak/util": "1.0.1" - }, - "dependencies": { - "@oozcitak/util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-1.0.1.tgz", - "integrity": "sha512-dFwFqcKrQnJ2SapOmRD1nQWEZUtbtIy9Y6TyJquzsalWNJsKIPxmTI0KG6Ypyl8j7v89L2wixH9fQDNrF78hKg==" - } - } - }, - "@oozcitak/util": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-1.0.2.tgz", - "integrity": "sha512-4n8B1cWlJleSOSba5gxsMcN4tO8KkkcvXhNWW+ADqvq9Xj+Lrl9uCa90GRpjekqQJyt84aUX015DG81LFpZYXA==" - } - } - }, - "@oozcitak/util": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.3.3.tgz", - "integrity": "sha512-Ufpab7G5PfnEhQyy5kDg9C8ltWJjsVT1P/IYqacjstaqydG4Q21HAT2HUZQYBrC/a1ZLKCz87pfydlDvv8y97w==" - }, "@opencensus/core": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.9.tgz", @@ -1139,6 +1071,17 @@ "pretty-format": "^25.1.0" } }, + "@types/jsdom": { + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-16.2.1.tgz", + "integrity": "sha512-KCEq427OsWfpX7FRyEMb3i2XIuz8Pt3XPls4nmX0iMTDJWsHD4Kzoa3v4Uv9c9IDf11ALeHUtPcyAjTz/HV03Q==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/parse5": "*", + "@types/tough-cookie": "*" + } + }, "@types/mailparser": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/@types/mailparser/-/mailparser-2.7.2.tgz", @@ -1169,18 +1112,18 @@ "@types/node": "*" } }, + "@types/parse5": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.2.tgz", + "integrity": "sha512-BOl+6KDs4ItndUWUFchy3aEqGdHhw0BC4Uu+qoDonN/f0rbUnJbm71Ulj8Tt9jLFRaAxPLKvdS1bBLfx1qXR9g==", + "dev": true + }, "@types/prettier": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.19.1.tgz", "integrity": "sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ==", "dev": true }, - "@types/prop-types": { - "version": "15.7.3", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", - "dev": true - }, "@types/qs": { "version": "6.9.1", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.1.tgz", @@ -1193,25 +1136,6 @@ "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", "dev": true }, - "@types/react": { - "version": "16.9.29", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.29.tgz", - "integrity": "sha512-aE5sV9XVqKvIR8Lqa73hXvlqBzz5hBG0jtV9jZ1uuEWRmW8KN/mdQQmsYlPx6z/b2xa8zR3jtk7WoT+2/m4suA==", - "dev": true, - "requires": { - "@types/prop-types": "*", - "csstype": "^2.2.0" - } - }, - "@types/react-dom": { - "version": "16.9.5", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.5.tgz", - "integrity": "sha512-BX6RQ8s9D+2/gDhxrj8OW+YD4R+8hj7FEM/OJHGNR0KipE1h1mSsf39YeyC81qafkq+N3rU3h3RFbLSwE5VqUg==", - "dev": true, - "requires": { - "@types/react": "*" - } - }, "@types/serve-static": { "version": "1.13.3", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", @@ -1238,6 +1162,12 @@ "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", "dev": true }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==", + "dev": true + }, "@types/write-file-atomic": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/write-file-atomic/-/write-file-atomic-3.0.0.tgz", @@ -1265,8 +1195,7 @@ "abab": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", - "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", - "dev": true + "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==" }, "abbrev": { "version": "1.1.1", @@ -1286,32 +1215,21 @@ "acorn": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", - "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", - "dev": true + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==" }, "acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", - "dev": true, + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - }, - "dependencies": { - "acorn": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", - "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", - "dev": true - } + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" } }, "acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", - "dev": true + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", + "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==" }, "agent-base": { "version": "4.3.0", @@ -1849,8 +1767,7 @@ "browser-process-hrtime": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" }, "browser-resolve": { "version": "1.11.3", @@ -2335,14 +2252,12 @@ "cssom": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" }, "cssstyle": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.2.0.tgz", - "integrity": "sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA==", - "dev": true, + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", "requires": { "cssom": "~0.3.6" }, @@ -2350,17 +2265,10 @@ "cssom": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" } } }, - "csstype": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.10.tgz", - "integrity": "sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==", - "dev": true - }, "culvert": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/culvert/-/culvert-0.1.2.tgz", @@ -2380,14 +2288,13 @@ "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==" }, "data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", - "dev": true, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" } }, "date-fns": { @@ -2410,6 +2317,11 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "decimal.js": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz", + "integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw==" + }, "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", @@ -2545,12 +2457,18 @@ "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" }, "domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "dev": true, + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", "requires": { - "webidl-conversions": "^4.0.2" + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==" + } } }, "domhandler": { @@ -2641,9 +2559,9 @@ } }, "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==" }, "error-ex": { "version": "1.3.2", @@ -3397,12 +3315,11 @@ "dev": true }, "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", - "dev": true, + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", "requires": { - "whatwg-encoding": "^1.0.1" + "whatwg-encoding": "^1.0.5" } }, "html-escaper": { @@ -3433,6 +3350,13 @@ "entities": "^1.1.1", "inherits": "^2.0.1", "readable-stream": "^3.1.1" + }, + "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + } } }, "http-errors": { @@ -3573,8 +3497,7 @@ "ip-regex": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" }, "ipaddr.js": { "version": "1.9.1", @@ -3750,6 +3673,11 @@ "isobject": "^3.0.1" } }, + "is-potential-custom-element-name": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", + "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=" + }, "is-redirect": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", @@ -4312,6 +4240,156 @@ "@types/yargs": "^15.0.0", "chalk": "^3.0.0" } + }, + "acorn-globals": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", + "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "dev": true, + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "dev": true + } + } + }, + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", + "dev": true + }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + } + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "^4.0.2" + } + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "jsdom": { + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.2.1.tgz", + "integrity": "sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^7.1.0", + "acorn-globals": "^4.3.2", + "array-equal": "^1.0.0", + "cssom": "^0.4.1", + "cssstyle": "^2.0.0", + "data-urls": "^1.1.0", + "domexception": "^1.0.1", + "escodegen": "^1.11.1", + "html-encoding-sniffer": "^1.0.2", + "nwsapi": "^2.2.0", + "parse5": "5.1.0", + "pn": "^1.1.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.7", + "saxes": "^3.1.9", + "symbol-tree": "^3.2.2", + "tough-cookie": "^3.0.1", + "w3c-hr-time": "^1.0.1", + "w3c-xmlserializer": "^1.1.2", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^7.0.0", + "ws": "^7.0.0", + "xml-name-validator": "^3.0.0" + } + }, + "parse5": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", + "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", + "dev": true + }, + "saxes": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", + "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", + "dev": true, + "requires": { + "xmlchars": "^2.1.1" + } + }, + "tough-cookie": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", + "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "dev": true, + "requires": { + "ip-regex": "^2.1.0", + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "w3c-xmlserializer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", + "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", + "dev": true, + "requires": { + "domexception": "^1.0.1", + "webidl-conversions": "^4.0.2", + "xml-name-validator": "^3.0.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } } } }, @@ -5084,7 +5162,8 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "js-yaml": { "version": "3.13.1", @@ -5102,36 +5181,35 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "jsdom": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.2.1.tgz", - "integrity": "sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g==", - "dev": true, + "version": "16.2.2", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.2.2.tgz", + "integrity": "sha512-pDFQbcYtKBHxRaP55zGXCJWgFHkDAYbKcsXEK/3Icu9nKYZkutUXfLBwbD+09XDutkYSHcgfQLZ0qvpAAm9mvg==", "requires": { - "abab": "^2.0.0", - "acorn": "^7.1.0", - "acorn-globals": "^4.3.2", - "array-equal": "^1.0.0", - "cssom": "^0.4.1", - "cssstyle": "^2.0.0", - "data-urls": "^1.1.0", - "domexception": "^1.0.1", - "escodegen": "^1.11.1", - "html-encoding-sniffer": "^1.0.2", + "abab": "^2.0.3", + "acorn": "^7.1.1", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.2.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.0", + "domexception": "^2.0.1", + "escodegen": "^1.14.1", + "html-encoding-sniffer": "^2.0.1", + "is-potential-custom-element-name": "^1.0.0", "nwsapi": "^2.2.0", - "parse5": "5.1.0", - "pn": "^1.1.0", - "request": "^2.88.0", - "request-promise-native": "^1.0.7", - "saxes": "^3.1.9", - "symbol-tree": "^3.2.2", + "parse5": "5.1.1", + "request": "^2.88.2", + "request-promise-native": "^1.0.8", + "saxes": "^5.0.0", + "symbol-tree": "^3.2.4", "tough-cookie": "^3.0.1", - "w3c-hr-time": "^1.0.1", - "w3c-xmlserializer": "^1.1.2", - "webidl-conversions": "^4.0.2", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.0.0", "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^7.0.0", - "ws": "^7.0.0", + "whatwg-url": "^8.0.0", + "ws": "^7.2.3", "xml-name-validator": "^3.0.0" }, "dependencies": { @@ -5139,7 +5217,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", - "dev": true, "requires": { "ip-regex": "^2.1.0", "psl": "^1.1.28", @@ -5313,8 +5390,7 @@ "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" }, "log-driver": { "version": "1.2.7", @@ -5330,14 +5406,6 @@ "@sinonjs/commons": "^1.7.0" } }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -5772,19 +5840,13 @@ "nwsapi": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==" }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -5978,10 +6040,9 @@ } }, "parse5": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", - "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", - "dev": true + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" }, "parseurl": { "version": "1.3.3", @@ -6382,16 +6443,6 @@ "sisteransi": "^1.0.4" } }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, "proxy-addr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", @@ -6520,31 +6571,11 @@ "strip-json-comments": "~2.0.1" } }, - "react": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz", - "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" - } - }, - "react-dom": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", - "integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" - } - }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true }, "read": { "version": "1.0.7", @@ -6682,7 +6713,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", - "dev": true, "requires": { "lodash": "^4.17.15" } @@ -6691,7 +6721,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", - "dev": true, "requires": { "request-promise-core": "1.1.3", "stealthy-require": "^1.1.1", @@ -6953,27 +6982,22 @@ } } }, + "sanitize-xml-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/sanitize-xml-string/-/sanitize-xml-string-1.1.0.tgz", + "integrity": "sha512-RzX25K64YtZm9FvdZr/Ac7Eeq0va1YX0xmpOkjWoREhgKXXldrJRVJhBel83nS8omIcaKcNTdLY8XzOIK920HA==" + }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "saxes": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", - "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", - "dev": true, + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", "requires": { - "xmlchars": "^2.1.1" - } - }, - "scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "xmlchars": "^2.2.0" } }, "semver": { @@ -7416,8 +7440,7 @@ "stealthy-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" }, "string-length": { "version": "3.1.0", @@ -7518,8 +7541,7 @@ "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, "systeminformation": { "version": "4.23.1", @@ -7699,12 +7721,11 @@ } }, "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", + "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", "requires": { - "punycode": "^2.1.0" + "punycode": "^2.1.1" } }, "tree-kill": { @@ -8080,19 +8101,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, "requires": { "browser-process-hrtime": "^1.0.0" } }, "w3c-xmlserializer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", - "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", - "dev": true, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", "requires": { - "domexception": "^1.0.1", - "webidl-conversions": "^4.0.2", "xml-name-validator": "^3.0.0" } }, @@ -8106,16 +8123,14 @@ } }, "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==" }, "whatwg-encoding": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, "requires": { "iconv-lite": "0.4.24" } @@ -8123,18 +8138,23 @@ "whatwg-mimetype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" }, "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.0.0.tgz", + "integrity": "sha512-41ou2Dugpij8/LPO5Pq64K5q++MnRCBpEHvQr26/mArEKTkCV5aoXIqyhuYtE0pkqScXwhf2JP57rkRTYM29lQ==", "requires": { "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" + "tr46": "^2.0.0", + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==" + } } }, "which": { @@ -8247,10 +8267,9 @@ } }, "ws": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", - "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==", - "dev": true + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.5.tgz", + "integrity": "sha512-C34cIU4+DB2vMyAbmEKossWq2ZQDr6QEyuuCzWrM9zfw1sGc0mYiJ0UnG9zzNykt49C2Fi34hvr2vssFQRS6EA==" }, "xdg-basedir": { "version": "3.0.0", @@ -8261,24 +8280,12 @@ "xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xmlbuilder2": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-2.1.2.tgz", - "integrity": "sha512-PI710tmtVlQ5VmwzbRTuhmVhKnj9pM8Si+iOZCV2g2SNo3gCrpzR2Ka9wNzZtqfD+mnP+xkrqoNy0sjKZqP4Dg==", - "requires": { - "@oozcitak/dom": "1.15.5", - "@oozcitak/infra": "1.0.5", - "@oozcitak/util": "8.3.3" - } + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" }, "xmlchars": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, "xregexp": { "version": "2.0.0", diff --git a/package.json b/package.json index 6e7f80b..f00ddfb 100644 --- a/package.json +++ b/package.json @@ -1,29 +1,28 @@ { "scripts": { - "start": "tsc && concurrently \"tsc --watch\" \"nodemon lib\"", + "start": "tsc && open http://localhost:8000 && concurrently \"tsc --watch\" \"nodemon lib\"", "test": "tsc && jest && prettier --check src" }, "dependencies": { "caddy-npm": "^2.0.0-beta.20", "crypto-random-string": "^3.2.0", + "entities": "^2.0.0", "express": "^4.17.1", + "jsdom": "^16.2.2", "mailparser": "^2.7.7", "pm2": "^4.2.3", - "react": "^16.13.0", - "react-dom": "^16.13.0", + "sanitize-xml-string": "^1.1.0", "smtp-server": "^3.6.0", - "write-file-atomic": "^3.0.3", - "xmlbuilder2": "^2.1.2" + "write-file-atomic": "^3.0.3" }, "devDependencies": { "@types/express": "^4.17.3", "@types/jest": "^25.1.4", + "@types/jsdom": "^16.2.1", "@types/mailparser": "^2.7.2", "@types/node": "^13.9.8", "@types/nodemailer": "^6.4.0", "@types/qs": "^6.9.1", - "@types/react": "^16.9.29", - "@types/react-dom": "^16.9.5", "@types/smtp-server": "^3.5.4", "@types/write-file-atomic": "^3.0.0", "axios": "^0.19.2", diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..e47a370 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,220 @@ +import express from "express"; +import { SMTPServer } from "smtp-server"; +import mailparser from "mailparser"; +import { promises as fs } from "fs"; +import * as entities from "entities"; +import { JSDOM } from "jsdom"; +import * as sanitizeXMLString from "sanitize-xml-string"; +import writeFileAtomic from "write-file-atomic"; +import cryptoRandomString from "crypto-random-string"; + +export const WEB_PORT = process.env.WEB_PORT ?? 8000; +export const EMAIL_PORT = process.env.EMAIL_PORT ?? 2525; +export const BASE_URL = process.env.BASE_URL ?? "http://localhost:8000"; +export const EMAIL_DOMAIN = process.env.EMAIL_DOMAIN ?? "localhost"; +export const ISSUE_REPORT = + process.env.ISSUE_REPORT ?? "mailto:kill-the-newsletter@leafac.com"; + +export const webServer = express() + .use(express.static("static")) + .use(express.urlencoded({ extended: true })) + .get("/", (req, res) => + res.send( + layout(` +

+

+ + +

+
+ `) + ) + ) + .post("/", async (req, res, next) => { + try { + const { name } = req.body; + const identifier = createIdentifier(); + await writeFileAtomic(feedPath(identifier), feed(X(name), identifier)); + res.send( + layout(` +

“${H(name)}” Inbox Created

+ ${created(identifier)} + `) + ); + } catch (error) { + console.error(error); + next(error); + } + }) + .get("/alternate", (req, res) => + res.send( + layout(` +

Typically each entry in a feed includes a link
to an online version of the same content,
but the content from the entries in a Kill the Newsletter!
feed come from emails—an online version may not even exist—
so you’re reading this instead.

+

Create an Inbox

+ `) + ) + ) + .listen(WEB_PORT); + +export const emailServer = new SMTPServer({ + disabledCommands: ["AUTH", "STARTTLS"], + async onData(stream, session, callback) { + try { + const email = await mailparser.simpleParser(stream); + const newEntry = entry( + X(email.subject ?? ""), + X(email.from?.text ?? ""), + X(typeof email.html === "string" ? email.html : email.textAsHtml ?? "") + ); + for (const { address } of session.envelope.rcptTo) { + const match = address.match( + new RegExp(`^(?\\w+)@${EMAIL_DOMAIN}$`) + ); + if (match?.groups === undefined) continue; + const path = feedPath(match.groups.identifier); + const xmlText = await fs.readFile(path, "utf8").catch(() => null); + if (xmlText === null) continue; + const xml = new JSDOM(xmlText, { contentType: "text/xml" }); + const document = xml.window.document; + const updated = document.querySelector("feed > updated"); + if (updated === null) + throw new Error(`Can’t find ‘updated’ field in feed at ‘${path}’.`); + updated.textContent = now(); + const firstEntry = document.querySelector("feed > entry:first-of-type"); + if (firstEntry !== null) + firstEntry.insertAdjacentHTML("beforebegin", newEntry); + else + document + .querySelector("feed")! + .insertAdjacentHTML("beforeend", newEntry); + while ( + document.querySelector("feed > entry") !== null && + xml.serialize().length > 500_000 + ) + document.querySelector("feed > entry:last-of-type")!.remove(); + await writeFileAtomic( + path, + `${xml.serialize()}` + ); + } + callback(); + } catch (error) { + console.error( + `Error receiving email: ${JSON.stringify(session, null, 2)}` + ); + console.error(error); + stream.resume(); + callback(new Error("Failed to receive message. Please try again.")); + } + }, +}).listen(EMAIL_PORT); + +function layout(content: string): string { + return ` + + + + + Kill the Newsletter! + + + + + + + + +
+

Kill the Newsletter!

+

Convert email newsletters into Atom feeds

+

Convert email newsletters into Atom feeds

+
+
${content}
+ + + + `; +} + +function created(identifier: string): string { + return ` +

Sign up for the newsletter with
${feedEmail( + identifier + )}

+

Subscribe to the Atom feed at
${feedURL(identifier)}

+

Don’t share these addresses.
They contain an identifier that other people could use
to send you spam and to control your newsletter subscriptions.

+

Enjoy your readings!

+

Create Another Inbox

+ `.trim(); +} + +function feed(name: string, identifier: string): string { + return ` + + + + ${urn(identifier)} + ${name} + Kill the Newsletter! Inbox: ${feedEmail( + identifier + )} → ${feedURL(identifier)} + ${now()} + Kill the Newsletter! + ${entry( + `“${name}” Inbox Created`, + "Kill the Newsletter!", + X(created(identifier)) + )} + + `; +} + +function entry(title: string, author: string, content: string): string { + return ` + + ${urn(createIdentifier())} + ${title} + ${author} + ${now()} + + ${content} + + `.trim(); +} + +function createIdentifier(): string { + return cryptoRandomString({ + length: 20, + characters: "1234567890qwertyuiopasdfghjklzxcvbnm", + }); +} + +function now(): string { + return new Date().toISOString(); +} + +function feedPath(identifier: string): string { + return `static/feeds/${identifier}.xml`; +} + +function feedURL(identifier: string): string { + return `${BASE_URL}/feeds/${identifier}.xml`; +} + +function feedEmail(identifier: string): string { + return `${identifier}@${EMAIL_DOMAIN}`; +} + +function urn(identifier: string): string { + return `urn:kill-the-newsletter:${identifier}`; +} + +function X(string: string): string { + return entities.encodeXML(sanitizeXMLString.sanitize(string)); +} + +function H(string: string): string { + return entities.encodeHTML(sanitizeXMLString.sanitize(string)); +} diff --git a/src/index.tsx b/src/index.tsx deleted file mode 100644 index 3da9548..0000000 --- a/src/index.tsx +++ /dev/null @@ -1,342 +0,0 @@ -import express from "express"; -import { SMTPServer } from "smtp-server"; -import mailparser from "mailparser"; -import React from "react"; -import ReactDOMServer from "react-dom/server"; -import * as xmlbuilder2 from "xmlbuilder2"; -import { promises as fs } from "fs"; -import writeFileAtomic from "write-file-atomic"; -import cryptoRandomString from "crypto-random-string"; - -export const WEB_PORT = process.env.WEB_PORT ?? 8000; -export const EMAIL_PORT = process.env.EMAIL_PORT ?? 2525; -export const BASE_URL = process.env.BASE_URL ?? "http://localhost:8000"; -export const EMAIL_DOMAIN = process.env.EMAIL_DOMAIN ?? "localhost"; -export const ISSUE_REPORT = - process.env.ISSUE_REPORT ?? "mailto:kill-the-newsletter@leafac.com"; - -export const webServer = express() - .use(express.static("static")) - .use(express.urlencoded({ extended: true })) - .get("/", (req, res) => - res.send( - renderHTML( - -
-
- ) - ) - ) - .post("/", (req, res, next) => { - let name: string; - let identifier: string; - (async () => { - name = req.body.name; - identifier = createIdentifier(); - await fs.writeFile( - feedPath(identifier), - renderXML(Feed({ name, identifier })) - ); - res.send( - renderHTML( - -

- “{name}” Inbox Created -

- -
- ) - ); - })().catch((error) => { - console.error( - `Error creating feed: ${JSON.stringify({ name, identifier }, null, 2)}` - ); - console.error(error); - next(error); - }); - }) - .get("/alternate", (req, res) => - res.send( - renderHTML( - -

- Typically each entry on a feed includes a link -
- to an online version of the same content, -
- but the content from the entries on a{" "} - Kill the Newsletter! -
feed come from emails—an online version may not even exist— -
- so you’re reading this instead. -

- -

- - Create an Inbox - -

-
- ) - ) - ) - .listen(WEB_PORT); - -export const emailServer = new SMTPServer({ - disabledCommands: ["AUTH", "STARTTLS"], - onData(stream, session, callback) { - let email: mailparser.ParsedMail; - (async () => { - email = await mailparser.simpleParser(stream); - const { entry } = Entry({ - title: email.subject ?? "", - author: email.from?.text ?? "", - content: - typeof email.html === "string" ? email.html : email.textAsHtml ?? "", - }); - for (const { address } of session.envelope.rcptTo) { - const match = address.match(new RegExp(`^(\\w+)@${EMAIL_DOMAIN}$`)); - if (match === null) continue; - const identifier = match[1]; - const path = feedPath(identifier); - const xmlText = await fs.readFile(path, "utf8").catch(() => null); - if (xmlText === null) continue; - const xml = parseXML(xmlText); - xml.feed.updated = now(); - if (xml.feed.entry === undefined) xml.feed.entry = []; - if (!Array.isArray(xml.feed.entry)) xml.feed.entry = [xml.feed.entry]; - xml.feed.entry.unshift(entry); - while (xml.feed.entry.length > 0 && renderXML(xml).length > 500_000) - xml.feed.entry.pop(); - await writeFileAtomic(path, renderXML(xml)); - } - callback(); - })().catch((error) => { - console.error( - `Error receiving email: ${JSON.stringify({ session, email }, null, 2)}` - ); - console.error(error); - stream.resume(); - callback(new Error("Failed to receive message. Please try again.")); - }); - }, -}).listen(EMAIL_PORT); - -function Layout({ children }: { children: React.ReactNode }) { - return ( - - - - - - - - - - - - - Kill the Newsletter! - - -
-

- Kill the Newsletter! -

-

Convert email newsletters into Atom feeds

-

- Convert email newsletters into Atom feeds -

-
-
{children}
- - - - ); -} - -function Form() { - return ( -
-

- - -

-
- ); -} - -function Created({ identifier }: { identifier: string }) { - return ( - <> -

- Sign up for the newsletter with -
- {feedEmail(identifier)} -

-

- Subscribe to the Atom feed at -
- {feedURL(identifier)} -

-

- Don’t share these addresses. -
- They contain an identifier that other people could use -
- to send you spam and to control your newsletter subscriptions. -

-

Enjoy your readings!

-

- - Create Another Inbox - -

- - ); -} - -function Feed({ name, identifier }: { name: string; identifier: string }) { - return { - feed: { - "@xmlns": "http://www.w3.org/2005/Atom", - link: [ - { - "@rel": "self", - "@type": "application/atom+xml", - "@href": feedURL(identifier), - }, - { - "@rel": "alternate", - "@type": "text/html", - "@href": `${BASE_URL}/alternate`, - }, - ], - id: urn(identifier), - title: name, - subtitle: `Kill the Newsletter! Inbox: ${feedEmail( - identifier - )} → ${feedURL(identifier)}`, - updated: now(), - author: { name: "Kill the Newsletter!" }, - ...Entry({ - title: `“${name}” Inbox Created`, - author: "Kill the Newsletter!", - content: ReactDOMServer.renderToStaticMarkup( - - ), - }), - }, - }; -} - -function Entry({ - title, - author, - content, -}: { - title: string; - author: string; - content: string; -}) { - return { - entry: { - id: urn(createIdentifier()), - title, - author: { name: author }, - updated: now(), - link: { - "@rel": "alternate", - "@type": "text/html", - "@href": `${BASE_URL}/alternate`, - }, - content: { "@type": "html", "#": content }, - }, - }; -} - -function createIdentifier(): string { - return cryptoRandomString({ - length: 20, - characters: "1234567890qwertyuiopasdfghjklzxcvbnm", - }); -} - -function now(): string { - return new Date().toISOString(); -} - -function feedPath(identifier: string): string { - return `static/feeds/${identifier}.xml`; -} - -function feedURL(identifier: string): string { - return `${BASE_URL}/feeds/${identifier}.xml`; -} - -function feedEmail(identifier: string): string { - return `${identifier}@${EMAIL_DOMAIN}`; -} - -function urn(identifier: string): string { - return `urn:kill-the-newsletter:${identifier}`; -} - -function renderHTML(component: React.ReactElement): string { - return `\n${ReactDOMServer.renderToStaticMarkup(component)}`; -} - -function renderXML(xml: object): string { - return xmlbuilder2.convert({ invalidCharReplacement: "" }, xml, { - format: "xml", - noDoubleEncoding: true, - prettyPrint: true, - }); -} - -function parseXML(xml: string): any { - return xmlbuilder2.convert({ invalidCharReplacement: "" }, xml, { - format: "object", - noDoubleEncoding: true, - }); -} diff --git a/src/test.ts b/src/test.ts index ccd54b7..dc9a3ec 100644 --- a/src/test.ts +++ b/src/test.ts @@ -70,10 +70,10 @@ describe("receive email", () => { from: "publisher@example.com", to: `${identifier}@${EMAIL_DOMAIN}`, subject: "New Message", - html: "

Invalid XML character (backspace): |\b|

", + html: "

Invalid XML character (backspace): |\b|💩

", }); const feed = await getFeed(identifier); - expect(feed).toMatch("Invalid XML character (backspace): ||"); + expect(feed).toMatch("Invalid XML character (backspace): ||💩"); }); test("invalid XML character in text", async () => { @@ -82,10 +82,12 @@ describe("receive email", () => { from: "publisher@example.com", to: `${identifier}@${EMAIL_DOMAIN}`, subject: "New Message", - text: "Invalid XML character (backspace): |\b|", + text: "Invalid XML character (backspace): |\b|💩", }); const feed = await getFeed(identifier); - expect(feed).toMatch("Invalid XML character (backspace): |&#x8;|"); + expect(feed).toMatch( + "Invalid XML character (backspace): |&#x8;|&#x1F4A9;" + ); }); test("missing content", async () => { @@ -124,6 +126,26 @@ describe("receive email", () => { expect(feed).not.toMatch("REPETITION 0"); }); + test("too big entry", async () => { + const identifier = await createFeed(); + await emailClient.sendMail({ + from: "publisher@example.com", + to: `${identifier}@${EMAIL_DOMAIN}`, + subject: "New Message", + text: `TOO BIG`.repeat(100_000), + }); + expect(await getFeed(identifier)).not.toMatch(""); + await emailClient.sendMail({ + from: "publisher@example.com", + to: `${identifier}@${EMAIL_DOMAIN}`, + subject: "New Message", + text: `NORMAL SIZE`, + }); + const feed = await getFeed(identifier); + expect(feed).toMatch(""); + expect(feed).toMatch("NORMAL SIZE"); + }); + test("nonexistent address", async () => { await emailClient.sendMail({ from: "publisher@example.com", diff --git a/static/favicon-16x16.png b/static/favicon-16x16.png index 2de8de9..7ec6a0b 100644 Binary files a/static/favicon-16x16.png and b/static/favicon-16x16.png differ diff --git a/static/favicon-32x32.png b/static/favicon-32x32.png index 122b59c..e8d7a40 100644 Binary files a/static/favicon-32x32.png and b/static/favicon-32x32.png differ diff --git a/static/favicon.ico b/static/favicon.ico index f95891d..be034d6 100644 Binary files a/static/favicon.ico and b/static/favicon.ico differ diff --git a/static/favicon.png b/static/favicon.png new file mode 100644 index 0000000..75b1628 Binary files /dev/null and b/static/favicon.png differ diff --git a/static/favicon.svg b/static/favicon.svg new file mode 100644 index 0000000..c5de937 --- /dev/null +++ b/static/favicon.svg @@ -0,0 +1,91 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/static/logo.key b/static/logo.key deleted file mode 100755 index 6750c69..0000000 Binary files a/static/logo.key and /dev/null differ diff --git a/static/logo.png b/static/logo.png deleted file mode 100644 index e65ede7..0000000 Binary files a/static/logo.png and /dev/null differ diff --git a/static/logo.svg b/static/logo.svg new file mode 100644 index 0000000..c6aacdb --- /dev/null +++ b/static/logo.svg @@ -0,0 +1,83 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/static/fonts/typeface-pt-mono/README.md b/static/node_modules/typeface-pt-mono/README.md similarity index 100% rename from static/fonts/typeface-pt-mono/README.md rename to static/node_modules/typeface-pt-mono/README.md diff --git a/static/fonts/typeface-pt-mono/files-hash.json b/static/node_modules/typeface-pt-mono/files-hash.json similarity index 100% rename from static/fonts/typeface-pt-mono/files-hash.json rename to static/node_modules/typeface-pt-mono/files-hash.json diff --git a/static/fonts/typeface-pt-mono/files/pt-mono-latin-400.woff b/static/node_modules/typeface-pt-mono/files/pt-mono-latin-400.woff similarity index 100% rename from static/fonts/typeface-pt-mono/files/pt-mono-latin-400.woff rename to static/node_modules/typeface-pt-mono/files/pt-mono-latin-400.woff diff --git a/static/fonts/typeface-pt-mono/files/pt-mono-latin-400.woff2 b/static/node_modules/typeface-pt-mono/files/pt-mono-latin-400.woff2 similarity index 100% rename from static/fonts/typeface-pt-mono/files/pt-mono-latin-400.woff2 rename to static/node_modules/typeface-pt-mono/files/pt-mono-latin-400.woff2 diff --git a/static/fonts/typeface-pt-mono/index.css b/static/node_modules/typeface-pt-mono/index.css similarity index 100% rename from static/fonts/typeface-pt-mono/index.css rename to static/node_modules/typeface-pt-mono/index.css diff --git a/static/fonts/typeface-pt-mono/package.json b/static/node_modules/typeface-pt-mono/package.json similarity index 94% rename from static/fonts/typeface-pt-mono/package.json rename to static/node_modules/typeface-pt-mono/package.json index f7f9fd6..9d8f115 100644 --- a/static/fonts/typeface-pt-mono/package.json +++ b/static/node_modules/typeface-pt-mono/package.json @@ -22,7 +22,7 @@ "_resolved": "https://registry.npmjs.org/typeface-pt-mono/-/typeface-pt-mono-0.0.72.tgz", "_shasum": "1ce4a636d335c77bb01712ba136a99f764647a04", "_spec": "typeface-pt-mono", - "_where": "/Users/leafac/Projects/www.leafac.com", + "_where": "/Users/leafac/Code/www.kill-the-newsletter.com/static", "author": { "name": "Kyle Mathews", "email": "mathews.kyle@gmail.com" diff --git a/static/fonts/typeface-pt-sans/README.md b/static/node_modules/typeface-pt-sans/README.md similarity index 100% rename from static/fonts/typeface-pt-sans/README.md rename to static/node_modules/typeface-pt-sans/README.md diff --git a/static/fonts/typeface-pt-sans/files-hash.json b/static/node_modules/typeface-pt-sans/files-hash.json similarity index 100% rename from static/fonts/typeface-pt-sans/files-hash.json rename to static/node_modules/typeface-pt-sans/files-hash.json diff --git a/static/fonts/typeface-pt-sans/files/pt-sans-latin-400.woff b/static/node_modules/typeface-pt-sans/files/pt-sans-latin-400.woff similarity index 100% rename from static/fonts/typeface-pt-sans/files/pt-sans-latin-400.woff rename to static/node_modules/typeface-pt-sans/files/pt-sans-latin-400.woff diff --git a/static/fonts/typeface-pt-sans/files/pt-sans-latin-400.woff2 b/static/node_modules/typeface-pt-sans/files/pt-sans-latin-400.woff2 similarity index 100% rename from static/fonts/typeface-pt-sans/files/pt-sans-latin-400.woff2 rename to static/node_modules/typeface-pt-sans/files/pt-sans-latin-400.woff2 diff --git a/static/fonts/typeface-pt-sans/files/pt-sans-latin-400italic.woff b/static/node_modules/typeface-pt-sans/files/pt-sans-latin-400italic.woff similarity index 100% rename from static/fonts/typeface-pt-sans/files/pt-sans-latin-400italic.woff rename to static/node_modules/typeface-pt-sans/files/pt-sans-latin-400italic.woff diff --git a/static/fonts/typeface-pt-sans/files/pt-sans-latin-400italic.woff2 b/static/node_modules/typeface-pt-sans/files/pt-sans-latin-400italic.woff2 similarity index 100% rename from static/fonts/typeface-pt-sans/files/pt-sans-latin-400italic.woff2 rename to static/node_modules/typeface-pt-sans/files/pt-sans-latin-400italic.woff2 diff --git a/static/fonts/typeface-pt-sans/files/pt-sans-latin-700.woff b/static/node_modules/typeface-pt-sans/files/pt-sans-latin-700.woff similarity index 100% rename from static/fonts/typeface-pt-sans/files/pt-sans-latin-700.woff rename to static/node_modules/typeface-pt-sans/files/pt-sans-latin-700.woff diff --git a/static/fonts/typeface-pt-sans/files/pt-sans-latin-700.woff2 b/static/node_modules/typeface-pt-sans/files/pt-sans-latin-700.woff2 similarity index 100% rename from static/fonts/typeface-pt-sans/files/pt-sans-latin-700.woff2 rename to static/node_modules/typeface-pt-sans/files/pt-sans-latin-700.woff2 diff --git a/static/fonts/typeface-pt-sans/files/pt-sans-latin-700italic.woff b/static/node_modules/typeface-pt-sans/files/pt-sans-latin-700italic.woff similarity index 100% rename from static/fonts/typeface-pt-sans/files/pt-sans-latin-700italic.woff rename to static/node_modules/typeface-pt-sans/files/pt-sans-latin-700italic.woff diff --git a/static/fonts/typeface-pt-sans/files/pt-sans-latin-700italic.woff2 b/static/node_modules/typeface-pt-sans/files/pt-sans-latin-700italic.woff2 similarity index 100% rename from static/fonts/typeface-pt-sans/files/pt-sans-latin-700italic.woff2 rename to static/node_modules/typeface-pt-sans/files/pt-sans-latin-700italic.woff2 diff --git a/static/fonts/typeface-pt-sans/index.css b/static/node_modules/typeface-pt-sans/index.css similarity index 100% rename from static/fonts/typeface-pt-sans/index.css rename to static/node_modules/typeface-pt-sans/index.css diff --git a/static/fonts/typeface-pt-sans/package.json b/static/node_modules/typeface-pt-sans/package.json similarity index 94% rename from static/fonts/typeface-pt-sans/package.json rename to static/node_modules/typeface-pt-sans/package.json index a931c3b..bfb628c 100644 --- a/static/fonts/typeface-pt-sans/package.json +++ b/static/node_modules/typeface-pt-sans/package.json @@ -22,7 +22,7 @@ "_resolved": "https://registry.npmjs.org/typeface-pt-sans/-/typeface-pt-sans-0.0.72.tgz", "_shasum": "c47d198510b2ed1272ad6329cf1ae5f782ebf4cf", "_spec": "typeface-pt-sans", - "_where": "/Users/leafac/Projects/www.kill-the-newsletter.com/static", + "_where": "/Users/leafac/Code/www.kill-the-newsletter.com/static", "author": { "name": "Kyle Mathews", "email": "mathews.kyle@gmail.com" diff --git a/static/package-lock.json b/static/package-lock.json new file mode 100644 index 0000000..d4aff8c --- /dev/null +++ b/static/package-lock.json @@ -0,0 +1,16 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "typeface-pt-mono": { + "version": "0.0.72", + "resolved": "https://registry.npmjs.org/typeface-pt-mono/-/typeface-pt-mono-0.0.72.tgz", + "integrity": "sha512-7AMVSvB0oT2TDPyCJlVKSIxPjspI08Rlhg/SEUwQORSyalZgtSt2pDJEvVZuJbBIak70oB2ts6vL4iunYPUGKA==" + }, + "typeface-pt-sans": { + "version": "0.0.72", + "resolved": "https://registry.npmjs.org/typeface-pt-sans/-/typeface-pt-sans-0.0.72.tgz", + "integrity": "sha512-eDMv72dE+0dwjIDltzZAUusF+cDgOfZKazHZK08uKCOG/BEzY6oc/WqtQLN71j5/voTXFi5M4+nXNbZnCayDMQ==" + } + } +} diff --git a/static/package.json b/static/package.json new file mode 100644 index 0000000..1c11f58 --- /dev/null +++ b/static/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "typeface-pt-mono": "0.0.72", + "typeface-pt-sans": "0.0.72" + } +} diff --git a/static/styles.css b/static/styles.css index dfec166..862d3c3 100644 --- a/static/styles.css +++ b/static/styles.css @@ -1,7 +1,11 @@ +@import "node_modules/typeface-pt-sans/index.css"; +@import "node_modules/typeface-pt-mono/index.css"; + body { font-family: "PT Sans", sans-serif; line-height: 1.5; text-align: center; + padding: 0 1em; margin: 2em 0; } diff --git a/tsconfig.json b/tsconfig.json index 726ad9b..a077119 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,6 @@ "compilerOptions": { "target": "ES2019", "module": "commonjs", - "jsx": "react", "sourceMap": true, "rootDir": "src", "outDir": "lib",