diff --git a/package-lock.json b/package-lock.json index cc24117..2626f8f 100755 --- a/package-lock.json +++ b/package-lock.json @@ -15,23 +15,23 @@ "@tycrek/log": "^0.5.9", "@tycrek/papito": "^0.3.4", "any-shell-escape": "^0.1.1", - "aws-sdk": "^2.930.0", + "aws-sdk": "^2.1008.0", "check-node-version": "^4.1.0", "crypto-random-string": "3.3.1", "discord-webhook-node": "^1.1.8", "escape-html": "^1.0.3", "express": "^4.17.1", "express-busboy": "^8.0.0", - "express-rate-limit": "^5.2.6", - "ffmpeg-static": "^4.3.0", - "fs-extra": "^9.1.0", + "express-rate-limit": "^5.5.0", + "ffmpeg-static": "^4.4.0", + "fs-extra": "^10.0.0", "helmet": "^4.6.0", "jimp": "^0.16.1", - "luxon": "^1.26.0", - "marked": "^2.0.7", - "node-fetch": "^2.6.2", - "node-vibrant": "*", - "prompt": "^1.1.0", + "luxon": "^2.0.2", + "marked": "^3.0.7", + "node-fetch": "^2.6.5", + "node-vibrant": "^3.1.6", + "prompt": "^1.2.0", "pug": "^3.0.2", "sanitize-filename": "^1.6.3", "stream-to-array": "^2.3.0", @@ -688,6 +688,14 @@ "url": "https://patreon.com/tycrek" } }, + "node_modules/@tycrek/log/node_modules/luxon": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", + "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==", + "engines": { + "node": "*" + } + }, "node_modules/@tycrek/papito": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/@tycrek/papito/-/papito-0.3.4.tgz", @@ -704,19 +712,6 @@ "url": "https://patreon.com/tycrek" } }, - "node_modules/@tycrek/papito/node_modules/fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@types/body-parser": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz", @@ -809,6 +804,11 @@ "@types/node": "*" } }, + "node_modules/@types/lodash": { + "version": "4.14.175", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.175.tgz", + "integrity": "sha512-XmdEOrKQ8a1Y/yxQFOMbC47G/V2VDO1GvMRnl4O75M4GW/abC5tnfzadQYkqEveqRM1dEJGFFegfPNA2vvx2iw==" + }, "node_modules/@types/luxon": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-2.0.5.tgz", @@ -889,103 +889,6 @@ "@types/node": "*" } }, - "node_modules/@vibrant/color": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/color/-/color-3.2.1-alpha.1.tgz", - "integrity": "sha512-cvm+jAPwao2NerTr3d1JttYyLhp3eD/AQBeevxF7KT6HctToWZCwr2AeTr003/wKgbjzdOV1qySnbyOeu+R+Jw==" - }, - "node_modules/@vibrant/core": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/core/-/core-3.2.1-alpha.1.tgz", - "integrity": "sha512-X9Oa9WfPEQnZ6L+5dLRlh+IlsxJkYTw9b/g3stFKoNXbVRKCeXHmH48l7jIBBOg3VcXOGUdsYBqsTwPNkIveaA==", - "dependencies": { - "@vibrant/color": "^3.2.1-alpha.1", - "@vibrant/generator": "^3.2.1-alpha.1", - "@vibrant/image": "^3.2.1-alpha.1", - "@vibrant/quantizer": "^3.2.1-alpha.1", - "@vibrant/types": "^3.2.1-alpha.1", - "@vibrant/worker": "^3.2.1-alpha.1" - } - }, - "node_modules/@vibrant/generator": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/generator/-/generator-3.2.1-alpha.1.tgz", - "integrity": "sha512-luS5YvMhwMqG01YTj1dJ+cmkuIw1VCByOR6zIaCOwQqI/mcOs88JBWcA1r2TywJTOPlVpjfnDvAlyaKBKh4dMA==", - "dependencies": { - "@vibrant/color": "^3.2.1-alpha.1", - "@vibrant/types": "^3.2.1-alpha.1" - } - }, - "node_modules/@vibrant/generator-default": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/generator-default/-/generator-default-3.2.1-alpha.1.tgz", - "integrity": "sha512-BWnQhDaz92UhyHnpdAzKXHQecY+jvyMXtzjKYbveFxThm6+HVoLjwONlbck7oyOpFzV2OM7V11XuR85BxaHvjw==", - "dependencies": { - "@vibrant/color": "^3.2.1-alpha.1", - "@vibrant/generator": "^3.2.1-alpha.1" - } - }, - "node_modules/@vibrant/image": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/image/-/image-3.2.1-alpha.1.tgz", - "integrity": "sha512-4aF5k79QfyhZOqRovJpbnIjWfe3uuWhY8voqVdd4/qgu4o70/AwVlM+pYmCaJVzI45VWNWWHYA5QlYuKsXnBqQ==", - "dependencies": { - "@vibrant/color": "^3.2.1-alpha.1", - "@vibrant/types": "^3.2.1-alpha.1" - } - }, - "node_modules/@vibrant/image-browser": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/image-browser/-/image-browser-3.2.1-alpha.1.tgz", - "integrity": "sha512-6xWvQfB20sE6YtCWylgEAHuee3iD8h3aFIDbCS2yj7jIelKcYTrrp5jg2d2BhOOB6pC5JzF+QfpCrm0DmAIlgQ==", - "dependencies": { - "@vibrant/image": "^3.2.1-alpha.1" - } - }, - "node_modules/@vibrant/image-node": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/image-node/-/image-node-3.2.1-alpha.1.tgz", - "integrity": "sha512-/Io/Rpo4EkO6AhaXdcxUXkbOFhSFtjm0LSAM4c0AyGA5EbC8PyZqjk8b11bQAEMCaYaweFQfTdGD7oVbXe21CQ==", - "dependencies": { - "@jimp/custom": "^0.16.1", - "@jimp/plugin-resize": "^0.16.1", - "@jimp/types": "^0.16.1", - "@vibrant/image": "^3.2.1-alpha.1" - } - }, - "node_modules/@vibrant/quantizer": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/quantizer/-/quantizer-3.2.1-alpha.1.tgz", - "integrity": "sha512-iHnPx/+n4iLtYLm1GClSfyg2fFbMatFG0ipCyp9M6tXNIPAg+pSvUJSGBnVnH7Nl/bR8Gkkj1h0pJ4RsKcdIrQ==", - "dependencies": { - "@vibrant/color": "^3.2.1-alpha.1", - "@vibrant/image": "^3.2.1-alpha.1", - "@vibrant/types": "^3.2.1-alpha.1" - } - }, - "node_modules/@vibrant/quantizer-mmcq": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/quantizer-mmcq/-/quantizer-mmcq-3.2.1-alpha.1.tgz", - "integrity": "sha512-Wuk9PTZtxr8qsWTcgP6lcrrmrq36syVwxf+BUxdgQYntBcQ053SaN34lVGOJ0WPdK5vABoxbYljhceCgiILtZw==", - "dependencies": { - "@vibrant/color": "^3.2.1-alpha.1", - "@vibrant/image": "^3.2.1-alpha.1", - "@vibrant/quantizer": "^3.2.1-alpha.1" - } - }, - "node_modules/@vibrant/types": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/types/-/types-3.2.1-alpha.1.tgz", - "integrity": "sha512-ts9u7nsrENoYI5s0MmPOeY5kCLFKvQndKVDOPFCbTA0z493uhDp8mpiQhjFYTf3kPbS04z9zbHLE2luFC7x4KQ==" - }, - "node_modules/@vibrant/worker": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/worker/-/worker-3.2.1-alpha.1.tgz", - "integrity": "sha512-mtSlBdHkFNr4FOnMtqtHJxy9z5AsUcZzGlpiHzvWOoaoN9lNTDPwxOBd0q4VTYWuGPrIm6Fuq5m7aRbLv7KqiQ==", - "dependencies": { - "@vibrant/types": "^3.2.1-alpha.1" - } - }, "node_modules/accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -1161,18 +1064,10 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/aws-sdk": { - "version": "2.1007.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1007.0.tgz", - "integrity": "sha512-I/o2R7RTh6NGRilsBrJHg7r9WprU9EavozZ43qMQcppaLAeZrECBbGfpfRyhfrj7885+KS+WOu1SGn6bsSd2VQ==", + "version": "2.1008.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1008.0.tgz", + "integrity": "sha512-wBEon+ARCuMcwEPpOFZqRT3elBLfLtPqv8jMql3Hsr7Ua5toPlgKMmjf368iTzBNaY7TOZsjLAT9nAhvtSZ++g==", "hasInstallScript": true, "dependencies": { "buffer": "4.9.2", @@ -2210,17 +2105,16 @@ } }, "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", "dependencies": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/fs.realpath": { @@ -2734,6 +2628,11 @@ "node": ">=4" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", @@ -2747,9 +2646,9 @@ } }, "node_modules/luxon": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", - "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.0.2.tgz", + "integrity": "sha512-ZRioYLCgRHrtTORaZX1mx+jtxKtKuI5ZDvHNAmqpUzGqSrR+tL4FVLn/CUGMA3h0+AKD1MAxGI5GnCqR5txNqg==", "engines": { "node": "*" } @@ -2779,14 +2678,14 @@ "integrity": "sha1-douOecAJvytk/ugG4ip7HEGQyZA=" }, "node_modules/marked": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz", - "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/marked/-/marked-3.0.7.tgz", + "integrity": "sha512-ctKqbnLuNbsHbI26cfMyOlKgXGfl1orOv1AvWWDX7AkgfMOwCWvmuYc+mVLeWhQ9W6hdWVBynOs96VkcscKo0Q==", "bin": { "marked": "bin/marked" }, "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/media-typer": { @@ -2962,16 +2861,16 @@ } }, "node_modules/node-vibrant": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/node-vibrant/-/node-vibrant-3.2.1-alpha.1.tgz", - "integrity": "sha512-EQergCp7fvbvUCE0VMCBnvaAV0lGWSP8SXLmuWQIBzQK5M5pIwcd9fIOXuzFkJx/8hUiiiLvAzzGDS/bIy2ikA==", - "dependencies": { - "@types/node": "^10.12.18", - "@vibrant/core": "^3.2.1-alpha.1", - "@vibrant/generator-default": "^3.2.1-alpha.1", - "@vibrant/image-browser": "^3.2.1-alpha.1", - "@vibrant/image-node": "^3.2.1-alpha.1", - "@vibrant/quantizer-mmcq": "^3.2.1-alpha.1", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/node-vibrant/-/node-vibrant-3.1.6.tgz", + "integrity": "sha512-Wlc/hQmBMOu6xon12ZJHS2N3M+I6J8DhrD3Yo6m5175v8sFkVIN+UjhKVRcO+fqvre89ASTpmiFEP3nPO13SwA==", + "dependencies": { + "@jimp/custom": "^0.16.1", + "@jimp/plugin-resize": "^0.16.1", + "@jimp/types": "^0.16.1", + "@types/lodash": "^4.14.53", + "@types/node": "^10.11.7", + "lodash": "^4.17.20", "url": "^0.11.0" } }, @@ -5060,6 +4959,13 @@ "deepmerge": "^4.2.2", "luxon": "^1.27.0", "use-climate-change-reminder": "^0.0.7" + }, + "dependencies": { + "luxon": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", + "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==" + } } }, "@tycrek/papito": { @@ -5068,18 +4974,6 @@ "integrity": "sha512-P5sQAJQOeirCzpphU6tXqjiCUmJf+A8T/1iJkpWu/uLq30lHyKjIoOeCXnW92b3hdDDxO1ruanxX2muJZTPQdA==", "requires": { "fs-extra": "^10.0.0" - }, - "dependencies": { - "fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - } } }, "@types/body-parser": { @@ -5174,6 +5068,11 @@ "@types/node": "*" } }, + "@types/lodash": { + "version": "4.14.175", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.175.tgz", + "integrity": "sha512-XmdEOrKQ8a1Y/yxQFOMbC47G/V2VDO1GvMRnl4O75M4GW/abC5tnfzadQYkqEveqRM1dEJGFFegfPNA2vvx2iw==" + }, "@types/luxon": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-2.0.5.tgz", @@ -5254,103 +5153,6 @@ "@types/node": "*" } }, - "@vibrant/color": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/color/-/color-3.2.1-alpha.1.tgz", - "integrity": "sha512-cvm+jAPwao2NerTr3d1JttYyLhp3eD/AQBeevxF7KT6HctToWZCwr2AeTr003/wKgbjzdOV1qySnbyOeu+R+Jw==" - }, - "@vibrant/core": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/core/-/core-3.2.1-alpha.1.tgz", - "integrity": "sha512-X9Oa9WfPEQnZ6L+5dLRlh+IlsxJkYTw9b/g3stFKoNXbVRKCeXHmH48l7jIBBOg3VcXOGUdsYBqsTwPNkIveaA==", - "requires": { - "@vibrant/color": "^3.2.1-alpha.1", - "@vibrant/generator": "^3.2.1-alpha.1", - "@vibrant/image": "^3.2.1-alpha.1", - "@vibrant/quantizer": "^3.2.1-alpha.1", - "@vibrant/types": "^3.2.1-alpha.1", - "@vibrant/worker": "^3.2.1-alpha.1" - } - }, - "@vibrant/generator": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/generator/-/generator-3.2.1-alpha.1.tgz", - "integrity": "sha512-luS5YvMhwMqG01YTj1dJ+cmkuIw1VCByOR6zIaCOwQqI/mcOs88JBWcA1r2TywJTOPlVpjfnDvAlyaKBKh4dMA==", - "requires": { - "@vibrant/color": "^3.2.1-alpha.1", - "@vibrant/types": "^3.2.1-alpha.1" - } - }, - "@vibrant/generator-default": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/generator-default/-/generator-default-3.2.1-alpha.1.tgz", - "integrity": "sha512-BWnQhDaz92UhyHnpdAzKXHQecY+jvyMXtzjKYbveFxThm6+HVoLjwONlbck7oyOpFzV2OM7V11XuR85BxaHvjw==", - "requires": { - "@vibrant/color": "^3.2.1-alpha.1", - "@vibrant/generator": "^3.2.1-alpha.1" - } - }, - "@vibrant/image": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/image/-/image-3.2.1-alpha.1.tgz", - "integrity": "sha512-4aF5k79QfyhZOqRovJpbnIjWfe3uuWhY8voqVdd4/qgu4o70/AwVlM+pYmCaJVzI45VWNWWHYA5QlYuKsXnBqQ==", - "requires": { - "@vibrant/color": "^3.2.1-alpha.1", - "@vibrant/types": "^3.2.1-alpha.1" - } - }, - "@vibrant/image-browser": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/image-browser/-/image-browser-3.2.1-alpha.1.tgz", - "integrity": "sha512-6xWvQfB20sE6YtCWylgEAHuee3iD8h3aFIDbCS2yj7jIelKcYTrrp5jg2d2BhOOB6pC5JzF+QfpCrm0DmAIlgQ==", - "requires": { - "@vibrant/image": "^3.2.1-alpha.1" - } - }, - "@vibrant/image-node": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/image-node/-/image-node-3.2.1-alpha.1.tgz", - "integrity": "sha512-/Io/Rpo4EkO6AhaXdcxUXkbOFhSFtjm0LSAM4c0AyGA5EbC8PyZqjk8b11bQAEMCaYaweFQfTdGD7oVbXe21CQ==", - "requires": { - "@jimp/custom": "^0.16.1", - "@jimp/plugin-resize": "^0.16.1", - "@jimp/types": "^0.16.1", - "@vibrant/image": "^3.2.1-alpha.1" - } - }, - "@vibrant/quantizer": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/quantizer/-/quantizer-3.2.1-alpha.1.tgz", - "integrity": "sha512-iHnPx/+n4iLtYLm1GClSfyg2fFbMatFG0ipCyp9M6tXNIPAg+pSvUJSGBnVnH7Nl/bR8Gkkj1h0pJ4RsKcdIrQ==", - "requires": { - "@vibrant/color": "^3.2.1-alpha.1", - "@vibrant/image": "^3.2.1-alpha.1", - "@vibrant/types": "^3.2.1-alpha.1" - } - }, - "@vibrant/quantizer-mmcq": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/quantizer-mmcq/-/quantizer-mmcq-3.2.1-alpha.1.tgz", - "integrity": "sha512-Wuk9PTZtxr8qsWTcgP6lcrrmrq36syVwxf+BUxdgQYntBcQ053SaN34lVGOJ0WPdK5vABoxbYljhceCgiILtZw==", - "requires": { - "@vibrant/color": "^3.2.1-alpha.1", - "@vibrant/image": "^3.2.1-alpha.1", - "@vibrant/quantizer": "^3.2.1-alpha.1" - } - }, - "@vibrant/types": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/types/-/types-3.2.1-alpha.1.tgz", - "integrity": "sha512-ts9u7nsrENoYI5s0MmPOeY5kCLFKvQndKVDOPFCbTA0z493uhDp8mpiQhjFYTf3kPbS04z9zbHLE2luFC7x4KQ==" - }, - "@vibrant/worker": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/@vibrant/worker/-/worker-3.2.1-alpha.1.tgz", - "integrity": "sha512-mtSlBdHkFNr4FOnMtqtHJxy9z5AsUcZzGlpiHzvWOoaoN9lNTDPwxOBd0q4VTYWuGPrIm6Fuq5m7aRbLv7KqiQ==", - "requires": { - "@vibrant/types": "^3.2.1-alpha.1" - } - }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -5483,15 +5285,10 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" - }, "aws-sdk": { - "version": "2.1007.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1007.0.tgz", - "integrity": "sha512-I/o2R7RTh6NGRilsBrJHg7r9WprU9EavozZ43qMQcppaLAeZrECBbGfpfRyhfrj7885+KS+WOu1SGn6bsSd2VQ==", + "version": "2.1008.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1008.0.tgz", + "integrity": "sha512-wBEon+ARCuMcwEPpOFZqRT3elBLfLtPqv8jMql3Hsr7Ua5toPlgKMmjf368iTzBNaY7TOZsjLAT9nAhvtSZ++g==", "requires": { "buffer": "4.9.2", "events": "1.1.1", @@ -6313,11 +6110,10 @@ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", "requires": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" @@ -6723,6 +6519,11 @@ "path-exists": "^3.0.0" } }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", @@ -6733,9 +6534,9 @@ } }, "luxon": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", - "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.0.2.tgz", + "integrity": "sha512-ZRioYLCgRHrtTORaZX1mx+jtxKtKuI5ZDvHNAmqpUzGqSrR+tL4FVLn/CUGMA3h0+AKD1MAxGI5GnCqR5txNqg==" }, "map-age-cleaner": { "version": "0.1.3", @@ -6756,9 +6557,9 @@ "integrity": "sha1-douOecAJvytk/ugG4ip7HEGQyZA=" }, "marked": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz", - "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/marked/-/marked-3.0.7.tgz", + "integrity": "sha512-ctKqbnLuNbsHbI26cfMyOlKgXGfl1orOv1AvWWDX7AkgfMOwCWvmuYc+mVLeWhQ9W6hdWVBynOs96VkcscKo0Q==" }, "media-typer": { "version": "0.3.0", @@ -6891,16 +6692,16 @@ } }, "node-vibrant": { - "version": "3.2.1-alpha.1", - "resolved": "https://registry.npmjs.org/node-vibrant/-/node-vibrant-3.2.1-alpha.1.tgz", - "integrity": "sha512-EQergCp7fvbvUCE0VMCBnvaAV0lGWSP8SXLmuWQIBzQK5M5pIwcd9fIOXuzFkJx/8hUiiiLvAzzGDS/bIy2ikA==", - "requires": { - "@types/node": "^10.12.18", - "@vibrant/core": "^3.2.1-alpha.1", - "@vibrant/generator-default": "^3.2.1-alpha.1", - "@vibrant/image-browser": "^3.2.1-alpha.1", - "@vibrant/image-node": "^3.2.1-alpha.1", - "@vibrant/quantizer-mmcq": "^3.2.1-alpha.1", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/node-vibrant/-/node-vibrant-3.1.6.tgz", + "integrity": "sha512-Wlc/hQmBMOu6xon12ZJHS2N3M+I6J8DhrD3Yo6m5175v8sFkVIN+UjhKVRcO+fqvre89ASTpmiFEP3nPO13SwA==", + "requires": { + "@jimp/custom": "^0.16.1", + "@jimp/plugin-resize": "^0.16.1", + "@jimp/types": "^0.16.1", + "@types/lodash": "^4.14.53", + "@types/node": "^10.11.7", + "lodash": "^4.17.20", "url": "^0.11.0" }, "dependencies": { diff --git a/package.json b/package.json index 61e630a..c4c0ba4 100755 --- a/package.json +++ b/package.json @@ -43,23 +43,23 @@ "@tycrek/log": "^0.5.9", "@tycrek/papito": "^0.3.4", "any-shell-escape": "^0.1.1", - "aws-sdk": "^2.930.0", + "aws-sdk": "^2.1008.0", "check-node-version": "^4.1.0", "crypto-random-string": "3.3.1", "discord-webhook-node": "^1.1.8", "escape-html": "^1.0.3", "express": "^4.17.1", "express-busboy": "^8.0.0", - "express-rate-limit": "^5.2.6", - "ffmpeg-static": "^4.3.0", - "fs-extra": "^9.1.0", + "express-rate-limit": "^5.5.0", + "ffmpeg-static": "^4.4.0", + "fs-extra": "^10.0.0", "helmet": "^4.6.0", "jimp": "^0.16.1", - "luxon": "^1.26.0", - "marked": "^2.0.7", - "node-fetch": "^2.6.2", - "node-vibrant": "*", - "prompt": "^1.1.0", + "luxon": "^2.0.2", + "marked": "^3.0.7", + "node-fetch": "^2.6.5", + "node-vibrant": "^3.1.6", + "prompt": "^1.2.0", "pug": "^3.0.2", "sanitize-filename": "^1.6.3", "stream-to-array": "^2.3.0", diff --git a/src/ass.ts b/src/ass.ts index 79a1a8e..5ec86c3 100644 --- a/src/ass.ts +++ b/src/ass.ts @@ -80,7 +80,7 @@ app.get('/', (req, res, next) => ASS_INDEX_ENABLED // skipcq: JS-0229 .catch(next)); // Set up custom frontend -const ASS_FRONTEND = fs.existsSync(path(`./${frontendName}/package.json`)) ? (require('submodule'), require(`../${frontendName}`)) : { enabled: false }; // todo: update with src/ +const ASS_FRONTEND = fs.existsSync(path(`./${frontendName}/package.json`)) ? (require('submodule'), require(`../${frontendName}`)) : { enabled: false }; ASS_FRONTEND.enabled && app.use(ASS_FRONTEND.endpoint, ASS_FRONTEND.router); // skipcq: JS-0093 // Upload router (has to come after custom frontends as express-busboy interferes with all POST calls) diff --git a/src/definitions.d.ts b/src/definitions.d.ts index 6f716b7..9781959 100644 --- a/src/definitions.d.ts +++ b/src/definitions.d.ts @@ -6,7 +6,15 @@ export interface User { } export interface FileData { - // Data from Multer file object + // Data from request file object + uuid?: string + field?: string + file?: string + filename?: string + truncated?: boolean + done?: boolean + + // Old Multer data being carried over to non-Multer files path: string size: number mimetype: string @@ -52,6 +60,7 @@ export interface AssRequest extends Request { ass?: { resourceId: string } token?: string file?: FileData + files?: { [key: string]: any } } export interface AssResponse extends Response { diff --git a/src/hash.ts b/src/hash.ts index 3b7113d..f4cfb53 100644 --- a/src/hash.ts +++ b/src/hash.ts @@ -9,7 +9,7 @@ import { log } from './utils'; * @param {*} file The file to hash * @returns The SHA1 hash */ -export default (file: FileData) => +export default (file: FileData): Promise => new Promise((resolve, reject) => toArray((fs.createReadStream(file.path))) .then((parts: any[]) => Buffer.concat(parts.map((part: any) => (Buffer.isBuffer(part) ? part : Buffer.from(part))))) diff --git a/src/storage.js b/src/storage.js deleted file mode 100644 index 08fbc79..0000000 --- a/src/storage.js +++ /dev/null @@ -1,151 +0,0 @@ -// https://docs.digitalocean.com/products/spaces/resources/s3-sdk-examples/ -// https://www.digitalocean.com/community/tutorials/how-to-upload-a-file-to-object-storage-with-node-js - -const fs = require('fs-extra'); -const aws = require('aws-sdk'); -const Thumbnail = require('./thumbnails').default; -const Vibrant = require('./vibrant').default; -const Hash = require('./hash').default; -const { generateId, log } = require('./utils'); -const { s3enabled, s3endpoint, s3bucket, s3usePathStyle, s3accessKey, s3secretKey, diskFilePath, saveAsOriginal, saveWithDate, mediaStrict, maxUploadSize } = require('../config.json'); -const { CODE_UNSUPPORTED_MEDIA_TYPE } = require('../MagicNumbers.json'); - -const ID_GEN_LENGTH = 32; -const ALLOWED_MIMETYPES = /(image)|(video)|(audio)\//; - -const s3 = new aws.S3({ - s3ForcePathStyle: s3usePathStyle, - endpoint: new aws.Endpoint(s3endpoint), - credentials: new aws.Credentials({ accessKeyId: s3accessKey, secretAccessKey: s3secretKey }) -}); - -function getDatedDirname() { - if (!saveWithDate) return diskFilePath; - - // Get current month and year - const [month, , year] = new Date().toLocaleDateString('en-US').split('/'); - - // Add 0 before single digit months (6 turns into 06) - return `${diskFilePath}${diskFilePath.endsWith('/') ? '' : '/'}${year}-${`0${month}`.slice(-2)}`; // skipcq: JS-0074 -} - -function getLocalFilename(req) { - return `${getDatedDirname()}/${saveAsOriginal ? req.file.originalname : req.file.sha1}`; -} - -function processUploaded(req, res, next) { // skipcq: JS-0045 - // Fix file object - req.file = req.files.file; - - // Other fixes - req.file.ext = '.'.concat(req.file.filename.split('.').pop()); - req.file.originalname = req.file.filename; - req.file.path = req.file.file; - req.file.randomId = generateId('random', ID_GEN_LENGTH, null, null); - req.file.deleteId = generateId('random', ID_GEN_LENGTH, null, null); - - // Set up types - req.file.is = { - image: false, - video: false, - audio: false, - other: false - }; - - // Specify correct type - const isType = req.file.mimetype.includes('image') ? 'image' : req.file.mimetype.includes('video') ? 'video' : req.file.mimetype.includes('audio') ? 'audio' : 'other'; - req.file.is[isType] = true; - - // Block the resource if the mimetype is not an image or video - if (mediaStrict && !ALLOWED_MIMETYPES.test(req.file.mimetype)) - return log - .warn('Upload blocked', req.file.originalname, req.file.mimetype) - .warn('Strict media mode', 'only images, videos, & audio are file permitted') - .callback(() => - fs.remove(req.file.path) - .then(() => log - .debug('Temp file', 'deleted') - .callback(() => res.sendStatus(CODE_UNSUPPORTED_MEDIA_TYPE))) - .catch((err) => log - .error('Temp file could not be deleted', err) - .callback(next, err))); - - // Remove unwanted fields - delete req.file.uuid; - delete req.file.field; - delete req.file.file; - delete req.file.filename; - delete req.file.truncated; - delete req.file.done; - - // Operations - Promise.all([Thumbnail(req.file), Vibrant(req.file), Hash(req.file), fs.stat(req.file.path)]) - // skipcq: JS-0086 - .then(([thumbnail, vibrant, sha1, stat]) => ( - req.file.thumbnail = thumbnail, // skipcq: JS-0090 - req.file.vibrant = vibrant, // skipcq: JS-0090 - req.file.sha1 = sha1, // skipcq: JS-0090 - req.file.size = stat.size // skipcq: JS-0090 - )) - - // Check if file size is too big - .then(() => { if (req.file.size / Math.pow(1024, 2) > maxUploadSize) throw new Error('LIMIT_FILE_SIZE'); }) - - // Save file - .then(() => log.debug('Saving file', req.file.originalname, s3enabled ? 'in S3' : 'on disk')) - .then(() => - // skipcq: JS-0229 - new Promise((resolve, reject) => s3enabled - - // Upload to Amazon S3 - ? s3.putObject({ - Bucket: s3bucket, - Key: req.file.randomId.concat(req.file.ext), - ACL: 'public-read', - ContentType: req.file.mimetype, - Body: fs.createReadStream(req.file.path) - }).promise().then(resolve).catch(reject) - - // Save to local storage - : fs.ensureDir(getDatedDirname()) - .then(() => fs.copy(req.file.path, getLocalFilename(req), { preserveTimestamps: true })) - .then(resolve) - .catch(reject) - )) - .then(() => log.debug('File saved', req.file.originalname, s3enabled ? 'in S3' : 'on disk')) - .catch(next) - - // Delete the file - .then(() => fs.remove(req.file.path)) - .then(() => log.debug('Temp file', 'deleted')) - - // Fix the file path - .then(() => !s3enabled && (req.file.path = getLocalFilename(req))) // skipcq: JS-0090 - .then(() => next()) - .catch(next); -} - -function deleteS3(file) { - return new Promise((resolve, reject) => s3 - .deleteObject({ Bucket: s3bucket, Key: file.randomId.concat(file.ext) }) - .promise() - .then(resolve) - .catch(reject)); -} - -function listAllKeys(resolve, reject, token) { - let allKeys = []; - s3.listObjectsV2({ Bucket: s3bucket, ContinuationToken: token }).promise() - .then((data) => (allKeys = allKeys.concat(data.Contents), data.IsTruncated ? listAllKeys(resolve, reject, data.NextContinuationToken) : resolve(allKeys.length))) // skipcq: JS-0086, JS-0090 - .catch(reject); -} - -function bucketSize() { - return new Promise((resolve, reject) => (s3enabled ? listAllKeys(resolve, reject) : resolve(0))); -} - -module.exports = { - processUploaded, - deleteS3, - bucketSize -}; diff --git a/src/storage.ts b/src/storage.ts new file mode 100644 index 0000000..52387be --- /dev/null +++ b/src/storage.ts @@ -0,0 +1,147 @@ +// https://docs.digitalocean.com/products/spaces/resources/s3-sdk-examples/ +// https://www.digitalocean.com/community/tutorials/how-to-upload-a-file-to-object-storage-with-node-js +import { AssRequest, AssResponse, FileData } from './definitions'; + +import fs, { Stats } from 'fs-extra'; +import aws from 'aws-sdk'; +import Thumbnail from './thumbnails'; +import Vibrant from './vibrant'; +import Hash from './hash'; +import { generateId, log } from './utils'; +const { s3enabled, s3endpoint, s3bucket, s3usePathStyle, s3accessKey, s3secretKey, diskFilePath, saveAsOriginal, saveWithDate, mediaStrict, maxUploadSize } = require('../config.json'); +const { CODE_UNSUPPORTED_MEDIA_TYPE } = require('../MagicNumbers.json'); + +const ID_GEN_LENGTH = 32; +const ALLOWED_MIMETYPES = /(image)|(video)|(audio)\//; + +const s3 = new aws.S3({ + s3ForcePathStyle: s3usePathStyle, + endpoint: new aws.Endpoint(s3endpoint), + credentials: new aws.Credentials({ accessKeyId: s3accessKey, secretAccessKey: s3secretKey }) +}); + +function getDatedDirname() { + if (!saveWithDate) return diskFilePath; + + // Get current month and year + const [month, , year] = new Date().toLocaleDateString('en-US').split('/'); + + // Add 0 before single digit months (6 turns into 06) + return `${diskFilePath}${diskFilePath.endsWith('/') ? '' : '/'}${year}-${`0${month}`.slice(-2)}`; // skipcq: JS-0074 +} + +function getLocalFilename(req: AssRequest) { + return `${getDatedDirname()}/${saveAsOriginal ? req.file!.originalname : req.file!.sha1}`; +} + +export function processUploaded(req: AssRequest, res: AssResponse, next: Function) { // skipcq: JS-0045 + // Fix file object + req.file = req.files!.file; + + // Other fixes + req.file!.ext = '.'.concat((req.file!.filename ?? '').split('.').pop() ?? ''); + req.file!.originalname = req.file!.filename ?? ''; + req.file!.path = req.file!.file ?? ''; + req.file!.randomId = generateId('random', ID_GEN_LENGTH, 0, ''); + req.file!.deleteId = generateId('random', ID_GEN_LENGTH, 0, ''); + + // Set up types + req.file!.is = { + image: false, + video: false, + audio: false, + other: false + }; + + // Specify correct type + const isType = req.file!.mimetype.includes('image') ? 'image' : req.file!.mimetype.includes('video') ? 'video' : req.file!.mimetype.includes('audio') ? 'audio' : 'other'; + req.file!.is[isType] = true; + + // Block the resource if the mimetype is not an image or video + if (mediaStrict && !ALLOWED_MIMETYPES.test(req.file!.mimetype)) + return log + .warn('Upload blocked', req.file!.originalname, req.file!.mimetype) + .warn('Strict media mode', 'only images, videos, & audio are file permitted') + .callback(() => + fs.remove(req.file!.path) + .then(() => log + .debug('Temp file', 'deleted') + .callback(() => res.sendStatus(CODE_UNSUPPORTED_MEDIA_TYPE))) + .catch((err) => log + .error('Temp file could not be deleted', err) + .callback(next, err))); + + // Remove unwanted fields + delete req.file!.uuid; + delete req.file!.field; + delete req.file!.file; + delete req.file!.filename; + delete req.file!.truncated; + delete req.file!.done; + + // Operations + // @ts-ignore + Promise.all([Thumbnail(req.file), Vibrant(req.file), Hash(req.file), fs.stat(req.file!.path)]) + // skipcq: JS-0086 + .then(([thumbnail, vibrant, sha1, stat]: [string, string, string, Stats]) => ( + req.file!.thumbnail = thumbnail, // skipcq: JS-0090 + req.file!.vibrant = vibrant, // skipcq: JS-0090 + req.file!.sha1 = sha1, // skipcq: JS-0090 + req.file!.size = stat.size // skipcq: JS-0090 + )) + + // Check if file size is too big + .then(() => { if (req.file!.size / Math.pow(1024, 2) > maxUploadSize) throw new Error('LIMIT_FILE_SIZE'); }) + + // Save file + .then(() => log.debug('Saving file', req.file!.originalname, s3enabled ? 'in S3' : 'on disk')) + .then(() => + // skipcq: JS-0229 + new Promise((resolve, reject) => s3enabled + + // Upload to Amazon S3 + ? s3.putObject({ + Bucket: s3bucket, + Key: req.file!.randomId.concat(req.file!.ext), + ACL: 'public-read', + ContentType: req.file!.mimetype, + Body: fs.createReadStream(req.file!.path) + }).promise().then(resolve).catch(reject) + + // Save to local storage + : fs.ensureDir(getDatedDirname()) + .then(() => fs.copy(req.file!.path, getLocalFilename(req), { preserveTimestamps: true })) + .then(resolve) + .catch(reject) + )) + .then(() => log.debug('File saved', req.file!.originalname, s3enabled ? 'in S3' : 'on disk')) + .catch((err) => next(err)) + + // Delete the file + .then(() => fs.remove(req.file!.path)) + .then(() => log.debug('Temp file', 'deleted')) + + // Fix the file path + .then(() => !s3enabled && (req.file!.path = getLocalFilename(req))) // skipcq: JS-0090 + .then(() => next()) + .catch((err) => next(err)); +} + +export function deleteS3(file: FileData) { + return new Promise((resolve, reject) => s3 + .deleteObject({ Bucket: s3bucket, Key: file.randomId.concat(file.ext) }) + .promise() + .then(resolve) + .catch(reject)); +} + +function listAllKeys(resolve: Function, reject: Function, token?: string) { + let allKeys: string[] = []; + s3.listObjectsV2({ Bucket: s3bucket, ContinuationToken: token }).promise() + .then((data: { [key: string]: any }) => (allKeys = allKeys.concat(data.Contents), data.IsTruncated ? listAllKeys(resolve, reject, data.NextContinuationToken) : resolve(allKeys.length))) // skipcq: JS-0086, JS-0090 + .catch((err) => reject(err)); +} + +export function bucketSize() { + return new Promise((resolve, reject) => (s3enabled ? listAllKeys(resolve, reject) : resolve(0))); +} diff --git a/src/thumbnails.ts b/src/thumbnails.ts index 851a43b..33b8748 100644 --- a/src/thumbnails.ts +++ b/src/thumbnails.ts @@ -82,7 +82,7 @@ function getImageThumbnail(file: FileData) { * @param {*} file The file to generate a thumbnail for * @returns The thumbnail filename (NOT the path) */ -export default (file: FileData) => +export default (file: FileData): Promise => new Promise((resolve, reject) => (file.is.video ? getVideoThumbnail : file.is.image ? getImageThumbnail : () => Promise.resolve())(file) .then(() => resolve((file.is.video || file.is.image) ? getNewName(file.randomId) : file.is.audio ? 'views/ass-audio-icon.png' : 'views/ass-file-icon.png')) diff --git a/src/utils.ts b/src/utils.ts index e537960..cfe330a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -78,7 +78,7 @@ export function generateId(mode: string, length: number, gfyLength: number, orig } // Set up pathing -export const path = (...paths: string[]) => Path.join(process.cwd(), ...paths); // '..' was added to make it easier to run files after moving the project to src/ +export const path = (...paths: string[]) => Path.join(process.cwd(), ...paths); const idModes = { zws: 'zws', // Zero-width spaces (see: https://zws.im/) @@ -121,7 +121,7 @@ module.exports = { arrayEquals, downloadTempS3: (file: FileData) => new Promise((resolve: Function, reject) => fetch(getS3url(file.randomId, file.ext)) - .then((f2) => f2.body.pipe(fs.createWriteStream(Path.join(__dirname, diskFilePath, sanitize(file.originalname))).on('close', () => resolve()))) + .then((f2) => f2.body!.pipe(fs.createWriteStream(Path.join(__dirname, diskFilePath, sanitize(file.originalname))).on('close', () => resolve()))) .catch(reject)), } diff --git a/src/vibrant.ts b/src/vibrant.ts index 6a75454..dd02b77 100644 --- a/src/vibrant.ts +++ b/src/vibrant.ts @@ -26,4 +26,4 @@ function getVibrant(file: FileData, resolve: Function, reject: Function) { * @param {*} file The file to get a colour from * @returns The Vibrant colour as a Hex value (or random Hex value for videos) */ -export default (file: FileData) => new Promise((resolve, reject) => !file.is.image ? resolve(randomHexColour()) : getVibrant(file, resolve, reject)); // skipcq: JS-0229 +export default (file: FileData): Promise => new Promise((resolve, reject) => !file.is.image ? resolve(randomHexColour()) : getVibrant(file, resolve, reject)); // skipcq: JS-0229