diff --git a/package-lock.json b/package-lock.json index bd9b287..23ec930 100644 --- a/package-lock.json +++ b/package-lock.json @@ -121,6 +121,7 @@ "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", @@ -1216,6 +1217,7 @@ "integrity": "sha512-DNUAHNSiUI/j9hmbatD6WN/EBIyeq4AO0frl5ETtt51VN1SvE4t4v83ZA/V6ikxEf3hxLju4tQ5Pc3zmZkN/3A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.7.2", "@jimp/core": "^0.16.1" @@ -1258,6 +1260,7 @@ "integrity": "sha512-fKFNARm32RoLSokJ8WZXHHH2CGzz6ire2n1Jh6u+XQLhk9TweT1DcLHIXwQMh8oR12KgjbgsMGvrMVlVknmOAg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.7.2", "@jimp/utils": "^0.16.1" @@ -1272,6 +1275,7 @@ "integrity": "sha512-1WhuLGGj9MypFKRcPvmW45ht7nXkOKu+lg3n2VBzIB7r4kKNVchuI59bXaCYQumOLEqVK7JdB4glaDAbCQCLyw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.7.2", "@jimp/utils": "^0.16.1" @@ -1300,6 +1304,7 @@ "integrity": "sha512-9yQttBAO5SEFj7S6nJK54f+1BnuBG4c28q+iyzm1JjtnehjqMg6Ljw4gCSDCvoCQ3jBSYHN66pmwTV74SU1B7A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.7.2", "@jimp/utils": "^0.16.1", @@ -1349,6 +1354,7 @@ "integrity": "sha512-UQdva9oQzCVadkyo3T5Tv2CUZbf0klm2cD4cWMlASuTOYgaGaFHhT9st+kmfvXjKL8q3STkBu/zUPV6PbuV3ew==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.7.2", "@jimp/utils": "^0.16.1" @@ -1492,6 +1498,7 @@ "integrity": "sha512-u4JBLdRI7dargC04p2Ha24kofQBk3vhaf0q8FwSYgnCRwxfvh2RxvhJZk9H7Q91JZp6wgjz/SjvEAYjGCEgAwQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.7.2", "@jimp/utils": "^0.16.1" @@ -1506,6 +1513,7 @@ "integrity": "sha512-ZUU415gDQ0VjYutmVgAYYxC9Og9ixu2jAGMCU54mSMfuIlmohYfwARQmI7h4QB84M76c9hVLdONWjuo+rip/zg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.7.2", "@jimp/utils": "^0.16.1" @@ -1523,6 +1531,7 @@ "integrity": "sha512-jM2QlgThIDIc4rcyughD5O7sOYezxdafg/2Xtd1csfK3z6fba3asxDwthqPZAgitrLgiKBDp6XfzC07Y/CefUw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.7.2", "@jimp/utils": "^0.16.1" @@ -1839,8 +1848,7 @@ "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@sinonjs/commons": { "version": "1.8.3", @@ -2006,6 +2014,7 @@ "integrity": "sha512-fUy7YRpT+rHXto1YlL+J9rs0uLGyiqVt3ZOTQR+4ROc47yNl8WLdVLgUloBRhOxP1PZvguHl44T3H0wAWxahYQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "jest-matcher-utils": "^27.0.0", "pretty-format": "^27.0.0" @@ -2023,8 +2032,7 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/linkify-it": { "version": "5.0.0", @@ -2043,6 +2051,7 @@ "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", "license": "MIT", + "peer": true, "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" @@ -2058,7 +2067,8 @@ "version": "16.11.38", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.38.tgz", "integrity": "sha512-hjO/0K140An3GWDw2HJfq7gko3wWeznbjXgg+rzPdVzhe198hp4x2i1dgveAOEiFKd8sOilAxzoSJiVv5P/CUg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/prettier": { "version": "2.6.3", @@ -2167,6 +2177,7 @@ "integrity": "sha512-I5zVZFY+cw4IMZUeNCU7Sh2PO5O57F7Lr0uyhgCJmhN/BuTlnc55KxPonR4+EM3GBdfiCyGZye6DgMjtubQkmA==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "6.7.4", "@typescript-eslint/types": "6.7.4", @@ -2375,6 +2386,7 @@ "version": "8.13.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2597,7 +2609,6 @@ "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" @@ -2615,7 +2626,6 @@ "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", @@ -2649,7 +2659,6 @@ "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", @@ -2672,7 +2681,6 @@ "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", @@ -2692,7 +2700,6 @@ "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", @@ -2712,7 +2719,6 @@ "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", @@ -2735,7 +2741,6 @@ "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" } @@ -2762,7 +2767,6 @@ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "possible-typed-array-names": "^1.0.0" }, @@ -2988,6 +2992,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001669", "electron-to-chromium": "^1.5.41", @@ -3553,7 +3558,6 @@ "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", @@ -3572,7 +3576,6 @@ "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", @@ -3591,7 +3594,6 @@ "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -3972,7 +3974,6 @@ "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", @@ -4075,7 +4076,6 @@ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", @@ -4092,7 +4092,6 @@ "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "hasown": "^2.0.2" }, @@ -4106,7 +4105,6 @@ "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", @@ -4224,6 +4222,7 @@ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -4310,6 +4309,7 @@ "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -4323,7 +4323,6 @@ "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", @@ -4336,7 +4335,6 @@ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -4347,7 +4345,6 @@ "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "debug": "^3.2.7" }, @@ -4366,7 +4363,6 @@ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -4377,7 +4373,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -4412,7 +4407,6 @@ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -4423,7 +4417,6 @@ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "esutils": "^2.0.2" }, @@ -4437,7 +4430,6 @@ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", - "peer": true, "bin": { "semver": "bin/semver.js" } @@ -4888,7 +4880,6 @@ "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "is-callable": "^1.2.7" }, @@ -4956,7 +4947,6 @@ "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -4978,7 +4968,6 @@ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5120,7 +5109,6 @@ "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", @@ -5217,7 +5205,6 @@ "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" @@ -5281,7 +5268,6 @@ "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -5317,7 +5303,6 @@ "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "dunder-proto": "^1.0.0" }, @@ -5347,7 +5332,6 @@ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "has-symbols": "^1.0.3" }, @@ -5590,7 +5574,6 @@ "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", @@ -5606,7 +5589,6 @@ "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -5632,7 +5614,6 @@ "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", @@ -5653,7 +5634,6 @@ "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "has-bigints": "^1.0.2" }, @@ -5670,7 +5650,6 @@ "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" @@ -5688,7 +5667,6 @@ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -5718,7 +5696,6 @@ "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", @@ -5737,7 +5714,6 @@ "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" @@ -5765,7 +5741,6 @@ "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3" }, @@ -5812,7 +5787,6 @@ "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", @@ -5845,7 +5819,6 @@ "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -5859,7 +5832,6 @@ "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -5883,7 +5855,6 @@ "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" @@ -5917,7 +5888,6 @@ "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", @@ -5937,7 +5907,6 @@ "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -5951,7 +5920,6 @@ "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3" }, @@ -5981,7 +5949,6 @@ "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" @@ -5999,7 +5966,6 @@ "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", @@ -6018,7 +5984,6 @@ "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "which-typed-array": "^1.1.16" }, @@ -6042,7 +6007,6 @@ "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -6056,7 +6020,6 @@ "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3" }, @@ -6073,7 +6036,6 @@ "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" @@ -6090,8 +6052,7 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", @@ -6187,6 +6148,7 @@ "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "^27.5.1", "import-local": "^3.0.2", @@ -7725,7 +7687,6 @@ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -7786,7 +7747,6 @@ "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -7806,7 +7766,6 @@ "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -7822,7 +7781,6 @@ "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -7926,7 +7884,6 @@ "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", @@ -8241,7 +8198,6 @@ "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" } @@ -8289,6 +8245,7 @@ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -8715,7 +8672,6 @@ "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", @@ -8746,7 +8702,6 @@ "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", @@ -8899,7 +8854,6 @@ "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", @@ -8927,7 +8881,6 @@ "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" @@ -8945,7 +8898,6 @@ "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -9036,7 +8988,6 @@ "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -9053,7 +9004,6 @@ "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", @@ -9128,7 +9078,6 @@ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", @@ -9149,7 +9098,6 @@ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" @@ -9167,7 +9115,6 @@ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -9187,7 +9134,6 @@ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -9375,7 +9321,6 @@ "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" @@ -9477,7 +9422,6 @@ "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", @@ -9500,7 +9444,6 @@ "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", @@ -9520,7 +9463,6 @@ "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -9896,6 +9838,7 @@ "integrity": "sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -9950,7 +9893,6 @@ "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -9964,7 +9906,6 @@ "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "minimist": "^1.2.0" }, @@ -9978,7 +9919,6 @@ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -10043,7 +9983,6 @@ "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", @@ -10059,7 +9998,6 @@ "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.8", "for-each": "^0.3.3", @@ -10080,7 +10018,6 @@ "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", @@ -10103,7 +10040,6 @@ "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", @@ -10179,6 +10115,7 @@ "version": "4.6.4", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -10211,7 +10148,6 @@ "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", @@ -10457,7 +10393,6 @@ "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", @@ -10478,7 +10413,6 @@ "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", @@ -10507,7 +10441,6 @@ "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", @@ -10527,7 +10460,6 @@ "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", diff --git a/package.json b/package.json index 8515eb7..740a30a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "whaileys", "version": "6.4.3", "description": "WhatsApp API", - "homepage": "https://github.com/canove/whaileys", + "homepage": "https://github.com/alltomatos/whaileys", "main": "lib/index.js", "types": "lib/index.d.ts", "keywords": [ @@ -32,7 +32,7 @@ "author": "canove", "license": "MIT", "repository": { - "url": "git@github.com:canove/whaileys.git" + "url": "git@github.com:alltomatos/whaileys.git" }, "dependencies": { "@hapi/boom": "^9.1.3", diff --git a/src/Socket/index.ts b/src/Socket/index.ts index 9c50067..615f32f 100644 --- a/src/Socket/index.ts +++ b/src/Socket/index.ts @@ -1,6 +1,6 @@ import { DEFAULT_CONNECTION_CONFIG } from "../Defaults"; import { UserFacingSocketConfig } from "../Types"; -import { makeBusinessSocket as _makeSocket } from "./business"; +import { makeNewsletterSocket as _makeSocket } from "./newsletter"; // export the last socket layer const makeWASocket = (config: UserFacingSocketConfig) => diff --git a/src/Socket/mex.ts b/src/Socket/mex.ts new file mode 100644 index 0000000..c276de7 --- /dev/null +++ b/src/Socket/mex.ts @@ -0,0 +1,58 @@ +import { Boom } from '@hapi/boom' +import type { BinaryNode } from '../WABinary' +import { getBinaryNodeChild, S_WHATSAPP_NET } from '../WABinary' + +const wMexQuery = ( + variables: Record, + queryId: string, + query: (node: BinaryNode) => Promise, + generateMessageTag: () => string +) => { + return query({ + tag: 'iq', + attrs: { + id: generateMessageTag(), + type: 'get', + to: S_WHATSAPP_NET, + xmlns: 'w:mex' + }, + content: [ + { + tag: 'query', + attrs: { query_id: queryId }, + content: Uint8Array.from(Buffer.from(JSON.stringify({ variables }), 'utf-8')) + } + ] + }) +} + +export const executeWMexQuery = async ( + variables: Record, + queryId: string, + dataPath: string, + query: (node: BinaryNode) => Promise, + generateMessageTag: () => string +): Promise => { + const result = await wMexQuery(variables, queryId, query, generateMessageTag) + const child = getBinaryNodeChild(result, 'result') + if (child?.content) { + const data = JSON.parse(child.content.toString()) + + if (data.errors && data.errors.length > 0) { + const errorMessages = data.errors.map((err: Error) => err.message || 'Unknown error').join(', ') + const firstError = data.errors[0] + const errorCode = firstError.extensions?.error_code || 400 + throw new Boom(`GraphQL server error: ${errorMessages}`, { statusCode: errorCode, data: firstError }) + } + + const response = dataPath ? data?.data?.[dataPath] : data?.data + if (typeof response !== 'undefined') { + return response as T + } + } + + const action = (dataPath || '').startsWith('xwa2_') + ? dataPath.substring(5).replace(/_/g, ' ') + : dataPath?.replace(/_/g, ' ') + throw new Boom(`Failed to ${action}, unexpected response structure.`, { statusCode: 400, data: result }) +} diff --git a/src/Socket/newsletter.ts b/src/Socket/newsletter.ts new file mode 100644 index 0000000..bb645bc --- /dev/null +++ b/src/Socket/newsletter.ts @@ -0,0 +1,229 @@ +import type { NewsletterCreateResponse, SocketConfig, WAMediaUpload } from '../Types' +import type { NewsletterMetadata, NewsletterUpdate } from '../Types' +import { QueryIds, XWAPaths } from '../Types' +import { generateProfilePicture } from '../Utils/messages-media' +import { getBinaryNodeChild } from '../WABinary' +import { makeBusinessSocket } from './business' +import { executeWMexQuery as genericExecuteWMexQuery } from './mex' + +const parseNewsletterCreateResponse = (response: NewsletterCreateResponse): NewsletterMetadata => { + const { id, thread_metadata: thread, viewer_metadata: viewer } = response + return { + id: id, + owner: undefined, + name: thread.name.text, + creation_time: parseInt(thread.creation_time, 10), + description: thread.description.text, + invite: thread.invite, + subscribers: parseInt(thread.subscribers_count, 10), + verification: thread.verification, + picture: { + id: thread.picture.id, + directPath: thread.picture.direct_path + }, + mute_state: viewer.mute + } +} + +const parseNewsletterMetadata = (result: unknown): NewsletterMetadata | null => { + if (typeof result !== 'object' || result === null) { + return null + } + + if ('id' in result && typeof (result as any).id === 'string') { + return result as NewsletterMetadata + } + + if ('result' in result && typeof (result as any).result === 'object' && (result as any).result !== null && 'id' in (result as any).result) { + return (result as any).result as NewsletterMetadata + } + + return null +} + +export const makeNewsletterSocket = (config: SocketConfig) => { + const sock = makeBusinessSocket(config) + const { query, generateMessageTag } = sock + + const executeWMexQuery = (variables: Record, queryId: string, dataPath: string): Promise => { + return genericExecuteWMexQuery(variables, queryId, dataPath, query, generateMessageTag) + } + + const newsletterUpdate = async (jid: string, updates: NewsletterUpdate) => { + const variables = { + newsletter_id: jid, + updates: { + ...updates, + settings: null + } + } + return executeWMexQuery(variables, QueryIds.UPDATE_METADATA, 'xwa2_newsletter_update') + } + + return { + ...sock, + newsletterCreate: async (name: string, description?: string): Promise => { + const variables = { + input: { + name, + description: description ?? null + } + } + const rawResponse = await executeWMexQuery( + variables, + QueryIds.CREATE, + XWAPaths.xwa2_newsletter_create + ) + return parseNewsletterCreateResponse(rawResponse) + }, + + newsletterUpdate, + + newsletterSubscribers: async (jid: string) => { + return executeWMexQuery<{ subscribers: number }>( + { newsletter_id: jid }, + QueryIds.SUBSCRIBERS, + XWAPaths.xwa2_newsletter_subscribers + ) + }, + + newsletterMetadata: async (type: 'invite' | 'jid', key: string) => { + const variables = { + fetch_creation_time: true, + fetch_full_image: true, + fetch_viewer_metadata: true, + input: { + key, + type: type.toUpperCase() + } + } + const result = await executeWMexQuery(variables, QueryIds.METADATA, XWAPaths.xwa2_newsletter_metadata) + return parseNewsletterMetadata(result) + }, + + newsletterFollow: (jid: string) => { + return executeWMexQuery({ newsletter_id: jid }, QueryIds.FOLLOW, XWAPaths.xwa2_newsletter_follow) + }, + + newsletterUnfollow: (jid: string) => { + return executeWMexQuery({ newsletter_id: jid }, QueryIds.UNFOLLOW, XWAPaths.xwa2_newsletter_unfollow) + }, + + newsletterMute: (jid: string) => { + return executeWMexQuery({ newsletter_id: jid }, QueryIds.MUTE, XWAPaths.xwa2_newsletter_mute_v2) + }, + + newsletterUnmute: (jid: string) => { + return executeWMexQuery({ newsletter_id: jid }, QueryIds.UNMUTE, XWAPaths.xwa2_newsletter_unmute_v2) + }, + + newsletterUpdateName: async (jid: string, name: string) => { + return await newsletterUpdate(jid, { name }) + }, + + newsletterUpdateDescription: async (jid: string, description: string) => { + return await newsletterUpdate(jid, { description }) + }, + + newsletterUpdatePicture: async (jid: string, content: WAMediaUpload) => { + const { img } = await generateProfilePicture(content) + return await newsletterUpdate(jid, { picture: img.toString('base64') }) + }, + + newsletterRemovePicture: async (jid: string) => { + return await newsletterUpdate(jid, { picture: '' }) + }, + + newsletterReactMessage: async (jid: string, serverId: string, reaction?: string) => { + await query({ + tag: 'message', + attrs: { + to: jid, + ...(reaction ? {} : { edit: '7' }), + type: 'reaction', + server_id: serverId, + id: generateMessageTag() + }, + content: [ + { + tag: 'reaction', + attrs: reaction ? { code: reaction } : {} + } + ] + }) + }, + + newsletterFetchMessages: async (jid: string, count: number, since: number, after: number) => { + const messageUpdateAttrs: { count: string; since?: string; after?: string } = { + count: count.toString() + } + if (typeof since === 'number') { + messageUpdateAttrs.since = since.toString() + } + + if (after) { + messageUpdateAttrs.after = after.toString() + } + + const result = await query({ + tag: 'iq', + attrs: { + id: generateMessageTag(), + type: 'get', + xmlns: 'newsletter', + to: jid + }, + content: [ + { + tag: 'message_updates', + attrs: messageUpdateAttrs + } + ] + }) + return result + }, + + subscribeNewsletterUpdates: async (jid: string): Promise<{ duration: string } | null> => { + const result = await query({ + tag: 'iq', + attrs: { + id: generateMessageTag(), + type: 'set', + xmlns: 'newsletter', + to: jid + }, + content: [{ tag: 'live_updates', attrs: {}, content: [] }] + }) + const liveUpdatesNode = getBinaryNodeChild(result, 'live_updates') + const duration = liveUpdatesNode?.attrs?.duration + return duration ? { duration: duration } : null + }, + + newsletterAdminCount: async (jid: string): Promise => { + const response = await executeWMexQuery<{ admin_count: number }>( + { newsletter_id: jid }, + QueryIds.ADMIN_COUNT, + XWAPaths.xwa2_newsletter_admin_count + ) + return response.admin_count + }, + + newsletterChangeOwner: async (jid: string, newOwnerJid: string) => { + await executeWMexQuery( + { newsletter_id: jid, user_id: newOwnerJid }, + QueryIds.CHANGE_OWNER, + XWAPaths.xwa2_newsletter_change_owner + ) + }, + + newsletterDemote: async (jid: string, userJid: string) => { + await executeWMexQuery({ newsletter_id: jid, user_id: userJid }, QueryIds.DEMOTE, XWAPaths.xwa2_newsletter_demote) + }, + + newsletterDelete: async (jid: string) => { + await executeWMexQuery({ newsletter_id: jid }, QueryIds.DELETE, XWAPaths.xwa2_newsletter_delete_v2) + } + } +} + +export type NewsletterSocket = ReturnType diff --git a/src/Types/Newsletter.ts b/src/Types/Newsletter.ts new file mode 100644 index 0000000..e3ed55e --- /dev/null +++ b/src/Types/Newsletter.ts @@ -0,0 +1,79 @@ +export enum XWAPaths { + xwa2_newsletter_create = 'xwa2_newsletter_create', + xwa2_newsletter_subscribers = 'xwa2_newsletter_subscribers', + xwa2_newsletter_view = 'xwa2_newsletter_view', + xwa2_newsletter_metadata = 'xwa2_newsletter', + xwa2_newsletter_admin_count = 'xwa2_newsletter_admin', + xwa2_newsletter_mute_v2 = 'xwa2_newsletter_mute_v2', + xwa2_newsletter_unmute_v2 = 'xwa2_newsletter_unmute_v2', + xwa2_newsletter_follow = 'xwa2_newsletter_follow', + xwa2_newsletter_unfollow = 'xwa2_newsletter_unfollow', + xwa2_newsletter_change_owner = 'xwa2_newsletter_change_owner', + xwa2_newsletter_demote = 'xwa2_newsletter_demote', + xwa2_newsletter_delete_v2 = 'xwa2_newsletter_delete_v2' +} +export enum QueryIds { + CREATE = '8823471724422422', + UPDATE_METADATA = '24250201037901610', + METADATA = '6563316087068696', + SUBSCRIBERS = '9783111038412085', + FOLLOW = '7871414976211147', + UNFOLLOW = '7238632346214362', + MUTE = '29766401636284406', + UNMUTE = '9864994326891137', + ADMIN_COUNT = '7130823597031706', + CHANGE_OWNER = '7341777602580933', + DEMOTE = '6551828931592903', + DELETE = '30062808666639665' +} +export type NewsletterUpdate = { + name?: string + description?: string + picture?: string +} +export interface NewsletterCreateResponse { + id: string + state: { type: string } + thread_metadata: { + creation_time: string + description: { id: string; text: string; update_time: string } + handle: string | null + invite: string + name: { id: string; text: string; update_time: string } + picture: { direct_path: string; id: string; type: string } + preview: { direct_path: string; id: string; type: string } + subscribers_count: string + verification: 'VERIFIED' | 'UNVERIFIED' + } + viewer_metadata: { + mute: 'ON' | 'OFF' + role: NewsletterViewRole + } +} +export type NewsletterViewRole = 'ADMIN' | 'GUEST' | 'OWNER' | 'SUBSCRIBER' +export interface NewsletterMetadata { + id: string + owner?: string + name: string + description?: string + invite?: string + creation_time?: number + subscribers?: number + picture?: { + url?: string + directPath?: string + mediaKey?: string + id?: string + } + verification?: 'VERIFIED' | 'UNVERIFIED' + reaction_codes?: { + code: string + count: number + }[] + mute_state?: 'ON' | 'OFF' + thread_metadata?: { + creation_time?: number + name?: string + description?: string + } +} diff --git a/src/Types/USync.ts b/src/Types/USync.ts new file mode 100644 index 0000000..9c0e631 --- /dev/null +++ b/src/Types/USync.ts @@ -0,0 +1,27 @@ +import type { BinaryNode } from '../WABinary' +import { USyncUser } from '../WAUSync' + +/** + * Defines the interface for a USyncQuery protocol + */ +export interface USyncQueryProtocol { + /** + * The name of the protocol + */ + name: string + /** + * Defines what goes inside the query part of a USyncQuery + */ + getQueryElement: () => BinaryNode + /** + * Defines what goes inside the user part of a USyncQuery + */ + getUserElement: (user: USyncUser) => BinaryNode | null + + /** + * Parse the result of the query + * @param data Data from the result + * @returns Whatever the protocol is supposed to return + */ + parser: (data: BinaryNode) => unknown +} diff --git a/src/Types/index.ts b/src/Types/index.ts index 69d4630..23a79dc 100644 --- a/src/Types/index.ts +++ b/src/Types/index.ts @@ -8,6 +8,7 @@ export * from "./Socket"; export * from "./Events"; export * from "./Product"; export * from "./Call"; +export * from "./Newsletter"; import { AuthenticationState } from "./Auth"; import { SocketConfig } from "./Socket"; diff --git a/src/WAUSync/Protocols/USyncContactProtocol.ts b/src/WAUSync/Protocols/USyncContactProtocol.ts new file mode 100644 index 0000000..88587f4 --- /dev/null +++ b/src/WAUSync/Protocols/USyncContactProtocol.ts @@ -0,0 +1,32 @@ +import type { USyncQueryProtocol } from '../../Types/USync' +import { assertNodeErrorFree, type BinaryNode } from '../../WABinary' +import { USyncUser } from '../USyncUser' + +export class USyncContactProtocol implements USyncQueryProtocol { + name = 'contact' + + getQueryElement(): BinaryNode { + return { + tag: 'contact', + attrs: {} + } + } + + getUserElement(user: USyncUser): BinaryNode { + //TODO: Implement type / username fields (not yet supported) + return { + tag: 'contact', + attrs: {}, + content: user.phone + } + } + + parser(node: BinaryNode): boolean { + if (node.tag === 'contact') { + assertNodeErrorFree(node) + return node?.attrs?.type === 'in' + } + + return false + } +} diff --git a/src/WAUSync/Protocols/USyncDeviceProtocol.ts b/src/WAUSync/Protocols/USyncDeviceProtocol.ts new file mode 100644 index 0000000..a20c3be --- /dev/null +++ b/src/WAUSync/Protocols/USyncDeviceProtocol.ts @@ -0,0 +1,78 @@ +import type { USyncQueryProtocol } from '../../Types/USync' +import { assertNodeErrorFree, type BinaryNode, getBinaryNodeChild } from '../../WABinary' +//import { USyncUser } from '../USyncUser' + +export type KeyIndexData = { + timestamp: number + signedKeyIndex?: Uint8Array + expectedTimestamp?: number +} + +export type DeviceListData = { + id: number + keyIndex?: number + isHosted?: boolean +} + +export type ParsedDeviceInfo = { + deviceList?: DeviceListData[] + keyIndex?: KeyIndexData +} + +export class USyncDeviceProtocol implements USyncQueryProtocol { + name = 'devices' + + getQueryElement(): BinaryNode { + return { + tag: 'devices', + attrs: { + version: '2' + } + } + } + + getUserElement(/* user: USyncUser */): BinaryNode | null { + //TODO: Implement device phashing, ts and expectedTs + //TODO: if all are not present, return null <- current behavior + //TODO: otherwise return a node w tag 'devices' w those as attrs + return null + } + + parser(node: BinaryNode): ParsedDeviceInfo { + const deviceList: DeviceListData[] = [] + let keyIndex: KeyIndexData | undefined = undefined + + if (node.tag === 'devices') { + assertNodeErrorFree(node) + const deviceListNode = getBinaryNodeChild(node, 'device-list') + const keyIndexNode = getBinaryNodeChild(node, 'key-index-list') + + if (Array.isArray(deviceListNode?.content)) { + for (const { tag, attrs } of deviceListNode!.content) { + const id = +attrs.id! + const keyIndex = +attrs['key-index']! + if (tag === 'device') { + deviceList.push({ + id, + keyIndex, + isHosted: !!(attrs['is_hosted'] && attrs['is_hosted'] === 'true') + }) + } + } + } + + if (keyIndexNode?.tag === 'key-index-list') { + keyIndex = { + timestamp: +keyIndexNode.attrs['ts']!, + signedKeyIndex: keyIndexNode?.content as Uint8Array, + expectedTimestamp: keyIndexNode.attrs['expected_ts'] ? +keyIndexNode.attrs['expected_ts'] : undefined + } + } + } + + return { + deviceList, + keyIndex + } + } +} diff --git a/src/WAUSync/Protocols/USyncDisappearingModeProtocol.ts b/src/WAUSync/Protocols/USyncDisappearingModeProtocol.ts new file mode 100644 index 0000000..41cb8a5 --- /dev/null +++ b/src/WAUSync/Protocols/USyncDisappearingModeProtocol.ts @@ -0,0 +1,35 @@ +import type { USyncQueryProtocol } from '../../Types/USync' +import { assertNodeErrorFree, type BinaryNode } from '../../WABinary' + +export type DisappearingModeData = { + duration: number + setAt?: Date +} + +export class USyncDisappearingModeProtocol implements USyncQueryProtocol { + name = 'disappearing_mode' + + getQueryElement(): BinaryNode { + return { + tag: 'disappearing_mode', + attrs: {} + } + } + + getUserElement(): null { + return null + } + + parser(node: BinaryNode): DisappearingModeData | undefined { + if (node.tag === 'disappearing_mode') { + assertNodeErrorFree(node) + const duration: number = +node?.attrs.duration! + const setAt = new Date(+(node?.attrs.t || 0) * 1000) + + return { + duration, + setAt + } + } + } +} diff --git a/src/WAUSync/Protocols/USyncStatusProtocol.ts b/src/WAUSync/Protocols/USyncStatusProtocol.ts new file mode 100644 index 0000000..947ca49 --- /dev/null +++ b/src/WAUSync/Protocols/USyncStatusProtocol.ts @@ -0,0 +1,44 @@ +import type { USyncQueryProtocol } from '../../Types/USync' +import { assertNodeErrorFree, type BinaryNode } from '../../WABinary' + +export type StatusData = { + status?: string | null + setAt?: Date +} + +export class USyncStatusProtocol implements USyncQueryProtocol { + name = 'status' + + getQueryElement(): BinaryNode { + return { + tag: 'status', + attrs: {} + } + } + + getUserElement(): null { + return null + } + + parser(node: BinaryNode): StatusData | undefined { + if (node.tag === 'status') { + assertNodeErrorFree(node) + let status: string | null = node?.content?.toString() ?? null + const setAt = new Date(+(node?.attrs.t || 0) * 1000) + if (!status) { + if (node.attrs?.code && +node.attrs.code === 401) { + status = '' + } else { + status = null + } + } else if (typeof status === 'string' && status.length === 0) { + status = null + } + + return { + status, + setAt + } + } + } +} diff --git a/src/WAUSync/Protocols/UsyncBotProfileProtocol.ts b/src/WAUSync/Protocols/UsyncBotProfileProtocol.ts new file mode 100644 index 0000000..06d5edf --- /dev/null +++ b/src/WAUSync/Protocols/UsyncBotProfileProtocol.ts @@ -0,0 +1,76 @@ +import type { USyncQueryProtocol } from '../../Types/USync' +import { type BinaryNode, getBinaryNodeChild, getBinaryNodeChildren, getBinaryNodeChildString } from '../../WABinary' +import { USyncUser } from '../USyncUser' + +export type BotProfileCommand = { + name: string + description: string +} + +export type BotProfileInfo = { + jid: string + name: string + attributes: string + description: string + category: string + isDefault: boolean + prompts: string[] + personaId: string + commands: BotProfileCommand[] + commandsDescription: string +} + +export class USyncBotProfileProtocol implements USyncQueryProtocol { + name = 'bot' + + getQueryElement(): BinaryNode { + return { + tag: 'bot', + attrs: {}, + content: [{ tag: 'profile', attrs: { v: '1' } }] + } + } + + getUserElement(user: USyncUser): BinaryNode { + return { + tag: 'bot', + attrs: {}, + content: [{ tag: 'profile', attrs: { persona_id: user.personaId! } }] + } + } + + parser(node: BinaryNode): BotProfileInfo { + const botNode = getBinaryNodeChild(node, 'bot') + const profile = getBinaryNodeChild(botNode, 'profile') + + const commandsNode = getBinaryNodeChild(profile, 'commands') + const promptsNode = getBinaryNodeChild(profile, 'prompts') + + const commands: BotProfileCommand[] = [] + const prompts: string[] = [] + + for (const command of getBinaryNodeChildren(commandsNode, 'command')) { + commands.push({ + name: getBinaryNodeChildString(command, 'name')!, + description: getBinaryNodeChildString(command, 'description')! + }) + } + + for (const prompt of getBinaryNodeChildren(promptsNode, 'prompt')) { + prompts.push(`${getBinaryNodeChildString(prompt, 'emoji')!} ${getBinaryNodeChildString(prompt, 'text')!}`) + } + + return { + isDefault: !!getBinaryNodeChild(profile, 'default'), + jid: node.attrs.jid!, + name: getBinaryNodeChildString(profile, 'name')!, + attributes: getBinaryNodeChildString(profile, 'attributes')!, + description: getBinaryNodeChildString(profile, 'description')!, + category: getBinaryNodeChildString(profile, 'category')!, + personaId: profile!.attrs['persona_id']!, + commandsDescription: getBinaryNodeChildString(commandsNode, 'description')!, + commands, + prompts + } + } +} diff --git a/src/WAUSync/Protocols/UsyncLIDProtocol.ts b/src/WAUSync/Protocols/UsyncLIDProtocol.ts new file mode 100644 index 0000000..8fdae06 --- /dev/null +++ b/src/WAUSync/Protocols/UsyncLIDProtocol.ts @@ -0,0 +1,33 @@ +import type { USyncQueryProtocol } from '../../Types/USync' +import type { BinaryNode } from '../../WABinary' +import type { USyncUser } from '../USyncUser' + +export class USyncLIDProtocol implements USyncQueryProtocol { + name = 'lid' + + getQueryElement(): BinaryNode { + return { + tag: 'lid', + attrs: {} + } + } + + getUserElement(user: USyncUser): BinaryNode | null { + if (user.lid) { + return { + tag: 'lid', + attrs: { jid: user.lid } + } + } else { + return null + } + } + + parser(node: BinaryNode): string | null { + if (node.tag === 'lid') { + return node.attrs.val! + } + + return null + } +} diff --git a/src/WAUSync/Protocols/index.ts b/src/WAUSync/Protocols/index.ts new file mode 100644 index 0000000..8dccdfe --- /dev/null +++ b/src/WAUSync/Protocols/index.ts @@ -0,0 +1,6 @@ +export * from './USyncDeviceProtocol' +export * from './USyncContactProtocol' +export * from './USyncStatusProtocol' +export * from './USyncDisappearingModeProtocol' +export * from './UsyncBotProfileProtocol' +export * from './UsyncLIDProtocol' diff --git a/src/WAUSync/USyncQuery.ts b/src/WAUSync/USyncQuery.ts new file mode 100644 index 0000000..a630ea2 --- /dev/null +++ b/src/WAUSync/USyncQuery.ts @@ -0,0 +1,133 @@ +import type { USyncQueryProtocol } from '../Types/USync' +import { type BinaryNode, getBinaryNodeChild } from '../WABinary' +import { USyncBotProfileProtocol } from './Protocols/UsyncBotProfileProtocol' +import { USyncLIDProtocol } from './Protocols/UsyncLIDProtocol' +import { + USyncContactProtocol, + USyncDeviceProtocol, + USyncDisappearingModeProtocol, + USyncStatusProtocol +} from './Protocols' +import { USyncUser } from './USyncUser' + +export type USyncQueryResultList = { [protocol: string]: unknown; id: string } + +export type USyncQueryResult = { + list: USyncQueryResultList[] + sideList: USyncQueryResultList[] +} + +export class USyncQuery { + protocols: USyncQueryProtocol[] + users: USyncUser[] + context: string + mode: string + + constructor() { + this.protocols = [] + this.users = [] + this.context = 'interactive' + this.mode = 'query' + } + + withMode(mode: string) { + this.mode = mode + return this + } + + withContext(context: string) { + this.context = context + return this + } + + withUser(user: USyncUser) { + this.users.push(user) + return this + } + + parseUSyncQueryResult(result: BinaryNode | undefined): USyncQueryResult | undefined { + if (!result || result.attrs.type !== 'result') { + return + } + + const protocolMap = Object.fromEntries( + this.protocols.map(protocol => { + return [protocol.name, protocol.parser] + }) + ) + + const queryResult: USyncQueryResult = { + // TODO: implement errors etc. + list: [], + sideList: [] + } + + const usyncNode = getBinaryNodeChild(result, 'usync') + + //TODO: implement error backoff, refresh etc. + //TODO: see if there are any errors in the result node + //const resultNode = getBinaryNodeChild(usyncNode, 'result') + + const listNode = usyncNode ? getBinaryNodeChild(usyncNode, 'list') : undefined + + if (listNode?.content && Array.isArray(listNode.content)) { + queryResult.list = listNode.content.reduce((acc: USyncQueryResultList[], node) => { + const id = node?.attrs.jid + if (id) { + const data = Array.isArray(node?.content) + ? Object.fromEntries( + node.content + .map(content => { + const protocol = content.tag + const parser = protocolMap[protocol] + if (parser) { + return [protocol, parser(content)] + } else { + return [protocol, null] + } + }) + .filter(([, b]) => b !== null) as [string, unknown][] + ) + : {} + acc.push({ ...data, id }) + } + + return acc + }, []) + } + + //TODO: implement side list + //const sideListNode = getBinaryNodeChild(usyncNode, 'side_list') + return queryResult + } + + withDeviceProtocol() { + this.protocols.push(new USyncDeviceProtocol()) + return this + } + + withContactProtocol() { + this.protocols.push(new USyncContactProtocol()) + return this + } + + withStatusProtocol() { + this.protocols.push(new USyncStatusProtocol()) + return this + } + + withDisappearingModeProtocol() { + this.protocols.push(new USyncDisappearingModeProtocol()) + return this + } + + withBotProfileProtocol() { + this.protocols.push(new USyncBotProfileProtocol()) + return this + } + + withLIDProtocol() { + this.protocols.push(new USyncLIDProtocol()) + return this + } +} diff --git a/src/WAUSync/USyncUser.ts b/src/WAUSync/USyncUser.ts new file mode 100644 index 0000000..0dc0d78 --- /dev/null +++ b/src/WAUSync/USyncUser.ts @@ -0,0 +1,32 @@ +export class USyncUser { + id?: string + lid?: string + phone?: string + type?: string + personaId?: string + + withId(id: string) { + this.id = id + return this + } + + withLid(lid: string) { + this.lid = lid + return this + } + + withPhone(phone: string) { + this.phone = phone + return this + } + + withType(type: string) { + this.type = type + return this + } + + withPersonaId(personaId: string) { + this.personaId = personaId + return this + } +} diff --git a/src/WAUSync/index.ts b/src/WAUSync/index.ts new file mode 100644 index 0000000..5492886 --- /dev/null +++ b/src/WAUSync/index.ts @@ -0,0 +1,3 @@ +export * from './Protocols' +export * from './USyncQuery' +export * from './USyncUser' diff --git a/src/index.ts b/src/index.ts index 735387a..a8c0295 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,7 @@ export * from "./Types"; export * from "./Store"; export * from "./Defaults"; export * from "./WABinary"; +export * from "./WAUSync"; export type WASocket = ReturnType;