{"_id":"@synzen/discord-rest","_rev":"114-b72e50fb199b25eeabed7d0f7da35baf","name":"@synzen/discord-rest","dist-tags":{"latest":"0.6.27","beta":"0.7.0-beta.16"},"versions":{"0.0.1":{"name":"@synzen/discord-rest","version":"0.0.1","description":"Bare bones library meant to properly and gracefully handle the frightening monster that is Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^25.2.3","@types/node":"^14.6.1","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.6.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.7.0","jest":"^26.0.1","ts-node":"^9.0.0","typescript":"^4.0.2"},"dependencies":{"debug":"^4.1.1"},"gitHead":"ffbc4a9ea8d5a5b8d82005a613cfe9b542893ef2","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.0.1","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-2iGWMjkom/y6QPbxrMXOKVNUPhzTY3jWBod2gb7nuSk6IaDkyAdepnv9CkqvvPya0kE075bo1Hgt2OO6H5p4Hg==","shasum":"a5c41307ff5c3a1e0fd2f4325dc93a3a07de6efb","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.0.1.tgz","fileCount":4,"unpackedSize":2997,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSaKPCRA9TVsSAnZWagAAx1EP/irhfjqKHVE1cjqUsxGA\nT0uKlqKTvwrUXNxOLmsKy8p0yjVOH8OzENeMeK2klpgpRXadFYlwSlwyZJxq\nFGoIzSQfTYNo7AFKC6k70E2IAgk5FsC94ijfemtqwwgW4Jkf/JzvPs+9rI+w\noyi84G6sy3h0r2PmKSc0xkb8geDOh2a9P2LFvRTQABb+uryE3x5BodabNF6t\nacFe9A7eGNDBQpG89FCBA8vPDxeRGygjPkStIQn8hKRzWesnpEN+0OSIMz54\nsadovHFpAVQjNv0zfhYyrjXdKKPQRD8vOYpUa1VvxZDZq7xmKXQIvXgp+4WU\nWPXdLIhVTt/bku8a0Pxxt/NXGS3yUWAkK1aCyNel3cD45vrGYDI6j5ngO69r\noL52tZWAf+bG8qt4eku5X8hJ7eOWTSKwLS2PIPtjWg32glBgiOGdYuw5oOzC\nMbBP82SW1LoKPidQCYdA7QawRHmI4xNzcwatYkmHR21bAnbOZhhdqgo5Zy3a\nZ8kOYEzaK+ADyGFrnagFjkkFba4qn1RM1fe3S/rsEJckwN+dYTXpd1GFXbad\nX6jBh8+nX11MGMg4ppfkSeg8JCw4gBL9CIjsR5DDD3/ZEoCadX/AkdC1FC+9\nzDFziKOGcDO1rjqmRvBAsM0IV9/MlPhHMiSWew+7eAne/oOkLPghcBL8r92M\n8C9r\r\n=ttG6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCgxobVxZIYeBcdkAByb2PjpL/d02E1r5PKZUAHfGGdzgIhAOKZzSPaWThVVNQxkKEbFhliX2STbhDLD0n32vWRxwZf"}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.0.1_1598661262891_0.6395674753739131"},"_hasShrinkwrap":false},"0.0.2":{"name":"@synzen/discord-rest","version":"0.0.2","description":"Bare bones library meant to properly and gracefully handle the frightening monster that is Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^25.2.3","@types/node":"^14.6.1","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.6.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.7.0","jest":"^26.0.1","ts-node":"^9.0.0","typescript":"^4.0.2"},"dependencies":{"debug":"^4.1.1"},"gitHead":"8d8e2376a46c012f05b723730b58c97d01677d0f","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.0.2","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-WWJZc5xgL06QojBQZY9fY2Io00Hm93POw3uXowBF6Cftg1yiTyCrdFew4VGXoQC2Dy8nFvJYf9VHRNHYzh/jhw==","shasum":"1c9d5cf87654d485ee68c12e0e2e58f4a8de162e","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.0.2.tgz","fileCount":4,"unpackedSize":2888,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSbqlCRA9TVsSAnZWagAAkm4P/2AqUbuuki/75CYL7d0M\nykbnrrq+u1j0FB7akkakJXy8rsuTIkGFXf9TlGEEMNiIw9tquKJU/lUpm7hm\nTmFyW/HMUTvLwDR/bi9FfZtXGFRq26JfJ2IrP21wqtXuv0Xw3z0AKCwZ26zy\nbdxCjKlqgKnLYR+eASBG31k57WLG8nZDVUxmIfjezSjeLEFdOuc6TQ41Um2B\nk3QDYUK3AS8+WKP7cLtUYYyLCxGuRRjqJHkn5MvZZki4SnBIT3q/3XPmi15r\n4Raa1ZDnK+xfu1QNqH8O2ELzBWpsmjMcGSytb/BCuw/tNr371K+pJE7SKiz6\nhUJXrg34rJT0hk/k1cnWI9bLXECd5cHeIjUXR8YHtTXswtAHAf1JD8Dg3Hhw\nfRR1KRuJTPf2cE2XR3glHAtTAjHH4AvgRDfb0NHhdckV3tmYggcdhw4tIQWB\nSgAZOn7vTsCAaBp8wFcLNZ7D82Gi9znYPx1EkwJ8VcqMzKD6UKXIDefaDWVp\n+MlNBXrkgYEaLeQrvNav7Z/UghRtJTVaKPaSbYpf0ex/hEmqEkEH2MGtrSEk\ncjJlXT5wcS0WsEgk9fx0a2elFTnr4hMNqg/zwC/56MGlKicAxhfjTr9GNdDH\nshjxZpx4n6j2QN+mJFA3g2PubiuVT+VFW34l4I0C3d0lgK//CNundU6kBis3\nsQAK\r\n=WAqg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBTYk/mkq7pfy4toqlRr/klqqDFXU2seqRxODCnPiIrIAiEAkhbKX+eGmxjhlZbfcDocsCGVcFYwn9Abxfsb8Caa8z8="}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.0.2_1598667429115_0.34159618308637163"},"_hasShrinkwrap":false},"0.0.3":{"name":"@synzen/discord-rest","version":"0.0.3","description":"Bare bones library meant to properly and gracefully handle the frightening monster that is Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^25.2.3","@types/node":"^14.6.1","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.6.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.7.0","jest":"^26.0.1","ts-node":"^9.0.0","typescript":"^4.0.2"},"dependencies":{"debug":"^4.1.1"},"gitHead":"829df8a8a31841949a4b63e1c958a63714a3e7f2","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.0.3","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-X4rQlB+BO1TvPzk6EhpGkfRgSCBwTVgRAmrFQwPQSWtxDkTef+nL4voUy7I2H6tuqxRjnxumTdPS2ldL8S2Y1Q==","shasum":"33b55373b39e0bbaa4e3d08e600753f2af623300","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.0.3.tgz","fileCount":4,"unpackedSize":3052,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSb1QCRA9TVsSAnZWagAABr0P/2oaxX6huyxxcKLnS5jI\nrAEJpoa6Y5TapwwbOx3KO2vNO7YQuBBi56goDMv9IcoitcPNh1nrZZj4eklL\nZDju2nLw0f4yNENTYhcVCfCWTP9T+yndvkbO0j0ZSdfysZCEFxOn7E8vSy7s\nt866RwFj/gUP+Vz2/SHYPUXu9L1950CNr9OiEwTuNHGPFEwBpPhWsy9zDHW4\n5KH8QW/Z5XtRxHZ37gZgC/ywVib5K3mgCwSM3SZDcu1i9nzdaFJzbaHWHQ/F\nB4uOmw/JcWgnIxsV/qK12aFwR05J8j6QeY7D+LFefPe+I8rUNnVrbyGBYecL\nr+s4JT44Df/aGJK305P0veP5vgz+mZP3uR710HoN1uoOOlhIz1vxbNtaEbS8\nI57ztvpMmcY6OWa/cCYVmxFtHxcJQgISUnf71O6kfYaUJklObtKbwp4no95c\nwHHs4zgl9o3nWH/jwcdwZ7OoPCT5ergX2n47AZfW5JY7ABeyqdxQYFyxxUTu\nNujLbC26R+POBwMup46sVGPATyI6BcUYa6RlV5swWarxQp0wZhDxcCaff2Ge\nsW/8QnitRiB5y0xj299XkeolLJmopOyMfWGWhrMt3gdRCMCGWXuQhffd9IPB\n2FqT9W2zky3cnpkcsWns6eZdjLCQmuwC6d3vBu+051Db9Xg2EG+bPB1hIcf6\nZIV7\r\n=dm4v\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIENi9g0PLlap+D1VFBe1n3kQWf0PtO5Ycvao0YOmlBkrAiEApwB/BzrOT3MWq1r9oYvOwtm4lVMSgM0+ZOX405Yhdg8="}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.0.3_1598668112024_0.25129330101272673"},"_hasShrinkwrap":false},"0.0.4":{"name":"@synzen/discord-rest","version":"0.0.4","description":"Bare bones library meant to properly and gracefully handle the frightening monster that is Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^25.2.3","@types/node":"^14.6.1","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.6.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.7.0","jest":"^26.0.1","ts-node":"^9.0.0","typescript":"^4.0.2"},"dependencies":{"debug":"^4.1.1"},"gitHead":"7fd7714364c8b1ec0fd1ec55f0ca59705e9135bd","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.0.4","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-CRs4CAn6rllXs7QnNieOUhcsQZNrCMypcld5RIltagnCSlAbvdCmR2FWjVlnVTTldq83IyGavEMs4Gdc89CRlA==","shasum":"76c229e73404ad71156de1bbf011f9ac3f7ad235","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.0.4.tgz","fileCount":13,"unpackedSize":26100,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSb4ECRA9TVsSAnZWagAAcAUP/jBx4yuscTY9+z9y68Rw\n1EUpbgThkqr8++CRwz7uUJ07X7Hjj8z0vWe4AMSaeByM2giguHqzXLTBhqt/\n2l4BdPByly/O5TJyyJQ+2ktyWJ6hU0TR5OIoXRH5ihUFzuR5wzMNVR+qDCuV\nJakOlX3E8bij9bJZZ4yiwyuipbfGYPMqGzY2IGgqmWIgn252sOt74Le/PWp8\n+qMStc8r90X2gOT+rVQ/ntF/Od4abAmuLDF5F55LK8QjhpkY8Ox8aR4R17ke\ny5K+GE671Y4eihXyEFc5RpIZadWmLyh126IIBVK+QrxlpCHjeXclkf0iWdHh\nFUhaMp/RgNtSu2MukStk7fAU6R+LNe7v27kU6Y0qK0Lz9L+EIeQukh/k0x9E\nOsRINeafAZTVtHogmdijykPlXoJLoLpQvmV6VuAb5E6iCWsHdjzAJBHQPXpp\nv0Cal4ZNB5Chg6YnAyiO9TkLImms7veYmOMNKA98EzxtD8ItCZ7x4jlZ72OZ\na79Nf/R4+3FcBVrJwwWH63478wBFKYpPp7+0bViX4wb7fG8zlRaoYTuAVQXb\n/jFv9wSUJtn7TWqjK/lJRATSqveB4n1y5HJ5RSyJWZx62D5wF1Sf6SEQlelM\npTeCiKTK627CwdoWrlLFHIqlv7qxZ0z4C9nX9vVNDoga7wsL6teQo2Jo6osk\nvkLj\r\n=7oTr\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDKFBUNt7jctYw5GoDIsvsNcbiHv6FxNMd7ga2KEAQKGwIgHc+Hk2Ayy49pgvk7Jk7EYHbR9o4ju/5gzKsrRbR86Wc="}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.0.4_1598668292447_0.7348696455804944"},"_hasShrinkwrap":false},"0.0.5":{"name":"@synzen/discord-rest","version":"0.0.5","description":"Bare bones library meant to properly and gracefully handle the frightening monster that is Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^25.2.3","@types/node":"^14.6.1","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.6.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.7.0","jest":"^26.0.1","ts-node":"^9.0.0","typescript":"^4.0.2"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.1.1","node-fetch":"^2.6.0"},"gitHead":"6f15e77d2fd4f7f17f3b801b215be873a38bab98","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.0.5","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-FiyWmzQewkZWPiwxTfZjC2JnKvx9jb31t64r55KI2GQSLrf4qJO8bKhI6xREB4iugsHR6HuxsRsYVlMnRZW8aw==","shasum":"d0663e94d34502855629df7bff6a3ab074323c00","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.0.5.tgz","fileCount":13,"unpackedSize":28849,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSpbqCRA9TVsSAnZWagAAPIsQAIoNH/JUhWhb8wv12oAa\nzdRH/nggNZCIAnBkCGOMbhJNjgEdNANVIaLoPev1bKgH981/gC8coyN0LI+f\neYJ71yURLVtcZpbFRyuldFd8I6h8DC8jPtDG4E2pUmUiWwfRI5NCz0RYlLUh\nBZQpDCZ9waHMroApqeBtA119jdSfHQm3ygAA/OAp57aD5Tpyq4YDHrccx4TS\nAQUGGeMCdYweoCHVhORy3xLa7GH5qckpRPUivAJmVDz6ZhxgL+bTA8TwdWqQ\nLIptHeJ8Q+sxJnot7tbZgZ5glQ880JD12lgCdOXYXNgFfixgtSM9hc8nkdgN\nTEQXgEEXzvW/rF9HJI0uyTOE3P1ebk4zuB9zmuXww4Q8B3B6+6D4Kbd9D5eG\nxlR7TJNoCCNpLqwn/WhomGqE75at851Mi8w7zuWycbBsST+YF8X551r+ua9y\nkt410FBCoxQOOLZQSqQqOLkmFFoZXbKI4xAn7HcjtDv52t2G3EDyMxZlITyF\nBz5+/bt0yhl560E+Y4ERMpX7rwjzTPdVKEPJ1mvwke9MDVT66e+oE3MT0+6x\n45U3vpoP3SoraQ7jIsLX9d91zLZOsgg3Zn5FGxrULhNLxxVOzSF2Et1Y5VtN\nc4iKXOhmhCgqYxy09TdE6bLwnFKo0CeNlQ5yV0yop911GI5QgaPm0RUePWUU\nJ4o9\r\n=g2A+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE1lCE6mH+5IDg9d5+0c+JxJWvtKT7lRs7VPELU887ADAiEA5MjEiK5QkIYA2sytJC88kJe1uUrVl4FnHPxLgCx6aJA="}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.0.5_1598723818376_0.5186888695271317"},"_hasShrinkwrap":false},"0.0.6":{"name":"@synzen/discord-rest","version":"0.0.6","description":"Bare bones library meant to properly and gracefully handle the frightening monster that is Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^25.2.3","@types/node":"^14.6.1","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.6.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.7.0","jest":"^26.0.1","ts-node":"^9.0.0","typescript":"^4.0.2"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.1.1","node-fetch":"^2.6.0"},"gitHead":"3039cff7b5e87f80a15345482d53580a81221b80","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.0.6","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-SiEujU5V8kLotXJZapAlDLECvN3FPANEAay6heO0IIAJiA9rdGPRHXxWWBTpDO9tX3P/1YLeCcHwG8sBB+77rA==","shasum":"ca57eb05be47408ec4079ef558987e51756962a0","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.0.6.tgz","fileCount":13,"unpackedSize":28940,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSstKCRA9TVsSAnZWagAA6ckQAIQDEAc/rZjDjaSRBStX\nlxnkeNzwefUY4iEdwrqKfWnNCh1okYGaAFgUcBz6Q4QrZdqVSkTbEpjzj7+H\nbhhLqkhlRZLsw5oZ2bKYzNBJof1wOnEh65jomou2zEn1vJ2HedFNXxvcWjd0\n96Z+iJZw3T/zS+ZNLUeob4LjVlE3Anie2J1RWdPRgNY+AapQEzREmAc0Xzm1\nc9h6d2cGruRmRedftawfFR7xXW78TD/68zVbMEiL7QdiKWuaFyJ9tEIqg7pC\nzYOX++riPrqEGBWuAIsWAyX5wnMSOesffZEbNjotB4G9gwPzAGC5suhrpp7t\nodfSFWcqglZheOnBOoK2xNAPaVzSEyIajB+p6bvLqHDVkXwAFxwqwKzyxc/1\nLNQpAr5Ib3X+npNJ5mqJvY2X+8T/ynYypKRVZ7m/6aY3jAkQYlImMJhAMl7/\nsJSyfoBQUWENdjjsKJ/Rwa5rNub4abEntxJs6RNc24ba/8RS4nBTuOhhTj34\n7I0JRUzqYiWsE+CmYwyL0PxE34JNd4Qc+S68ZRM081R+EwIisGtH04vqwdul\nN/owPxIsnpKlq4iO3ThI+nlJVDe4tQNwJ2/ybqyY5mKbe8Wp5+O8mUckr7DI\n1P6uQERnqWiTvoDrc7Qb2P8GfCea9zFX8dozP+kz/VlDrp3Ykkhy3fksnRiP\n0Pm6\r\n=VLhM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCgwDxTp8OZBrs2d2j49uD7Q5euGSC3K6Dsz67oeSlEUwIhAOB92tEqV8fIiN5xsQOQlPVgvnsQ9WAnrok1WJpPCtdK"}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.0.6_1598737226056_0.7901120489238198"},"_hasShrinkwrap":false},"0.0.7":{"name":"@synzen/discord-rest","version":"0.0.7","description":"Bare bones library meant to properly and gracefully handle the frightening monster that is Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^25.2.3","@types/node":"^14.6.1","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.6.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.7.0","jest":"^26.0.1","ts-jest":"^26.3.0","ts-node":"^9.0.0","typescript":"^4.0.2"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.1.1","node-fetch":"^2.6.0"},"gitHead":"dea6f44dcd1768e3fedbe62f4fad4d1668eb7fa3","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.0.7","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-3H7EM0SJaSIbrjscLEPv0XDTHSTpOl4RBpIWxw94ydlUF/d1i2Vz9TEVsBaBUdMTvBmBboeLTpW+B0TbJERYdw==","shasum":"afd969b7848fb09d8b85154049110a2f5d035a8a","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.0.7.tgz","fileCount":13,"unpackedSize":33400,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSzc0CRA9TVsSAnZWagAAQAgP/A898LGrByzMtj6+vEH7\neQ2zkY751Y+XJ6hUN87sXT4j/ih9n22xlEPCRvIk0NCciS/rYMxZ6UvjXIiw\nXlNiksSwIkZn0NRYIY1whqNkJePCYHzW6sXFKSG43OlR5i1wra3AI9P6youw\nSBYhi3dNRHIy4yvAUmQvdrhOizhCA0Fq2drcPJs2fbbEDBgjEjUtUa0a4SUf\npJCfeHnQWWbS7qA4DulX7mTPaGrRkzoX/EK71jVHeBS6SoO+AEE3Tt7tyyqp\n10VTB5UcUcURu/KJ+kOlK8T+62yfMd3ZjzuXGmTsVPDkxYbKkMNxSan5M1Gf\nn5eSIlYRn4ZkhVhL1pkteYqhgSm52rvu7tbO2JknCNhzYakn063oO88BZc02\n70nAbLbFBRRg1eIoiqHFV4oz1uv8kvsSpRYYjmJMORuiHK8+WHgLLl81r5fj\n8/Foep3Hc0uwG5APsJ2N9GqSdKxZLpOx1R9HxpQoxUjUcCKU+IugP0QVgu7T\nvM8zC2hS1npUx8nn9E7b0CWuXWFAesp4R2jqazn0hogfcta46CJQwi24l1rf\nBbPAqHCc28KzK8SqXpuTJ11e+mmxaw0STAEeLm0wbbkHOIHu4qcSTMO9vSoq\nn8nvzF4Z2Crl0bp0fsj+1ad5wi4j5ehs1Jjh3RxYDFuGYuRM/80Yfl1WUrUm\nahKx\r\n=RqEJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC2tLv9MtjrCm02cCyeEu52mNhCNgQWRshAYBM6kgkcuwIgSACOHEAD6FFofjTWd1svaa4NV1qO9W6fx0+l592MlHM="}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.0.7_1598764852022_0.10328638273238866"},"_hasShrinkwrap":false},"0.0.8":{"name":"@synzen/discord-rest","version":"0.0.8","description":"Bare bones library meant to properly and gracefully handle the frightening monster that is Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^25.2.3","@types/node":"^14.6.1","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.6.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.7.0","jest":"^26.0.1","ts-jest":"^26.3.0","ts-node":"^9.0.0","typescript":"^4.0.2"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.1.1","node-fetch":"^2.6.0"},"gitHead":"8adf7d40bf4e06df44378f16c4d0702aca81e337","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.0.8","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-5qLmLsfhd+K3puecBlLSBU4iLvqiUV0ErJpFdJ+01bUjUydvSVnKjSIVnQnNw/Z5gs/T3AIjRLT7swxlMsgP6g==","shasum":"ac2cd34c76d4b834868c1fbe014792b9db7429db","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.0.8.tgz","fileCount":13,"unpackedSize":33532,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfS0AOCRA9TVsSAnZWagAAlMAP/33DaalqyuRZyiKnKFoq\nq1oJWqCB9voiM8uM3oUcbN+FAs9/h6dPJkufBSD4QqaNtsRqtBLJC/cPYnTQ\nfUUBgNwY7qzUZ2PgP7yRYuc4NIxl77xUora8e4TDlvlCS0EMqIUjYZ4cDPp3\noLY9o9Q52EBIDGn0g6l53V+IN/07Du16ibNetyR6Lc5nga0oDBaoCt/cMXwN\nv7e31vPVF6RJ8LxLxoM5+L8/zt01ZSdE4jcy8f0B4v+wfZHKdKBkwLo7JXiQ\nh3UXNHEF1PzurY6ezQhS1a/th0KHB0HdSV/G3Tos6fCVb5aQ38RscUAC0Cp8\nUQMXaDZ9YmjveJ9pSQRX21Nu2oqe2PXxANPAv+ii2ZcO9SVyJYyRQem48vAa\nbnVWHFHUFPLURQ0CESx1nNEXzXdjl9PuI3/o1lhSlOlwrtjz1GtM/mMoJLEp\nUZqt4jFP1BYhUPOQW6DCOj9cYWY6deQR0c6uEI60GooQ+VVdH/QiXud2w3It\nU75uqrJCYOKFG3ZxDOOcGONRn4JGo2LE+LABFY92vVE8lq9JJpW7GCQrcTO9\ngy0/3ShrMhnr0Tlomf9cc2Cj1c8DJK/SEyHyjJGgNBrJ8+FSj1j+RzJx3rWK\nZPdG4zvYsNbR4cZ7CoOuvX3vyGJ0zLgM0tbwOCvTqZd3PH4LQuqpnob8Ibhp\nJLL1\r\n=2Rkm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCfe2pmvQJkx4NtPJltXW1bG+n92Ppx+i5zAqZDQGzSKwIhALoTBkXwFvRG/pl9q8fYqUnxSeFyTcd9DNh0LJ6OieXg"}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.0.8_1598767118056_0.9228526730859419"},"_hasShrinkwrap":false},"0.1.0":{"name":"@synzen/discord-rest","version":"0.1.0","description":"[node-fetch](https://github.com/node-fetch/node-fetch) wrapper meant to gracefully handle the frightening and confusing monster of Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^25.2.3","@types/node":"^14.6.1","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.6.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.7.0","jest":"^26.0.1","ts-jest":"^26.3.0","ts-node":"^9.0.0","typescript":"^4.0.2"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.1.1","node-fetch":"^2.6.0"},"gitHead":"8cf38aa9227562d3b9486d3c06b92aaf8b57c0b1","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.1.0","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-0A0fUSDZytn8ay6jIEh6eUwbkWaD0XG9LFQ09t98vCnKnPIa6lpHr6DnTz5xap9zZPzDd0lgD1tbMlN13bnWcQ==","shasum":"e0994e82dd7d13d04a385328e8850cad75ce08ea","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.1.0.tgz","fileCount":13,"unpackedSize":42034,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfS9/wCRA9TVsSAnZWagAAw8IP/1OfN5OKqptHfVNC6qKe\nFwzFGjv5RilpR6bUVOgWdz97tDa353sUK2YFtMZYXJf/6lGniCOwzhyZXKFY\nTklMLcv3mfDhWjAEAKVhM8uDRToepvehf8PcrVZp+2LdjoSZ2OLXIsvsY+y7\nUjA1mLjH9GC/+7EfZpwozYzgVq8QLB3oIdFRmmLPrdutfhrG9mTCKSp7HvJC\nMTI2izA6KTGQymP7bTuDmcNxovKDrciHuXoj/hh7sRt4KVvi1LeTF7+P+DHp\nFlWq0xfn9uk9yMYZgoIrB1to7qt7Ov4w6t7ujLyZ7BLWlRG2+MEtGMx1CFN9\n4U60HCnuP0QiuuBnItegqNklbtZKU5r2yjTT4HzTLAnbZ6eC70QvE0G9TnIl\nue03ffLw1/41VYxvfTjMVM7dLMa6kpFMdMK15227qB1emCituYvhv16FVzkJ\ndjjtCrvjmIl1Cbzpddl0nNmAZ4BcI8qlSgIzs4/9lE7SLMFmm4IEHF7pFO4b\nD6WYJCVUs91aSyeoGLLtT3wcKyBRBQJzXB/Zk8MY+cLrg7cbuarHkV6+jvD3\n9CwofukaPYqtN45CZu/XmS38Qj2v9cfgW2O0IqNBFy0S5Bqoef3qu9vQRCXe\nlqTA9pNbCYlluw6zBLjvrXV7O5c9NVm9DjICY1lnEcn4+y4GK0oP1xHFFh2s\njq4c\r\n=SJWU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICBcCtKBP+Dp+gA/nzCxO3iXOMEUp33OzALKqXwow3utAiBCpiGV49SV/jHxzferkkqIbUnu31sqdHCkN/kOpM9oUg=="}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.1.0_1598808047716_0.39130310522857337"},"_hasShrinkwrap":false},"0.1.1":{"name":"@synzen/discord-rest","version":"0.1.1","description":"[node-fetch](https://github.com/node-fetch/node-fetch) wrapper meant to gracefully handle the frightening and confusing monster of Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^25.2.3","@types/node":"^14.6.1","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.6.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.7.0","jest":"^26.0.1","ts-jest":"^26.3.0","ts-node":"^9.0.0","typescript":"^4.0.2"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.1.1","node-fetch":"^2.6.0"},"gitHead":"a95b76a19bc999d0a2b68ffa897c6f1c6dfacb18","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.1.1","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-Dw4Iwgnh7rWThcX8JCruwwys9tp1B6j8GGxx4QRC9kRTCAUgQU1ZUhWdrpN30e252cJMvX39wLvvnNMWY2J8IA==","shasum":"019fccf05538adf8bca3fccb4189ea4eb55fa63d","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.1.1.tgz","fileCount":13,"unpackedSize":42033,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfS+BvCRA9TVsSAnZWagAAuM8P/1ufXToTh0OgTm8nu6Ny\nX6c3GxEAEJbVdJi9aceJay3Zf6Amar/2FV6/9j+4SFc97WY+m4oJrJLoKJNg\nx93kzxN9kbFnTsC7Yp17bgJW8uBlkPu/12g2YdB/QZw1jm317FqmbA19AwT7\nla983gJzGb//2J3dsKOlBHsl+ieZz+AmtPH9RTACWWzNQtqNVPBl5xpfNbU9\n5UymqKD/CajwtmG73cnw3hdEUyjdOC4eGl//3GG4j6ZRe74kD2wE1VZfGTcL\nOZboi7vRHnAk/+klWXiiSq94lo1obb5s0z3MQ/Y5JjvV8LHsYCdW13r5fzjs\nddxYJW50lhDwUi+/5jT2H6eaZ4YC03ZEVWi8AhVMtoDkiyoMcOCpsKT2kxGr\nMRj/3l0v062Z2aWHtNIJyy9oa4WXb7qSRM4IFL2FsjjBEoWQRFGXDA9AWcZI\nJmRgyuuLmjMus1CV8h+dFKbDNd8UH/gw4c7814Z6SoXGdz7cJg8HdzQCUJR8\nCncf2JbV3a+wq+BQGQiAWgtU/KwoZShJxDnMRFlIWatAA8MZvTQojZpprQhp\nnxnuyZtz9rLV2dwWGKTnei/UCq7dCX2qPnXHtbQsmY45KiKIE5YsgNQFJXg+\nMZxMxdLIgHNwl6iX1+1A53UYXsxAY7nZJ0fSTfJDLufgKiTKKAke6SmG/XJ5\nniCY\r\n=cg4z\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAO5KTKpFMKoDztJ/WKbyLopmAo7jOoBtKc5GW+YepBEAiEA06ZuyQrcFZPX1fsyXNZkVdxE/2qAOL0Nv94aPnRQj54="}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.1.1_1598808175203_0.6052136709777658"},"_hasShrinkwrap":false},"0.2.0":{"name":"@synzen/discord-rest","version":"0.2.0","description":"[node-fetch](https://github.com/node-fetch/node-fetch) wrapper meant to gracefully handle the frightening and confusing monster of Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^25.2.3","@types/node":"^14.6.1","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.6.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.7.0","jest":"^26.0.1","ts-jest":"^26.3.0","ts-node":"^9.0.0","typescript":"^4.0.2"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.1.1","node-fetch":"^2.6.0"},"gitHead":"88189083fad869878ba33c40359faa8bbb8da587","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.2.0","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-brghf/XzbvvHqWG5gxba6w0C2Lqyz4JrUK9KhDbizH5AwE0HUgjKpQrK358PnHM4fogFih/1E4GS9vPfCAw+bQ==","shasum":"1dc81ae3f3d815fc5b5552ff8b6ef4cb0a05cf55","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.2.0.tgz","fileCount":13,"unpackedSize":45066,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfTCOiCRA9TVsSAnZWagAAXnoP/1vt+AjAiPD3bWtCTcj3\nA+s6qurVbvlUzHDFHAr/JihHCfkR23ddvJV4vRe7pibC8xdoMQNfMx7TUK+i\nQAavY+wU1OWB1aKJEGEelkswcu4r8uiJzEDuUB2z+2iysugWEnynCx88bWdQ\n4OL6GfX9Y+L0COlc4B8G/ED7LJ2j+372mpnf22zF1OX1392CAmuFxkIV5bzQ\nHevjdPf4vS98fZ+KfHDUCDNr5QbKDDrLNBfmrm16fAyNNWrB+ryoV9rBC7b9\nNvy/IGfGctnkLO7y3tWvomurYfMq/02y0D0lI6m31qzrYKatvP9Z8irFA1un\neYftzd7f6d7HqzWLKke0msVFzfbqQd2nLER+yJBqLUZidbK36/6V2US59cTx\nzaj2eblSAJHHvJWKRqwZ4xFwNVIT19pnXnsHL1FKhk/fd0p7KyOW/CdWQdaD\nj3ddh1RsLZyJNTOVB1gb/8gvg1ER9/psC0jeb7bo22QIe5V+SlMQxiCVeu8F\nFyPFaei/befCvoo1b1TuT9HrVVbHr1lrErAbpm3kKvyiGGW/aRyKwCxJbwWX\nDciKWis7hfVdMJNyWafU/+7JsGlvDodl467VwLzDbF1oF59KmpFBW2dwjYQ/\n3yPOScnV8d3xYnAzfRqLqEnexad4apfLExS2ey5BrpFabaVcclycgT4Oinsp\nguEw\r\n=BdPj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDKOCv52PeatyxM5k8URgpJt2TceeKz9F00l6OfVWiBxgIhANLT2zWPu7+AmHsiPj2eM0kNVyw72+QA+odHMFLtTFnt"}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.2.0_1598825377599_0.14817199404064008"},"_hasShrinkwrap":false},"0.2.1":{"name":"@synzen/discord-rest","version":"0.2.1","description":"[node-fetch](https://github.com/node-fetch/node-fetch) wrapper meant to gracefully handle the frightening and confusing monster of Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^25.2.3","@types/node":"^14.6.1","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.6.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.7.0","jest":"^26.0.1","ts-jest":"^26.3.0","ts-node":"^9.0.0","typescript":"^4.0.2"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.1.1","node-fetch":"^2.6.0"},"gitHead":"5a86189c2de4b33df8919b1fee276424096a3072","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.2.1","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-V2XxF08VXuFGEW449JzXMJT85miIMa50FS4DlCVnk2zNJvVZqA767jr4+2XiCxMTl2rU/VEeq0I57/hHErX8cg==","shasum":"bd5a18695b50c93305f6ea69d6fd757ec4afd464","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.2.1.tgz","fileCount":13,"unpackedSize":45474,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfZ8r7CRA9TVsSAnZWagAAD9gP/1NSN2sLEcbcJPGaf4Da\naoUAQhr3NfWTSYCbSc5EQpAOIAiLvT+U0CvKeR1m2uPrf26T8O3LagAMdG9Q\nCWc5fp2RlpWFJtQHNZJhtkkrmMGcI4vcsoHxAk2yjndXFM6wwg2lhg2wMWtt\n3HqfclZ0meYwLtMcHDJnI26GrKddjrtPsQoler6gS5lmyKNmEZOM/75rhs0g\nnMIGbF7vavo2XNDJXkp5yJH631Lrh3pqSjsw3H+odYSAgniwpeWYlybesNvy\n/lZW10eV/rlBeQIRHDyR/XbOoYMLZ3AOfdatq01Ul5LCG8EWK6URue2P5cwL\n6nf6pg7yna93crbYIs7gqq48iEGHObOkXNoZIYU7EvAjLEvRQvXFBEfgHHut\n9zlGD36AdwMXvdZdBRwcebQzjBrUQdHVwNkZK6mdsSqk44ZNKw80kd3p1CDL\n0xyUeRRbOn3IU3NRcSMHamk2B5K/gyVqLrhcSz1hO+kt0EoHMKPXxE7VjlbP\nkVPZXXOFo3JcE+5z8VcdXJd2hD3C0jP3ryCSu3GkOUwI1pyR4f2W6584SeSB\nzdKqjmUD42Av8rTPLzZSL1/BCDOcPV+HkJnmymmst+JYZTi+T+pebdULSXWV\nBfSP0Uj2dEZmg5piwBXrjfFkec/DhI/WMiR+PYWaRYXGZ1aEzhXDHzzKG7R/\neIAI\r\n=JYoD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCjTrUVIMt+MNkso6flJiYW9VplesfJhIexa6qTd8B49AIhALe0IllzgUlPCsutzxLfNt/Qu00jPNbJXBNgVLu2g0xG"}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.2.1_1600637690297_0.4362936006312246"},"_hasShrinkwrap":false},"0.3.0":{"name":"@synzen/discord-rest","version":"0.3.0","description":"[node-fetch](https://github.com/node-fetch/node-fetch) wrapper meant to gracefully handle the frightening and confusing monster of Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^26.0.14","@types/node":"^14.11.2","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.9.0","jest":"^26.4.2","ts-jest":"^26.4.0","ts-node":"^9.0.0","typescript":"^4.0.3"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.2.0","node-fetch":"^2.6.1","p-queue":"^6.6.1"},"gitHead":"aecd7baa4d961edb902b55a4601c462fd3b58fc5","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.3.0","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-jB/sbi2Sfomq42cINloCbPSwehhL4+E9KqyfDmBvaNk2mVomZF9tfvOnsS0o9RykZIectK2JSRl3/jjmbNp0kA==","shasum":"d18ad74b2ee7c8ff9fb2924c6661065474605189","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.3.0.tgz","fileCount":17,"unpackedSize":66460,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfbgPUCRA9TVsSAnZWagAABkgQAIaN6tMcGKchiSKI3sFY\nSS3sTyyYiP4dbeKp6+uihDRLBtAFR2D1F5AYTuhKFe1OI5LEnu+DQq9rnEe1\nhpfLHXnqiONFV795nk9YsGSJItXBRBxuI4jNlKdR1c2Ti42mI6h2m54WFXbU\nj43T1ddkas3+bYFiH3rdx/rtPi5t/wOJ9S7MZralbEBkKV0gRUdHHg9AYHd3\n5kCc8x45z+P3wbhRH5joaxPJi2Ogvdi3GJsnboPi1DTdKVp67U3SBIAfZFXA\nu3WnSjh0lSRZ4QCTb/FyHXCaagmrnX5lUs2xp9tXxRYhtkar+60+UJI6GJt8\nsXC+xEJR0kKsQ73wDxjEsXWkOetZJBrYeauA1KP0xhQzqcKHTzNZiVmbPte2\nTTGdx5L5ysk9qYRE6gkp/UajQ8OS/JF1+TSRUKl9G/DoFpjubIgPxEmr3pjY\ncDpccuucA9mUrJbtC4tgdiBtM+jyRm/lqd9y8wQ/pCgWxyWMu7NzRHCdlRl1\n/wQphF0rE7U/cJrOgup3PXwgbr4giXQUiRVxPTjEhdAhyyFxcs1MaBlD9wcQ\nxLDNp03Al7Vbw6yxQhcDhD6kJvehfw0/jBsXPw/3m/IkGmJK6rEpxS0HSJ7g\nybiN1lQYhrzfeoSCUQKpF2z6whmhA9kuprMMQe1+IPsiaIaPO6/quMrZk4MO\nKsV1\r\n=LlC8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCqEdBmD9HA9qBwd0m4AeDXN21rZtX9KBJRMQgqw0HhzAIgfumrUN3GTNZSy1n7JfZKlUDR4ttZM87uOQ8GVPn9G/A="}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.3.0_1601045459894_0.4572657339365771"},"_hasShrinkwrap":false},"0.3.1":{"name":"@synzen/discord-rest","version":"0.3.1","description":"[node-fetch](https://github.com/node-fetch/node-fetch) wrapper meant to gracefully handle the frightening and confusing monster of Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^26.0.14","@types/node":"^14.11.2","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.9.0","jest":"^26.4.2","ts-jest":"^26.4.0","ts-node":"^9.0.0","typescript":"^4.0.3"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.2.0","node-fetch":"^2.6.1","p-queue":"^6.6.1"},"gitHead":"d08be4d9dba9f5270fa648499e47243b0bc7b77d","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.3.1","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-z/QJo770sjgg4pna+9lfy8BlBbdM3/DW1a0OZqOfViwfD+aWeDid4o8Nl24oDxIgZf0kA4v7XubAEkh6eOyKXQ==","shasum":"9a29c41af025d754e758f8517b8f1fe11a936ffd","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.3.1.tgz","fileCount":17,"unpackedSize":66461,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfbgUPCRA9TVsSAnZWagAAOXoP/ju4uf3/xOSF2ZKr50iH\nq8HdeS4vuLTCWHKc8lKQCuLywfNzN4hRD+UkXe99UU2nMeiBA3l3ThYbnwM7\nZyiYrkd0LjibNWC8/cqKTGWMZnrUmXxUJ8RITi3aSOYZWeq/Y6arS6hTwCZW\neFQs1vnmC4chpup85caeJgy2jgSJUprHF5QnEvL6CeYOxnrB4qZFMpkVnPTu\nnM3+givfDHeKXPn4RCxrS4o0Otem3tKu34rSuP1niT19GiQGCXuITYS8lrXy\nRZGz4PUh1uyjuUG+idA7vfJoQdX4if9aGYOuf9KICplR8hV96KKUJq9MqH+d\nBBHfkChl7aDTiwI82ZTuCrSzx8Cvt2Xa8D0oejQldjnDyZwNmNY+GwIn7jUe\nXpEoUieq9nx7URlLvaPaWP4814Foh7/uwEE+V+8I+2ZrmETSQKqXEegQ5sBI\nOpFe+okUUlWobFpDAJkZoKduebQ+srUCEginc0QTHwxz2qscbzbluRWdlWcn\nFPBi/VWT3Kq2wz47aPtFXq1E0cvkM5AhE9ix2XFKSxTlaEYn4CRASK9Je1ya\nMftH4d1go1C+Jk9MsGRPdrVkCsisaLID6BKG/rBW5LHFwtwT5ZTtq24Sl8Hx\nv0JlsTNYsTwKEKJ/FnnyubgS75AokbsvUjq+yxip3IkBtxXUEq4EHGSxglXQ\nDRGB\r\n=fSAD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCvwC5QouxOupOF1O7Er9w9r+EifsyTlcBLsOezsXhiXgIgKy1407ptu7KYzbGaJQZJSdSKmgyhnvDOqTGjV1fCIDQ="}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.3.1_1601045775078_0.6501177612819928"},"_hasShrinkwrap":false},"0.3.2":{"name":"@synzen/discord-rest","version":"0.3.2","description":"[node-fetch](https://github.com/node-fetch/node-fetch) wrapper meant to gracefully handle the frightening and confusing monster of Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^26.0.14","@types/node":"^14.11.2","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.9.0","jest":"^26.4.2","ts-jest":"^26.4.0","ts-node":"^9.0.0","typescript":"^4.0.3"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.2.0","node-fetch":"^2.6.1","p-queue":"^6.6.1"},"gitHead":"7002e12ac98126d16dd4ea8a8274a9b941a72d38","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.3.2","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-CX9CCt1h731Bwus4QwngM4EB+cm5OH++lhWWLYVsYKHJaiI9gtQ2KzgqFpKbzeWKBliznGxzh/CdSDN8jYxuEw==","shasum":"251e8db51a4d5b2a0a3c9ee523bea001315dadd4","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.3.2.tgz","fileCount":17,"unpackedSize":67213,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfbgcGCRA9TVsSAnZWagAATnUP/jYZFfS81B+1v8HpAZEb\nwTyhI8XoeuWy+bwuV/6N1+IJI+jZbwzQOThowzpW92PMBXgSPcVjHhVaZ+q9\nozOSi1f/pQvW5fTudTj0ON6U0rfme2HPFykPiUZC/7Q5z/x3baEpi4tE8U4r\nyXlkakDjE8TgG3hAfEcDTgGY+/z7uQnoNEbR11o8hUJi2McExbiiK8Db++cu\nyB8+wcukWNFd2wm7PcdmGldoC/r7KNRSOF032g15JjGnDQK1WtCgnyH2hODY\nzZtF+jMjTl8cbaRCGkmuCnZq2ZDUamMyeTbF5VlJEYdf8Qyd+n4zTZ2qptLf\nrn+0rf0VkrzhOBOAmG3ZYXVVbYZZflZRUfLDvUPZ5hU2WPmaobWE4TQMKmSA\nf9r1e1qt5UALpnzSa5XAGaBXobS80nZPPBN49eK+936Fq0L1G7itcx+0k8jR\nSimqXobnsVZLByi/UMqsBUQbfi3nlfjlcsnJSJ8Fw+KcsXHaAIfNSLO670Mx\n0EFUkr+GRU5CxnAlTvRWCNyZWGDtLiOC9Fu6j4c8DXGt2bDqUBOZiagj1OUW\n1DIn8sJ4eDJ/MBihiyZvXPvCmMtiC2wJKdIrt/G7gyO+3SGrG8B5XBsBfXX2\njFbzBKOM+CLR5/Vkr8J6evc3bGymb+d3xGb4pz3FEofwDcEd2EBBM2r8kAFv\n+bqG\r\n=e+v0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGKGc+cQhfd9kwlFLas1qyPbUuomp0rXz3R9yu8FoziLAiBHyRKLyXC30+fPJC5pwceHjeMgn5/QGoKVOpwMes6BNQ=="}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.3.2_1601046277570_0.3267583651828483"},"_hasShrinkwrap":false},"0.3.3":{"name":"@synzen/discord-rest","version":"0.3.3","description":"[node-fetch](https://github.com/node-fetch/node-fetch) wrapper meant to gracefully handle the frightening and confusing monster of Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^26.0.14","@types/node":"^14.11.2","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.9.0","jest":"^26.4.2","ts-jest":"^26.4.0","ts-node":"^9.0.0","typescript":"^4.0.3"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.2.0","node-fetch":"^2.6.1","p-queue":"^6.6.1"},"gitHead":"e6ae4d6e832121049b95b01662cba2a287fa6d5d","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.3.3","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-Z2n2JSSacTnnR8wmPABKQqHMZJjduGIgprzC1Y8CjhsQgvZtAafr/FPaDPgglelSMiw7iul2+gPVkNPcFJFeGA==","shasum":"6eaf4cf68fcf5bbdc1e146f91df642debd0dee06","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.3.3.tgz","fileCount":17,"unpackedSize":67352,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfbgfMCRA9TVsSAnZWagAAc00P/idU+ib/2bzmwmLZ9Xit\nNLphouTLxmyKY1u9AnhJLSzt4dAgLCBUQjMPZsccGXlJF2LgKupzCB3V7x+m\n9s7HI9RkTAe9EMN8civ63tX6Rr0Qa6eVF7Wt/EYo+ep15UcdMhvlCAK8GkAx\neMdgfi+Tv9aWQQOGuFhShn64rVgN2JpuH1JmX3Lj/jqR2h+fS/BhXqyBMEMx\nE2aioyHIQYazAv8ugRvrAokrsrsux/Q1EtoFvjm6NNIEMfhRTVvckDKLYPrx\nWbAlRyz3HlM1bZEzO+6kh+CdTBwE6eTiLFoPUnG8YvWRjZQ5JsgnhQgwepPx\nwpH4Iq162ogW1/8XHlHBXSirqEz85ulyLy4nC29ffyOnvSEpc6k1GcMpJg+m\n3vLxQlPC0wKzVdA33rJnoZfqcawXe9AL7Qklg+zBJKxwxEoE88ThXfDLdIbw\n4gNe18es/RGW9MlSejM6ZUky9M26PKTFxGWk+hw/YwCc7JcTIJqDbCMPYjt6\nfwysky//AIE7c8ak0E6MerV8KiZynkv2CIqhNOzIuLBpw65t/gjPReoZ/Ob3\n4oHn6+XShWrwZqZBaUdCKuEtRS7K73DygYvLFk4QauEfRFEMvsgjeElfYY90\nv+upiRICZWzLQmD3ns4keJvU/QxJgBcK0jM+IgRGaDMusPaLmeF2uBozDFPp\nTbE9\r\n=XEDk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDYBn5k9ci0smYCDSjLVBnTg6wI+JCSJUtnusLNUUyXTAiEAvXR15JhhU7iYEY0B+T9ZAEb2qO/YjpB+BbX+LawFDK0="}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.3.3_1601046475729_0.3155854759047261"},"_hasShrinkwrap":false},"0.4.0":{"name":"@synzen/discord-rest","version":"0.4.0","description":"[node-fetch](https://github.com/node-fetch/node-fetch) wrapper meant to gracefully handle the frightening and confusing monster of Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^26.0.14","@types/node":"^14.11.2","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.9.0","jest":"^26.4.2","ts-jest":"^26.4.0","ts-node":"^9.0.0","typescript":"^4.0.3"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.2.0","node-fetch":"^2.6.1","p-queue":"^6.6.1"},"gitHead":"7c902c6bf501ded63699e7a311bde9bf683bbe04","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.4.0","_nodeVersion":"12.16.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-nonjNDqYRrg7M8awrEd5gRZMpWl2d1ExKpHEu5AcqJoKaYnfs9DRfcFq79w71rAu5D1/fCzXDjpo09IGsTmi7Q==","shasum":"760579ed34eb12a8e937cade42953c39f449e932","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.4.0.tgz","fileCount":17,"unpackedSize":68190,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfbgvdCRA9TVsSAnZWagAA4JgQAIZxFFhhS1y3jacEqdX8\nlVyrZ4334Jc52B+++FcJeqsIBYe4LvRr8snkisALluNJ4o4kcplAR/dw3zlz\ncHY1FsBEdUveyiFwtgqS069dkwkqO3M72wnUBtxM5fd8Ds4mqXBYsiP5GKYz\n0WiOsatog0tJmPxHCH37fF2YmRQ9664hypPLg5PSIbwStxOKNuyYFnHQI7AF\nljuWeL580mejFejAl96N/f3ixRpkPq46pbE+tOuGcVYryzsuMgvemNPHtydA\nBmNLjmQ3zMuoIDjcQpSrqPsm5wENC9ZHhq4YgyeJ2W3frFjpSLHfwweEpZzn\nbprPg3HOazbRg/Qp4VSEB5dSCHED3OSyAq9HC4dNyqQtxu2bi5BkwsXhr7aR\nGX0G1EBy4zvDpHIueoMcwttw+wXxCjS+w2P+l0ZcO8xL0w2i/6s6pFnPhJwr\nNjXcl5OpMVZHiWoz81HB7kbORMLtEopXb0rJUV/qGGkKKncUBSLq40/Uqabq\n5RM18YPkIhQDkWMecYqvpbElMWpnZKtB9s/RK/pB9jGMQ5jXV0WzCk7czJRo\nV9L4nevdRvr4d+iuSpTJiseAvQr3JYdpJbXvJ3f7WjJB8xBXTTU+siIGX4Np\nllaceLxag//wwYlHcwJvyp7jzpLOII/DEY1KBOo9nqOYbPdWFeFLCQh1KFBo\nHPsm\r\n=OtGG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFfSwkD9GeauuTqaQPv5Wb+MlB8IXx4gFfa5NbUvSXwKAiALPZZFpbhdnJyUTCMwRiLo2Puo6nRXkOhLUQmdnCWi1g=="}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.4.0_1601047513048_0.8479920454563463"},"_hasShrinkwrap":false},"0.5.0":{"name":"@synzen/discord-rest","version":"0.5.0","description":"[node-fetch](https://github.com/node-fetch/node-fetch) wrapper meant to gracefully handle the frightening and confusing monster of Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^26.0.14","@types/node":"^14.11.2","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.9.0","jest":"^26.4.2","ts-jest":"^26.4.0","ts-node":"^9.0.0","typescript":"^4.0.3"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.2.0","node-fetch":"^2.6.1","p-queue":"^6.6.1"},"gitHead":"61907d4e4fce75672b8e1af8d70ac5cbcacd138e","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.5.0","_nodeVersion":"14.5.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-c1BBBffzmtpeD8Lg802JzCyTCsGg9oBQov+Kg6VdpDoLaJ7PzfHzo25tpjZnwxGJbQNbRUDOFegChf9C6JHzLQ==","shasum":"e4af8397fa7ac822d3ace8cb990bc728f3cfd5ad","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.5.0.tgz","fileCount":23,"unpackedSize":84802,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiM4xCRA9TVsSAnZWagAAb5sP/R7QMl73WTDNh5Bqpgbo\nPdSDm7aZdUHbM2xShzJqVKIbMI3JtoFeBVTymm2MXMN8VKVclN1FNN0q9FwU\nwzYEkaOf4a7lMchEAVQqTJFXK6rTDOluHicycSnmvON99jqkM5CacGC2m1MM\nT/qbmrxuMmN4UWP/XmOUYLWBnAT1zKw4QE0hliX0kRRtJcgx4YwU7aIkN3R0\nBZ6m9P+YQaqjXAbTo3OJqUtx7m6QHCBkcdixnLWZ8dgHHI5y0D7tkAcRDqva\nmHYwCWsizup1GPPqWHNErV3euCWzYIXk5pfekgz3km9/MG/QEf+LN+RDOuhP\nTKXD4u5ccC5jLmP01l+gBg3Q54T/9XwttXvkpM3bjx+YRut/K2YABJ+Zg/4N\nu3qOEO6yClB2ZEwLybfMsFaBLZkK7x7yGbYRC+BJPj6LQBzVpigS8gYg24Vk\n4tSQohB9gNg2OyrgNN9cmIyyGi04Sby6a1Vga8Cz61+fmUbOhqCcPNFs/pl9\nnm2Oc2O4AtKLb+2+XNBioVSevfa8T+Kxeye6ZmKzDDLoQfcTCS8LP7KZ5BDf\nbvcnLBwebRRWr/IgzG6nOD0FJKRgXmD/kg18+7UOcE2gVSCehVw8CMkMv7rk\nXk8ud3gfGjaG++dZXKvJwvhqZbSWfidFeFlfpSiFdOWj7aW6Ky/CcrNc8lMo\n0GcW\r\n=ObBZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID18QOtzLY3FWxsGkVsW45ZbU6etlNApngsQVdXdunoFAiEAnEOeSihFGXxp/gLqidXnItpJbKPl9R33hdSxBM1F6sY="}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.5.0_1602801200687_0.5165526292125979"},"_hasShrinkwrap":false},"0.5.1":{"name":"@synzen/discord-rest","version":"0.5.1","description":"[node-fetch](https://github.com/node-fetch/node-fetch) wrapper meant to gracefully handle the frightening and confusing monster of Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^26.0.14","@types/node":"^14.11.2","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.9.0","jest":"^26.4.2","ts-jest":"^26.4.0","ts-node":"^9.0.0","typescript":"^4.0.3"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.2.0","node-fetch":"^2.6.1","p-queue":"^6.6.1"},"gitHead":"af7cbc366290597e4e073efad04b38d09f84a3c9","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.5.1","_nodeVersion":"14.5.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-rLG7CmFZ/V27CZrxgNgsOkclkyC7rQBCRajjKHRqHCstazSSYu+2H4jz6VnEBkloubaogySZfFjqhn2msXinPg==","shasum":"51f4aa625f5a545b1bdbe191521958d8698dffe8","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.5.1.tgz","fileCount":23,"unpackedSize":84943,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiNjtCRA9TVsSAnZWagAAU6MP/A/ahBun/qLwzrwWXPN/\naKXMRmxcG+tI7XTeWctL6bzukEacEj7MSYl1326TwOZlkHXlR4mypxrTb1Co\nkuV7qgrzNXflIN9hYNBk5BiM6mrL6sfJuZoc7Xz96lqyB8FpKzxReRN6HfwA\nIdgdvI4HDto653N9GXhLEeeXpJHwBeCfIU8AToMHgWK2oySOb2JDV+PN/pAw\npUv8A2k1EL+Uh/PJEGs1iOl9EQ8XET7hsqHEOe4lFk6TKn5eBwl0GauI2DM0\nvWcLlX9L9eY/coOdHd0ZnGcYTK6zgd2wuHhNQy06ov85mANZm8LGoG3blM6R\nSavt8Jed+U+ue75/qdFNRr2fd2XhWDvriJNsPyrAo+kr0CzbQ9emDaLOHeBl\nh+ephPKg2m5RKiVTKqjHBbIXmEkp3k3I7+EoeKBRR3I4dw0fBcU8LpAb70N+\nZKaT43aFH0yZKgwfpY0PsrK2FHvOGBuGV0BBmGbWibSf/363vVxvRIRaNG9r\nsziiVv+PopIrOPw6SkA223+Z26gOsotyJ6oCtfvbOgv53b4b7/oEESV7U/EJ\npQsgTAx+84IXwStLE5CJj6zuLeZ50iAsE4eqx3ZdxTBn0OVkNB0hXbZKqDVn\ny3dY6O7bhBCHhj9m1Hfsj2L8aFRPvbR4tFMGqc89eSS+r3beOv9fFx8Xz8Wi\nTRqo\r\n=QqY3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDEvMRuevtFnuQedQ2RHUNGtabLsAOZADyrLtiLppBt9AiEAvKu9U9l6w6CenY/W+zJVpf43+sEo41ogShc6LPI/NHQ="}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.5.1_1602803949292_0.7303215020462162"},"_hasShrinkwrap":false},"0.5.2":{"name":"@synzen/discord-rest","version":"0.5.2","description":"[node-fetch](https://github.com/node-fetch/node-fetch) wrapper meant to gracefully handle the frightening and confusing monster of Discord rate limits.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/debug":"^4.1.5","@types/jest":"^26.0.14","@types/node":"^14.11.2","@types/node-fetch":"^2.5.7","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.9.0","jest":"^26.4.2","ts-jest":"^26.4.0","ts-node":"^9.0.0","typescript":"^4.0.3"},"dependencies":{"abort-controller":"^3.0.0","debug":"^4.2.0","node-fetch":"^2.6.1","p-queue":"^6.6.1"},"gitHead":"935c2d1b590f4b0b7f1ea695d7a49864be2948e3","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.5.2","_nodeVersion":"14.5.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-XkHxBe/YXefDAyc8Fa+14/JwcC27rP7oQIOAB2KRV+7wLvkl44rLaUnuhO+e4A4yzfI76XCAJM8eXysvCct7lA==","shasum":"e7f0612cc4cc05ac2f517849d658bdbf055acba6","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.5.2.tgz","fileCount":23,"unpackedSize":84978,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfia1LCRA9TVsSAnZWagAA8+EP/3VvX0pkgtu2wN+9LPvE\nRpHBAs2XIP+isxk4ZY2tZ7QzaF5AODyQ+xHB/Tvsmgd1BefTkm68gZq63j1/\nTR87fMJpzlGGj6nYY2GRfinF52xL+UABvWgczmUUGzBru9sVw4IkrJQw03+Z\nCNPKHMtUSMr0v/ZYgNm8sFyhq65O0RvzE5/ob3cu76SzhStjc9SEvqjdCZZh\ntCShQwqMc49aQ6Y77naK5MgSupb4IoyPTapHz8CGdxF+v4Q80bqlNezsjpsR\nL4+odku7hfnLuM+qIba0cVjcjJ4vBG666rPvoEuSHyP+yYmjP1dOLrvmmKRR\nT89e859WgXuDj6ztlrHkzQerW9PVKx4Q7e8XuhweCGtYkffxcuqBO9bqFO8z\n8o+ae+dG17hDjSbCExvbNrvReL7vg0LII2EeMtineT8butYb4IFkpmQlTVRv\nv17UKOOUqWxgIC0xSMSrBTUPbW6aEpCtOrNVd1NXP0MfHWLdkGxaS1/C/mNk\njYPep5QE6WsGwmwfl20SZsgKdNkj4T+ECkmnVRjkS3JbRZC/vB7qYclIKHtY\n4SDeb3Hnmsfyg8vB0weKTSMhVnExljN/QfSS6DfwSqAd32Zms+nW9fYa4EmI\n7T8NbdywfCVzZcmIoQ12skvA90X+AUGEvJfIIzFo1aI8gEPrFVv3w9QRLY+6\nbvXr\r\n=gw4v\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC6Zx7mF3WjLnNxXV6FFgm40R/4avem5XzFSsgi7HPgXQIhAOpLTm9I3EC3Tz0QPWPWO97L0wrdyJ/XDJR1jS7YAKof"}]},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.5.2_1602858315148_0.21310890794621296"},"_hasShrinkwrap":false},"0.6.0":{"name":"@synzen/discord-rest","version":"0.6.0","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"a1ed13b01f7e8e2327d0fc9bf478136e793d3ed3","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.0","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-UzlmdUrd2HzfLrrbCJznHMFIhpe62n79lDbw0470mihqw1F5icojsYtq6oHMkhTdzeEbQg9YR5VRRVXZ1Jzi4Q==","shasum":"f18ae040c4d13fba06aae34469c87759a72da912","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.0.tgz","fileCount":25,"unpackedSize":84583,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJghuGUCRA9TVsSAnZWagAAjaUP/io6Bsmp4wwcdVacesB/\nqpQrjAMPsUY6rDdFASBgObBPXlq6uzSRtZI/d2RJFMYggb3P69QHsbER5RK5\nKUdFrhjZWVruYGs8v/bUNs94Nza26e39yuU8wlHvEXpPMzQmD5YMqWq60MKp\nTleVsehaTPKau+EDhNZJZvbop7LCOV6agZRXsQe9knLYBSxAKpK+z8aOBe9V\ngIMQjIN8xoBRIq7pcu5GOlXUB/UhBReVEytN7lKlfQBCYLR+J3Cplh33FKN2\naf2HJqxLabKJ1AKlCk2+ue9+aB8BMOYI3iOeqLkAdssiO+J+WjoAkOrRirdH\nq+iXv1NecmbhO0bIj8vzp7ZktrL92vVGirGFjWQ5C4yXYAbMJbQZmjLOdy4x\nfyMYC3H7Pg/AO5BRngqCJsV811iTFVEpvwF8k3trdS9DIVieJELaZtFI9ExU\nh7EjBrHkJ1PLBzunVv4lr90T11Cff2ODZggK2rv1ac5zchN4bxaxodZM6qvT\nja2xBiNgEh9RB601dkIK0f+A8vTsfO3HXKxJIvBpFNAs6ZADAs3nw9AZlXB5\nggjH8HlsxjfQbzOK396LgoMEDPxDkI3pYSNqmzhZWBkXny5ZaeEYHqwB+JKH\nCuN0armagVq1Qe3lKO8Fj1gp5CreOVrIKeIIzohR2kdzXmrY3gnGo6UhmUDC\nuKkZ\r\n=KQdU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDaMvCvWkThcmwQex1BEmLd27OxftH4i0dbcCxkVpneqwIhAOOblLbjP9fOVMGCedDTdcPk82HXj7358C4BzPaKawZB"}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.0_1619452308080_0.22458918951481976"},"_hasShrinkwrap":false},"0.6.1":{"name":"@synzen/discord-rest","version":"0.6.1","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"52ded083ebe40897cdfd99afe53b60caa870584f","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.1","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-n58lxkrykukN//oFHW8+4HebxlfWGMjv1qvM4JmBhp7R4K9cBVZO2HOjUT2LE71o8X5GwU+0dcW1jVdb2udC2Q==","shasum":"6f287e6257963db357fbd0b999b78f00ae485d0d","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.1.tgz","fileCount":25,"unpackedSize":86006,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJghxbiCRA9TVsSAnZWagAA+fsQAIoGwvnEDmHmho1fhOpz\nHCuNcVjkShRQ4DQw7KJHi3Um5h0NGwJWeJzQG836sNM+NrD132pCMBmYFvsG\n7O5AfT+fVhrsqFXlhJhjBM/JbMKbuJ8tM53V0hnaltaA5IZPvMS86tiGawBf\nB1zr7MBxtktxyu5OBnzukzli676ZIjzzAUgzb87lKQBYiU19zQdEDY4rchkx\nTYBVQB7xfQjJBUzGxa1F4se5FpngSz/G+NDaS6QclfQNox43rDE/heVQevTV\niyT1xB6ddSrngpU6YBHGj9ePgNbRqY4TZ93MmulgwvOtaszwMDdQJppiWThO\nEhbYbWoB3pgtoRU6wsSCmd29G0jfgH4oNnS1zmnzx8/uooSYtiGYPg1FtC2y\nTKhbZWZ7qrbRl/wQQXqCIYHRzal7y+XpVC/W8jQVo9u1rY0edIQ4pvHoOpKI\n4j02dYEoRg2wr59i4VofrbddSyhdU2iNrqizwBcaGzyNUY5JFhzD/iyn9oIW\nmITfOuXDMbvEmyXKYQZc4Gldsp3FtIuNCbeyU6l12nJvTkaRVGSv1WBpP39x\nKGHKtq26ChVTje8AJLLSD+JYC+ezdrL4pkte9DmrFiXTB3ENmh2s6F0MDZV6\n/WhKMt86C2TyGHO+gH6SaRIKNg65SDS0ElHqGlFZ0TqBzRHpR/O6KI8ClZR8\n9zdf\r\n=O3ej\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC3oI0mGsPI8OJmoSwY1ziN13fwIq+FYtljGq25+g2H0AiAqqqWx74K+r9AlPNN2xHDM+jtgUY+1X54vOJ7rlVfWFA=="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.1_1619465953850_0.2839942301444427"},"_hasShrinkwrap":false},"0.6.2":{"name":"@synzen/discord-rest","version":"0.6.2","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"65c47d28d6803b6e136fcf2c875ccf3dd86dec5f","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.2","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-H/SBQcihqe49h5FT0wUyP36/M6nkZbSMLN9uPAq3xOyXdfywg4qQgEb/dklEvnC/MQX08AaHXCacR+ofJXd3RA==","shasum":"ccfc4333402fb06483134ad6d14fba6600c303a7","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.2.tgz","fileCount":25,"unpackedSize":86058,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJghxq1CRA9TVsSAnZWagAAsH4P/RczR97S5S90bmZlxudz\nc3F4bG0yOb7s+MBDUmj6p20LN7VBME6HqIgQfkR5VOsq6FaVZtQE7yFCNnJf\nTd91twAbouAmnsy4cbHwTEFZbZ6//HwOiYGxpE4F1ODyVSV2rf/1tAT+qN/N\nDWeZXgVHRrfQjnGaUBEsl9rdhv7UnOIRUk9cD1YCSqyapVFyPcFiwSgU/fwZ\nZuIpBukpPF0bJbXBJFk0qlSXzwZtoJJUDRqU7nuU+YEPNFjb1lmYwdoO0vVs\n1TgL35ib6svtnBYbiigrvOtLOGRHnGZ3VOSFrQfePpzAp4uqSVmD3mxdqQt9\nPnHoRyj1EIfDqAv/b8N319dWfnDrFk/KjxEIMVtHByv2vK3YnCYoZGK3qn3y\n32ynOm3l1/Q9aBRLYxSc0JupuRP6lUyQorxQVSLSI8C7tkDapZgYjoIUOQlR\nm7gZ+eql050I2t0yRRF3/x/syTfZjZ7ENvR9pf7Fy/RZhAAvTviSJGI1CDX8\nb5Ra8y2B3LMScznJOSoIzw+gjCcPN6lBT0hYn8mus4wyqLUIWN5yw8wEyX5d\nQ2wjR8tyCgwSec0Nm9GJCIibg+YkRXy5lwF7YTV1IRvoJo+0Tj8hlCxgSvn+\ngpv34LRk46FIKzkpzP6BOhy5i754rVgkw0WW5L/INqoU9TbeUetqW/dOynRC\nVh85\r\n=FvZW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDKq/+Hn048JWmDDgxF4aTMrgUiCArO3a1IZ7yaAEhLugIhAJw3fnfL38zMX/qVoOaV2tSmn7basY0/ePWxkBc85elg"}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.2_1619466932881_0.3874651907585316"},"_hasShrinkwrap":false},"0.6.3":{"name":"@synzen/discord-rest","version":"0.6.3","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"08cd79dc3fd18cf4e9214bac31bfd964e173817e","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.3","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-OR3UppxQqcGwkb62LRX3udHhItMJBkulZlIhz+bBzAxTIg8FPl9hU+CfBelCfjQNwTWWTCn0zi6S1G9N+mn4EA==","shasum":"805b0fda12e9cc6759384798842f243a7f5eb116","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.3.tgz","fileCount":25,"unpackedSize":86510,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiLWaCRA9TVsSAnZWagAAAf8QAJzYtRh8qfmvT7jjgsSB\neRXIZ9YTEdhv4HewgGV4hctvwVCEy89ZMa4MbkX4bzFBYhDk998LqZaBfzE7\nVpIuCrQJtSoYJHfA8zSQjUv8Ve/QQZbHkwoBdSHcdWgizzfUCn4bvcpT5NcF\nouXd/c9O6JtaENPhYwx+bdYqKQTtSzuZFo2X86qIaAv120+GjTCqfYcz7N2a\nhe9EwNophQ5k3tQ/Gb7suStG20IEvXBeCKbCgdyTd2j4rFVTUnHq0X4q6hDv\nx/5dn4bLfkKh1H5YSvIvO879+hqbol3cBFbrmUJblxwbQrv/SqVPBjGOSbFU\n1trFrQx9W36xPOpBOJesOPWsHUb51r61n3Zsy1OwJoXjwxF1dKn10XCCW9VX\n2jwLYa5bna7EfbiJtRu/JbsZTQh3bjnKHbGdpaaGPz54vGdaehWAxg2Rtp4D\nFuBwtd+a5o14oAJFEUhAAEjMKmV2AgYG7QmqP+bJXBdOkxMuz+7Jx9LjDjhw\n5bzxxkBb59zlNHEXfhVQskYTngLQVRebk2hsw9/Di/uEbWp3uSGTKtmtpq+6\n9Ukmfd5bJqi3thGy/ntGvY7rxB81KEJqIvim1BOJwdoz4ahWk3UkQ6P9bO49\n04mhjYy2woUe7Vdk6x1tVPShEAf7B5UQC2AuBvBpC0Bm1+cQQv1czwVU0VwD\naAyt\r\n=fnDH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCQCR4MsUN34+uuRZ5umVd0heeK5PrHgaMPTebvgk/dmgIhAJNlmtGVw8iQ/I2DobfXd6/JATVApK8popTY8lnXmc6x"}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.3_1619572121974_0.7762726570652998"},"_hasShrinkwrap":false},"0.6.4":{"name":"@synzen/discord-rest","version":"0.6.4","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"12ff949c01cc4c9aa3e52f8d78782f716bf169b3","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.4","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-GrFEIziDWxypx/NwBiaFA/ymfKLuwr/nG3j9QGQFdNXgTuMrY92YaK06s5VlgslSKtSocpca7OslMc5n3hdB3g==","shasum":"643b14602717b676c945a01a94a7631fe8f117d2","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.4.tgz","fileCount":25,"unpackedSize":86522,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgjhiJCRA9TVsSAnZWagAAuM4QAJoUoVKcDHmngXO0dNJP\ngAA2K9fOWQwi5Qzp1RxAjkY2MjOSknEmBtNNDBzM0KZxSekT5ZJXR4QZOLLy\nuoCDHm64Sw9bkEk5DoebSkzvpp4lNrmM2cvcR71tiM3Ua9TvtoNzFXzLhnH0\nodIgChSWrims10Igi1CihmduEH9G02hoksOJ/C/GY8fVfuvkO9H7dG96dbSz\nqOg72Y576+gdZ+Fn4PJh7BCyL0Of9BS0Z3Ex9cP3XzWY20vk16L9uTZBPJK4\nSz5gZRxvjqnNX9oY+dxoXoPCxBE3UuHMSQz2n6N4ptYllJQFUczp2D7dUKvM\nKQS3r3sbJbHFqqLU8Kxo5T8foq7Fr87YdQiMNDDTrVPlfcMNnjUwquhvpAh0\n3HyW/ywSdbV9QXDca7m20bn2NYbiRNiosHqDPVsfk4R8vDEM2ob5CEQiq1Qp\nxn8QlDEnuvIokFNT4Tm8uOZ/ARyamQS8LLr9WzZO7nzAe+HE7voSZ+UO38aJ\n13XQVbSEvCelHvZ30xGs3lBvN3KXg0cMWeC+2raNuzmALBsO0FqBM1cHa0C7\n+QMgg2CikB7v4dZvoumQArAW7t8XFfB8deFYwede04RkPxr7rdUh8Q4VVZKa\nzKL9QdrHbLIV9gmEpWSKD1qLGdQ8PYZ6iV+K+Waqq8dxyDYnW0RZ6huxTbJM\n/BSz\r\n=CpPm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCxLNEu+nzZ4waRVNe6LO5SIvbxYVghcJ+oZnbzcnycnAIgdCZ1yVZdMxaa9+SGWKzhWr+2WAeZIEeiukDArKCQSsE="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.4_1619925128629_0.6241724324809494"},"_hasShrinkwrap":false},"0.6.5":{"name":"@synzen/discord-rest","version":"0.6.5","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"7495b6a9209f110885bf2e64cf08058c6c07fab3","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.5","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-yqFD82Tttz1bH80WWD2tQa003aZTtwZKQIIdtrNKycxqDN+y0HXtRQNeTC0V6r9oRPorTVRUcIJUmNRLIW012Q==","shasum":"9a97b880c0fd396be3fb07353323ed0726d24343","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.5.tgz","fileCount":25,"unpackedSize":86505,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgjsvUCRA9TVsSAnZWagAAmhgP/Rm1ufkdKptZmszv511i\nhAKUrdgLGy/EelYAU3+pN5dHpiOqR84DSwb71yxdC0iye2uXjKyHM5V5jZr1\ngwltRH5eDSAdwnqyCg85Ro1nXobMG+rfXJEN6YMvjmWg+IzSw/D+8RN+/Fdd\nHmpDHbA5Q10dTdq3Bxz0lPxQhYQWWSs/76YNzEEVBEtvpWmz6GVBUrpMdVxx\n1Z2b8ayAm6FTa+dCf7UrEY9cP6H1v5hHh4jod+37n2TP7E2qIKkNnS+aL6du\nDy9FCS5VBL2fUqHPsBbIi+ejLQiVKcSTeMykCkQiJZ9YOwJYOhVspDiG5LVU\nwNXaih/4lurAMKXJRl1GwyUt51sgo4OjcVzAsMWXI6azyBJE82Ku4CnHPcnP\nVQ2R+orHK6WVTCwglVsAXN/L+ScPoUcsEL/J252oaPf1E0eibAIW1AjbeEys\nd9cKLDTqG5lEeOHhg/C8rRBHiCF+zLNybbm7J8eXTMjkONVYN3HC+awfqtz2\nzEmLpatcJ1oSJ+GMwJ+9iFuNelFa9t/HasRZlXt1KtGP6sv+OiWId8RO0mgg\nBxxNtxbgfZHPMl0xXfeXbRH07dY27oYtLkB5btvP22R9A6Ugk0JvOtN155D8\nkYuNkeylqUFiJQvfJsinE1oZaOE6PZwb8vl3/bAuILxFM9wH3PHmYzz6IYYB\nJx8m\r\n=ZlaL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDEnSEz1KKHZq6RIxAn+D7FOU8ZtuENBhLJKA6aeSKUiAIgSp2Lcn7+I+Loyop47QXFW04dTkB6gOA4QtUTQU7veN4="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.5_1619971028285_0.545836767428376"},"_hasShrinkwrap":false},"0.6.6":{"name":"@synzen/discord-rest","version":"0.6.6","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"7d2d108df11c395ec1209f3bf379820d431e935b","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.6","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-3IClmYQ0m2RiNjmgQFU0XL0/3JHJFRoiTPezkneplMVy9nW6H8Xd51bVzmYhpekst3IbhgN5HjCT9I/s4O8q4g==","shasum":"c33e1ba770109a49e21af97a83afec05d664ab20","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.6.tgz","fileCount":25,"unpackedSize":86510,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgjtGACRA9TVsSAnZWagAAzXgQAJNQswO32ZGU9fAPdQFQ\n2NFHcONVytln4zbya3+kFD/aF2AwInV6LRix7gFMkzt9P4xoG7uCjk72qZHj\nj1FAYgTPOyhIcPGTM1vCbPASv1rqLre7W/WA0hsqb5mejkTbA4pZFn5vI5dU\nhcGCXGIdUCpM6LQlw7KC3w5DZYr0eM1K4BDx6v0vlpjw+38XQK3HcttV1C3o\n/E9KGqan9uRdR/4GGQmG+TFqIsgDNYknP6RHK85uv8q6G0ddRTUKy7+KoIRT\nwRBp67hu88KNbkNr+ZEDr7v/DNppT7Wodh7bu+TB3RSOgdEfSuw8lmRvCehl\nYcDZRLXCz7MiZWrr9aAQqyzYfMNsddmkL4joJ+ECx474oI566v56jE+KkSBa\nMaCAZFcbmwD1sx2L4ESOJ301c2LizL3MEeMWtNt8QLmUSfh+NQfj+gLPk+56\ngaX/Hu7zG3J6x2peTmrRUWnj5PMQSFE3LgqVn5bqP450vI57rTWHBlx/jBux\nlgcu79JEcDayON2UF5vsQG3zDXm6XbSqVBpb2EbHcZSiD1KhdSPgHveh1vX6\no/mauoef0+rFef6BZvgNZqQ4QmnzFhg2HwJizr3lFunEpSU1gtm253eQYbtF\nA1zmtG+Gv9Z2JgWMghUlwwWcHzTnIdRX/Sz4Db8rb7ocvyi0LWXU+R6JVSXb\ntbIX\r\n=i7dX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICrpg7SssqJI8DtoZpxnOEb+bNmqjTtPnnYHt52bHF5xAiEA6ic2v85+IcRDgEhdji6SpANXm7zNVvwQI3zv+OI3BEc="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.6_1619972479711_0.09006874480641991"},"_hasShrinkwrap":false},"0.6.7":{"name":"@synzen/discord-rest","version":"0.6.7","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"531d2e6645e3c8c0728f125915da9d7f04d185e2","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.7","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-VQBAEGUCXZpRHGXSUX1SXdSQsxZV+TC1HCgKE0YsNeoOjes7NGXqdJfIXYfgvcx8ejlTBKcig57hx76/wB1WCA==","shasum":"dd05819ea8b81bd7332bc191134b50f04f4e00f5","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.7.tgz","fileCount":25,"unpackedSize":86506,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgjtNxCRA9TVsSAnZWagAAh5QQAJ5cEBrnETfW6VAfrsIb\nyP2XwFht4FanWZrkW+iIbFdLOwfo3X9fUm/SZAA0pP8dRuDHIauWsC2aWXIV\nRpF0xSpt2d214JIj5i3gx3RwQ0DpbgWC5GTLaykXE2RdGtrYNQjTEIHhB8Va\nwwv0wXUiEqRqvTha4ZhSrBa+QgietZyJWRhSsjKKsWzaiQyRujXQwJMwrdwf\naEn2bq0DCJKwC7WR6KyvSR8Gq8ihvqpOAXkIHn+/QIViSCQz8cyI9nY4Kpl6\nFh3D0OkxbNNGFuE+3wE4fwEknOhxf4ZznzLlgR3H6YeLmx0vhS2LJKZo6qiI\nnnkKXPh2FG7aJJxUSU8sWK2WSZFawn662ZVT9XgalrBjQhu+/gQCbn6l11/o\n+F4W9BdSmL/qVgdau2DdrpeHSAQ6kQnLuhyP9nrtfov8Pg00GVAa6IMn3X/W\nTE2NOGJbFmdiRyK5MzbltZgZPdBXBZg73Hq4hY5RNsuqp8bBQpLRqmaHCYb8\nigaP8z4Bio+Qtz4ueLbF4Bzg1jzVdjlOn7hdR8NtK33MaZkLTdZMPMElHXj2\nv/ZAgyZYf3bzheALG4k4TVYbkdGhN/ynY2LhGQOaJF3zArUXHvJS1wemKPqh\n2wvyTzoy+wBsKYWHPfueAREp26exI36JvpjQGRWQxnWHEolVRrpzmdKLz7nL\n7n9n\r\n=48Tt\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDfr45xoM0JsLW+H/KVXxBJ5mN6tFr208MnRpCMxwzW3wIgS6EhCG5QdLc5DA0jalyCVm45esjv0VND+85W4dl8auo="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.7_1619972976939_0.46643218050816526"},"_hasShrinkwrap":false},"0.6.8":{"name":"@synzen/discord-rest","version":"0.6.8","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"bc152a701ecf552c12a34564ec0f0ba900bd123f","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.8","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-blOg2bIz+ZlABwWZ0ewhDizud2O5qwriqGKpwJpdlxhPZKYuzApkJn1boiH0q2hDy7tsx/PAIu2sKqeSfVthqA==","shasum":"c2eace44e112b123ad98813158b3cbd8cde4414b","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.8.tgz","fileCount":25,"unpackedSize":86873,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgjtj8CRA9TVsSAnZWagAAkhIP/2/jNrtTHWdpR9YXL41h\nBaMelkeTXJQehU6av/qgJoyW3vBzgwnfylvhYOnydPA7K8Xb6O+XIQL9ruDJ\nvz2Zct65mOKNM/IdIAK1XMjNWydeXcfzoIWZviHgNH0nZqMuBn7NMfVkqV86\nfHk8r0+qfPkI3jd8CTk5fSsCWTp2yURLqM6RER+UYiHOnC2eHpwC+LbHNUcn\n/G9lAOmkiFsp/ndhj49Bmct1PEexB22cm3LGH6nkt1iIKFJAf8HuSxZDZlVX\nrAPQnAOkvnZj5D09WuMr4vHl7uViiwp8H8MGPnnFHO/1qxf3OL0LEx+HLCQ9\nsorxt9H9quBZHaWOclQVS6gbLQoBRt0HpOXOM2QZHVoByS1rcN88H4HltNdT\nI78w/TOJor/ZxvZqIMPB0eDaXIIhUYnysYKEt2yGlSk9M0Kh0pdKYmg4Yt5F\njZiViSdKKwXILyqxjI+PVhdG5mWiujsZqzoMGGFFC5hnQuE42/rT7epF+0VI\nZM4YAkIiwP/ol52yryGCsR5VaTsDyHVVFZmFZYk4Lj9nZ6FKuCTO06spMZOa\nWHlKkmD/kBnYeo/x1u84SxhPi0+ejsEcgjeRZfg2zjq39n30hwJD80/vVFB6\nwVCu+1hkB5mrJpQ3r5C7UmT9AeguhZWDNEA0ypcPRgHkkRdPt7ziAxXSTc5H\nDyY4\r\n=LFMv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQChnDzjRMrtlaMBPW6h1jtyr1z5q586aF0pqVQ+okeesAIgbcO1FJ1oZX6Z/rrbJ52Kx0JcWqd0wr2Qeo3iF2j62tk="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.8_1619974395477_0.9614116845794201"},"_hasShrinkwrap":false},"0.6.9":{"name":"@synzen/discord-rest","version":"0.6.9","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"6665efb8c3b7517307532eadc3e5e22b8d582146","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.9","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-TF05mTaWK68xK1H61VD0e3c2myTWQzxfjCU6Na3YBLNGWMQMPYZtksqz5ugb40lpDSHdiX+urTyTCm86Uxemrw==","shasum":"91c5479827b049fda128b71660621d80ff056562","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.9.tgz","fileCount":25,"unpackedSize":86872,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgkIiQCRA9TVsSAnZWagAAsPAP/3Dc8qD4mtkkZeCa53pu\nn9YLC9/ktQ9ZgYhdrbw41ePO3cXsjq42ZIIHzIiCdY/fsohWjX6hYCHfaKBU\n3haue6WyRK5vNqByhXvcrT/biSH/D92Vj6ecJAltMvqxXoGGTzvFKuogvx/Q\naAH0D7T0RWMhe49yEsiPlCfCgsmrlQ1t3neaQs57kBzNdhmj2lMCu3YyUOYA\nZ5btJQ7FQG+Oj0FDCYOlkkY7l9iYIE7V92CzkOPFmZn+UpCYEGxk1PE2eCUy\nbLcbrYU7jpc9BuTbKc5a6qN4YHkPqUyTYvuBqdZ+Wn3Bz7oSPDSgUkhtPBV5\nhOVTG4tHlxbrSLnmk5sJXuEQLzsth4qCuAUD9C6Zwaujz0ON2GIgBcV7MiIp\nSmpUV1aXfZg58utjruelqqY1u5fri2hezV1AoOQaWAzf/g/Kbpc+dEd1X6rw\n+1CNnGezGVU67lGrQ+L+YS53N9TPbWJKnzVMuaSoovQZjzL8uuPzocOVNUT2\n0fO+rkEb59+xgXi82SUGnZnv8bd/Tbxvh5BnSwYig6lJgSjrvG8QkOCaCSHO\n3SNYJD6lgPxojL5suooumLcrAlKPI9nUmaowbpIaSLlqAZkP+oTqeJSQEoHS\njlS/ejz1AMXQFE6Wo6T6EkqpFLPHNcS+vT3hgblMpMVyGSCs8y9UVa5+SMay\nNBfJ\r\n=iJeS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD7bBMVLwwWRePKe/JY3ZIfGDQQAeB7zuprjQXyY7jfWQIhAIukOfC+lX9Rm2fGfC4v7ScBNDUvxMuEcgJX6r/NjC7G"}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.9_1620084879963_0.10781682769161538"},"_hasShrinkwrap":false},"0.6.10":{"name":"@synzen/discord-rest","version":"0.6.10","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"6aa355b67afa4130aaad7d401bfb2abfd2255976","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.10","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-NtN7Dt94OIs5DcpfM1O/twrt2l7OxdkAXS0HazhmqswRKzn9YEEKUYzdm6OVoaHbCPHQtDRl0uA+H2GYcko+cQ==","shasum":"d8b67bff70d57673d834a98f5deffafd5b75c493","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.10.tgz","fileCount":25,"unpackedSize":88166,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJglx52CRA9TVsSAnZWagAA/OIP/iGWnmDwZoia1cXggWGx\nPUOzO230zxt5i1pK3vmpNsGEr7On6XSZHMyq1b4WNoqf+7xO0D1vtbSb07wr\nhqX8ewuzXcAQ28eLRlDp4g2Nz6LyX01n99DSIEVdfXskI1c3MjWAkpvxboAi\nUiARgAjao7w4p0q90g8HIbv/lATeY27TcrltluoWymxCDMM3d5r3hRvCSYEf\neyhKGicf3o2C6yHZ8Dek96cLYpxkXzVTP+lPM6u13wGZAQksM2PWLyy+zoe3\nddDT1fAbE4bznbnmSp7jFWmVr11IvSMNnKz0H9XC49R1REIW5VQ1FRi/zJ8e\n4N7nFLHEr9LRaFPM9kEUBua7y8IoMsYtP3S5SzlklaAkwqqh51MlrK+3sJEP\n0n42MjWRbQGhEYSxRjURS8Q8KOzSf8CoP2t4pA8gw+CxxSwyzF55r3CDBD3p\nBaqmP4T20Ym8YhzKUh+LAICgqH/FvC9vAF+Isb3giWTtCuO9Wul3tzqoJEEL\n6tnSBFosQBTPy+7w99CT/WnhPurdeyKjpbOpdfCxjvMTbtiA+uJbOwMaUX+4\nl7EZ6O3hwVfYKJoHsbJtvdiEZkvUhi/KW0ID0MdVPuJTTWu1dps9yVDfA7vW\n0VdFtYrQaSDzrKeuihgzuxcGcocAN9+twbHV0Q4es7TNSTiAB3XLVoHcZwKK\nLsoK\r\n=BIrH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEfzA4aGLzfZxYPkUpxjpwxcyUerqjlIC8Cva1fzknNSAiBZzKkevE03UCdmWnfDv5wryuLBd+xwjSE6HvlSLihzGw=="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.10_1620516469541_0.08690956468371858"},"_hasShrinkwrap":false},"0.6.11":{"name":"@synzen/discord-rest","version":"0.6.11","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"2348b9ac829044671c773bad78287f595e45b722","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.11","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-xNANlxuheN+f0jxJgWac/XgiF8DlvoCfwicep9X4HKPewwZx+LycDqZirBl64bYjHOjiAQmSNMPZyu6Vbv94PQ==","shasum":"9a44babdd89347032f6ee9f26b7846d18ea56094","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.11.tgz","fileCount":25,"unpackedSize":88346,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgl97VCRA9TVsSAnZWagAAQ/0P/i4GKh7IK/wiI6UgFCwB\ndSSWA7RlefCW7NJ2hvBk5ZIjwurs64hh0CR64XpLPqK4R403hd79qSv79tTf\nzKnKO6wqinnYkVusvaSOsMx/jDKWiIC0EfAcAJp5kg8vvE4RBF+xsgoz7aRh\nbxF+VlcfY7mbTv4KMbK/b44FOW+ljfQIWjMEPvUjDZ2uFTghYrYPCNrKzV7m\nFloA6fzEVqtRE8NFN1hwvFTNMPuGKjQqDooMmQ+TG4Q/xO4jYK/2x8wx8vs8\ndJgG53vs52nmFBWufbbEun3YI8jN7heg4NgVpoVwF4wFZnOyEt699GRB5PAF\n+W3Wm3/JdIhhPeXkoor/haWSFAgVWSOjHtZn/G3+aNaue0crvK9quw8f9PU/\nDJJwUXMjZRUaOd4RudZlE9PsaZyU5oeEtnWott1uGPxwuPfZtqaVokKhclEg\nxd1gvZTQfiyeqEG5xdzt+xl/QV4y93e/Ozu2728bRtNs8H5/UNsDP0zbG2Sx\nmDJlXd0Y24J6TIWlhHcRtxhy7S81evhDLvi7LLoCfwoFJ3sZnXWCHxiVS8Aq\nrMshEfftfFu2lqlKcG9p/oURbbqlhX2+vnzgmPsaIXEPpLKgjYXuK9VqzkEE\n6DIdZwjXDMIa+lYjtY/Pytjt7srMcC3f/8HRFsuAHRwP5RXb3slm09+QCzCM\nUkJ2\r\n=hDz0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBpsEP9g8cdKGdw5HuX/Oc6tfoRmpevM+jncLb8+a2jNAiBDxX9N7tDFC6BA81muptwG5Eucfqek+ecg8lf2CxEWYQ=="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.11_1620565717012_0.09749813931633433"},"_hasShrinkwrap":false},"0.6.12":{"name":"@synzen/discord-rest","version":"0.6.12","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"6559069745539b6669bc05f9bada8c8e6fb4f98d","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.12","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-SqZ3hnd9Y9VOsmGDmSGF8lEasRdUhyqEOaeBSDCl7tUHpUEOF71aUJD0saBUfdeLoGkm4+R+838PbcueldQZCw==","shasum":"3a9ecb1abd43f752b591ff9701c64e7d43797f8a","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.12.tgz","fileCount":25,"unpackedSize":88557,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgm9g9CRA9TVsSAnZWagAASuwP/iiO87phBw21P+Qcez0H\nQstCm08t1tRKR69T6v/ZlGlpfC//xfivv8x/GCqnBoxC18QEA+0Dg+UwAupa\n0i7ASnsnNyauFOqhMOW53QU0Xq7a3GcfM4mSZbM5kRcsr2JPjwtr94QuwoIY\nvaqzVcSOj6yVUXbvzAX9L0FAuOZJnZaRsU70PrKJPdPi7aWuAEMrB+RhyYwz\nsw0DtTeOo1j0v5bf1sKovCQ0PrG1OcPHsOf6jJc0NXwj0Ua/Z03GM7SbRK37\nGCGc1G4y0L3eBf9b08DqqRr8K0uTMzDs56i04EHNG6dDXVKtLsjhou34jNKY\n2OxVLZ25mEZIHHyfqRij43T/yD8a7xTnPYh9VKjgsnd9kOWBc7f9UG4jxoIn\nz4IxZ/wNcy/vpKdioemYUM74R6qhIIXrrGyOQifMQpeid/Inhrqbyq4TN2WO\np7AcfoNtF4Eys663C1caA0CghG0Am4jgBsz0zgxMBJb57CJfJECO/5GNoLzG\npeN1jhHUkCp5Oy+uxHPnDu9kePdeuiYfc8bWXNQ0Uz3ZzhY4i6ue7XoQhknU\n5Ogcmlqrdjrze2z6NnS6KdwtTDcby65gST+t4UieeK0Ak92n0P9QevGxGCoF\nI3VyxsehJiu8XLgvIeah8B9PgDbcH1HBBde7/8rqGhthCzpVl7S3d/7nYC7H\n1hTT\r\n=1l7E\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICX0CVX+KXyOSjg4jU+Q4IEIIZqvK/EDER1kUS0vVMDoAiAaxJiMzuY2eTe76ieXLkK4SLmQSkvN2y7SqLmmQV6Rqw=="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.12_1620826172671_0.42060245309117583"},"_hasShrinkwrap":false},"0.6.13":{"name":"@synzen/discord-rest","version":"0.6.13","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"b6fd3348aef77f537243c43c978093a7de8a6761","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.13","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-rtRKu09RG5sU8rjsvxfKeJ3evMFRm6Dg4UCYGNmbwwtPW0nK4i7HtHWzBA+ky1NSg50KOVs5ZSusib9b8udBNw==","shasum":"15461203de7140118f2ea0c40b8b659a8f86fd30","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.13.tgz","fileCount":25,"unpackedSize":88674,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgm9sjCRA9TVsSAnZWagAAG/QQAIZJmXnhKLliZujs+gkC\nRQLS0VXtV1lXDJacWcvrX1/BBjove0sGuan7DrJ10/R++G0JppHef+5h6EF6\nlGucw9wFHRYyjm2fuNa/M7VRCMUsrh0yMsWBrTzo7LEn2IUPfNW7KjZFjl+h\n/T/QxaXBHJ0WW+IjS/VxQ41RWxO6zh4Ytxap8JpYEDV2JfvkTe/zD4kFV6Sk\nWE83V0BzuWqKtafLyBuD98gve2vxEK0FjXKsBpwBm4z3/z8mQ8bokDpeYfvM\nTI3iWFudspkTvP5Gv6tgJZbWezAGQ54CpbdZPu8C/cLP5AnkefzG1VfuVN9j\nj9kqFWEKFMheJio9X9sJdPb9qiSSLPX1A3asmlCL20D10rG4/G0s09FZEfkq\nmpiY2NNsNyOG/Of/WCQAZZImXbvYhXouFzHmpBhKO6v9yIi4pGlf+wkUtzVk\nMn4NyJcsMSbmrwTQgn7mUQvWeQnRf9cwVuRt5+GIVRxan7kdY4StGrA4Dd7L\nU7OfkQEuoKsgt36AKrotbaYne1LEpHJJQPqriPtkrVLhoHpSuBR/ks/HLZ8A\nMR67R+SUb9j/Ie198w3n7dhvKVmrxXPftCgabG1l1TicApHGIW5OiCflRyOm\nwGons1I/xhCheCYEEyytBQgDvFnb6PDa3EoAU1n/5LoJnQTvtXcWQbGXCg2c\nLLQb\r\n=AzMf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEt5ywFGygfbiLYgYt5njgdyRfSA/vTCX1a+w0S/8Hv3AiEA0AJFYgKk13aNXoG3Dk7wavROn2Ze/qMPou2o3iw7afM="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.13_1620826914956_0.03961629119644505"},"_hasShrinkwrap":false},"0.6.14":{"name":"@synzen/discord-rest","version":"0.6.14","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"e0d3deafebab0aa27d9d5d1674274a2a286b6006","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.14","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-3OQds4Q308IZGjoGGoNzx5B5ZGaGYOR0lS2RyAoXS1xkHocSf/Kzp95n8BLG0invRhECamwcCL7rEPCyxuT78A==","shasum":"cf78e375dfcccca76f0e5c2b550e3dbb039f6638","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.14.tgz","fileCount":25,"unpackedSize":88676,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgm991CRA9TVsSAnZWagAAhKsQAIZSuC/Z4ldk3s7PScJK\n8oYPrDIxbyunijOLRwLwG/Pp4CwzH7Eyk0AymUGQv9B0bNozoZnqIRZ5+Rf6\n3cFw26yd8ACuaxb2qhFba+RuJT7b3xjcpGumO9bvPWxjsA5QTjEKW53eH3CT\nsBt7PMyoppqEBovq+Yc80SzkhoMMmuC7rj8XLXi+uvkJpH5qfS6yuyvVk8J0\n6qVdmg/r45YSm+F4yPFbE7TD6YLKHa5Dvy+ZH3AfWwu5PXwwnJ7StcYRVAHI\nY10WyUHm9X81SK7lj6mPuHudH8OFq57NWeygKn427hLw0PodPeosbtIG7GRC\nWL80Ibnx4vsw0kXPQV7iVRTrNn4o/v/phZ2SemlkLcjuS3OkjgMvbvun3P58\nxeJFaG3bKa6hydCxmJwFFmJKWjJ8etDGyvc2VjBhXsgzZBVcScqioRGHeQX/\n1SX0yP1Qyw4A8buz4qKxCXXbOSxfaOaXJwIniErg62xLrU97W4nSozeWMn3x\nghoIG8gfqn1CFPuw6m+2PZf/4gfiY2DbL5mB6VIdocc/VUAb2tDklRS8hS6C\nVSNVpar2IK2J8YUSl/v5Up4rU4+EtbpANDnG8XalD8qgwXTi1HuCfSlYDL0j\ndUEX5xuQQ7jBEMaBV8SDuRskfiCdZARA7yWxoni5h568pyLFyztBE1bgoUsJ\nyEkN\r\n=fUku\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA8X1MGaWmxAlA+c8PQv5FLFpLt6ebCei1vxp5dUs24DAiEAoEb/pTVA8C2PMpwxNBVfUHt50iIfgLeVYdgAJLPYMBA="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.14_1620828021127_0.8870973470206973"},"_hasShrinkwrap":false},"0.6.15":{"name":"@synzen/discord-rest","version":"0.6.15","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"78df0fafc6d0b00da4ed59ae75a2478846418fe6","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.15","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-sTCzd2z8ze+xWQC583iQOI4oi0DaHBdegA3pGUSWO2DZRTC2nUyeiJLDJ3sN1uDgXNPlqc8qBZjgrZWz4IfvPw==","shasum":"5857e38bf0e977675762a5505425574f89c97ca7","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.15.tgz","fileCount":25,"unpackedSize":89124,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgnyLoCRA9TVsSAnZWagAAF9cQAI3yQSfvXEZH8tSdwrbx\nQ1vmmj8EUG4nmk0HCf+is4wOWcI2yuSPb9ZdkurSbhBXByzz8BnrMfcaygal\nIAL0KzTqCBqmQ3pNuDxLGAg9ojAidtO+pHhsUpcLICfEHpiE4yD6lzWOqaIe\nHV+8kuXeR0y4xZf9Oc41LuvxMRrGyCTqIQAcB4z6Wl6h+4GU+ImD9gm3weWz\nzb7+6GlV8A/qoEMCgvUtbG8FdJeArcEC2CY0PtT3Ay027Qr5rAMj3m8jB/Eu\n4Vd8OTKiSXkjrbchelMxb81ko/ePWlp9GU5agH+VLOCLXxRw0ibn/iRYww/c\nc9wApX+gBA8GiUaK+nU6nydYb6rFNSnH0Ldg0ZaTE8XKeW6pOnyzteR1QyZ9\n+BRT8WSjfzWPsvjTXsHZjReIOpW9j7QyDnrU8IM8BM48b801UW3nt2UWWIH3\nfgxnm2aSbNkQGOHWxtXVxnF0daaMVtSKAOiFYRoOC9Sf1j/Vh9W37aV5/9TH\nBTLxYQGKXTvtdxOSlcomryzOuZCdXqANZ0oCticxCGyfGMRvT5U31N5JzuZS\nTbYrm3s4yNSmRjOmk51I9exCXH2YFKWnbulBA1tuKIGdlHKjRXIcSZVY//bH\nbIYHzZ9UluISO6t07Q62VBJX3biI70ZFTPYDWPCb/ZEJK6lCZqerT6a5RgYi\nRUGO\r\n=Xk2s\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA85Jo49rYXyGL6OfxGpPHoh57rzfhEJ1s1WtayOB6m6AiEAzCYZO5QH0ibEjs52zZ0h+UO7w8q9dVWDF84y5w1CVW4="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.15_1621041895777_0.7767804641260199"},"_hasShrinkwrap":false},"0.6.16":{"name":"@synzen/discord-rest","version":"0.6.16","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"d2b36a8ea7371a08202116d8ccd0374c2d8e5d42","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.16","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-rUCpmoRjSe2AUpjLAH6Y4OG4FZyScXsxhHDw17oB2L6YB5tsvGM6pHsKsrnBXKsZ+gCDL+mOU//ikVp7qZNQ8w==","shasum":"b638e88671bec078ca5077176b139fc54cf393dc","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.16.tgz","fileCount":25,"unpackedSize":89073,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgnyOUCRA9TVsSAnZWagAAh8gP/ieTpfNC1gB43Ri36SrU\n4xJTmxXXsk0PLjzdIx7CB5fwUEj8wgaUvXQLgwiylAZTcku96SmRmulwgTTK\nr0upkm6AtNJynMtvuXozZb8RZNdNxYV/1llGfs95AzrLOlBFSpSB7XZjo2a8\nAJY64oLAwwzoj0ajY1d+FagWMfhVvtgz3LlaYGoxlrJlDbOoufUc8ice8qR6\nIWpZk6g7yRH+gIJU/bX5Af46UeDnPf6bJoIKt86Y2bpzh/IhDm39lUtDE8Yu\nuqCmXCWa0RmungJu6NzP/gJLkgrMw9ilerZf3e7g5gXZfrSSQDNfkADq+m52\n8p+QxYQ23a+6NSUKTsNY5+/hYjk9d/RlkYywNAuleNjm07ug/3sHHtVJWaci\nT88riUN7FBGnr6Xuv6iXxRcmZ23MbgKb99vc4Yn3Vk8gXgKZ6XPXg0zdyjG8\nij0XJwE6VlHh8+UuBQxhtQkFdspgOMp4BGBnSDxBJoLQ7QfhhWib7UPkcz9w\nmyDIv+Vqm/bWn8sP1YJbMwSeU5MPqWFojTZgPTvpkL9VTR/OjXdmz2k45WX4\n07A0wvGphUTbf4Diyfwq8LhpQxHvFfzkEnUkEKCjQxDqTUPGm7VgUh6wMBZU\ntixr6z62BWODX/vO4kY26kFEWumNEt8biqKGOPBfRnVwhx7LEbvISEyc7N7p\nalqh\r\n=s8CL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCqOkvvdSnweqCHNavhmX4/8sII6q76S27jH5JSDRQj+wIgMm9oGk2YdgS/ueAyK8oOqrSquFCzMFUqRGOtCJDSzuI="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.16_1621042068046_0.7240194669909532"},"_hasShrinkwrap":false},"0.6.17":{"name":"@synzen/discord-rest","version":"0.6.17","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"24aead79d50167a53e776ec689b57fc013f1f3cc","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.17","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-Kox1W0X9ktnOiQNnDEVBnHmG1PeG0txgr4K83KUD3vWfFpSLKCmupoz2mGbVHoNeT4xSrFykOIDxAweylFGGlA==","shasum":"2783e674eb006c6ce0d4a1d2aec020b3106c723a","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.17.tgz","fileCount":25,"unpackedSize":88676,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgnyUTCRA9TVsSAnZWagAAYe0QAJfKxzfs99A8XC1IERrp\nAG7kD3vuMxHYvlPH6X79+ZnMyrhsIAW/Klml2nKCU5Egpfss2T2z/0ajxa/a\n07kcEKvDGOO0Vg4bAZoU+5lQXCKIXq5IzAC/qQmtGgEPhcIBiRTgms78jbCZ\n94//1r0p8XYxO3nkCPhz3rjS870nA3xj844ZJGy7Ivm6mHPXNpraoK9cP189\nNYviNYqUiK645Rnv9jwAlJB7DHBVYOMtTJ6QK+xMPkCfcHlpMGS7QlTI3INy\nxxz3CCgU+qO60KVcIw6HBhjY1Hyk0r/kcdIfBLCK4Q6pzxq86nTJAdrzOaxz\nKZU5odyFVA/Wd90tV/aA9khMRqgyW3jYL+EmO/glznh/pg7vfPQZjwmLJTxn\nbDSwtR6mr11PFCwqYWq/ieAVhBp972DY6XiN9KcAuO1Gktymqj4kkkdS7SXv\nv9v08HLyou+3P23ML9J4MFQFpmGY9nYnPhRFeobKBAtCu9AqDFp8uVoDoD+l\ni2/n61Y8+h6ho0DqCA/8K1X/qHqgnHB0Q2lZR/vMDKx0EHrFlpAKPJ19wAbj\nPort2SXjdeTu0vWNUHC5LANB+4JjfYy8AQ+jh3HeM5cESptUw74YAJMm+IdY\n6ll38ZoiN8xuFnKvYQXsxMghq3B9JnzzC6BjQ9LPA3kWGtzetFuAWSrNmOV/\n48QR\r\n=OegO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFyJUFYipKYd4RE+2u4RwzS12phTlbs83eCZGll/FvV9AiA65gj8qAnPkT7EXGwic4SsYZkdhr18MNkgUV6JZODw/g=="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.17_1621042451044_0.44344504903597715"},"_hasShrinkwrap":false},"0.6.18":{"name":"@synzen/discord-rest","version":"0.6.18","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"88848ea04fc3a3869964a5a0c1ec7b3517ad8efa","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.18","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-syKUJKOTmKcthMc2Vtpcux1FOTNNDVN9pduBbn1GKnMRqYnRfsEeU8aTfYXOvNH+wuP8Oo1zNAt8Zv8q6VVPnw==","shasum":"054cc0bd9353b951bdfa7b1a3e48c7661cd91736","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.18.tgz","fileCount":25,"unpackedSize":88794,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgn094CRA9TVsSAnZWagAABCYP/1hIAZbWd1362cRtrmdy\nO3snPY7rZpTDe6NPOrFJByl4wTT0t5nUyQxrLn7wRziiNlKqoE/z4/ZVEDvM\nU/hG/i2yq0cfG5k0AuVd+Vr01OxoParzIKagERmoRdaPsA+JkKnOzomOZCWS\nwEix4x0OoP0trC3QNmKLLuc0qkI7Y/CKv3RzEV30rg+YvDAxx/7h6CXFxQyb\npQKqjefkRPAbfgR7pa6tWfj8wnNKHU2FqyvhtWCSc9ckER8XPohx/ReNvAM4\nXQqzXAsp8zbyGbkd76nIIoOl4ytrpxM42VcAazsaoU8WDWW/4/bUWeW2Nq8b\nLXcgMJyf1dK9s5TJ8akj/WCf928msBiO3BAZO3K8L7MPFBJ2JK/fzlTcPX7r\nDZfLKO3c81EThsse1U93Ynb/IinliirV4Js2I0D2r+dGNqfzcCE6lVzstHOg\nZ09UMYwZvSH0MRULsg6vVCErYZtk/3lCVbwi/m8rPSObDck+2m08V9gsEuEM\nt5vt6SnQDT7nS74IACyodRUIz4OKFtx+WnhTPg//xRpD2MgHsn7Br37Gwikw\nDjS4MzT0Q2LUNI3p4aDmiviZ4p79Zzypa/RgpGAshDiFRnv2QQFxayax1PNZ\njKqAzD0wvNb3iQ671ZBZOOPaWEiBlNkHjGy/GGMxID7IEvlQdHzN2J069Wxm\n9Srm\r\n=pqZ6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDq+qTD9aBw1hNiyRtiTcMwy6Y+jGZxX6HvY92qeqcQDwIgZYkdtndFCCstINJU8Ne48HoC51ud77+qY/x1GRfGBCw="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.18_1621053303506_0.8767305731099306"},"_hasShrinkwrap":false},"0.6.19":{"name":"@synzen/discord-rest","version":"0.6.19","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.1"},"gitHead":"4f56f9d7cea48f8ed3a355d6a0d3f65174f55a35","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.19","_nodeVersion":"14.15.3","_npmVersion":"6.14.9","dist":{"integrity":"sha512-DGG6nw2PEho7iKq8rCinQO8tZ+QHzBtILzbwFcUg4oc64dAc5Q95XdzAEaKUOGTn/pGIj7hr2R2GpHYxulViHQ==","shasum":"daf7623c27606b36783a4da0304d0a129bf186b6","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.19.tgz","fileCount":25,"unpackedSize":88829,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgrEx0CRA9TVsSAnZWagAAB+AP/1EULKRc3K1xkHxlAeOY\nXgavjnkMMybIk1XZKZFjajPcrv73oue3lVFzTjj9sBKvH1mMTWaxwk6U1OaZ\nK16II15akZtbEHnlolo4873ywq4ZDDE9LMF6E98cTKBs2bN3DcEOQe7A4JsN\nNK2HEzT/rdMkpgQZerhSrvkoWehWZuLQQr7dWF2yzP1NObnHa/MLB27t1fdy\n+i7PWMzmPsi49r/cH9Mk9z+41On2UxNKCEVNF6Zn83qs+k6qt8QErLJOosJc\nN93CGnSGc1HyZOtR7ZUcssIkHmiQtn8/658Hp/H9LovUsga/VMSO8vqRGLOF\n8ummt7rf9u9FqVY0swiMpnkwsuQf6lZ56Ws1m5xIXMshmr0KvjZ11ipGp5/c\n1ZsK2xL1TJSTlY/n7siBNfcc1P0nnUC9x25c+vUeipCFDXIGBzKgAvqmkYm8\nVYfInukf3oxzxhuTNhD4iBH7aRhTBuOwQ1qkyffZk14K/tq7vuarB33oajz8\n6K4pen/4qPAGtb8qj/uLLdjLMciZdULHKVqjW0MqMbn2BU6TeAiiCcuWfwDF\na+fKe/obDYSExqN4AD6D29pb/pGvvkitix5ECAWtUsXCef4AVqlt6iTwalkN\nehY9lfbyWh0QlOfuJSK6JK/pg/zjgpCht4q52KfPKWQESvL6TllWcuF7bqQV\nWgsq\r\n=Ufc9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDIV1S5EBRrMVoLunC74vEFHE/MbHZYFdtmrl274OweXwIgHSg+/QOmU/FqXhu3L+MYCZMGCgVRA/bk5hISPWajE4o="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.19_1621904499867_0.9693781444538243"},"_hasShrinkwrap":false},"0.6.21":{"name":"@synzen/discord-rest","version":"0.6.21","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.7"},"gitHead":"4ce67ff4862c730eeb2d950e483c8f07d2ef50e4","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.21","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-+nP5+MY0RJ1buVO8v6U4pZw1A0I+niFjVfgJKiDumjv2TL2u4w6xvbjmWubeYtXFHlyZMunD+TnVxU3QD5qPgA==","shasum":"29c39e05b73c7722671fb55a75d5b7c83a476e9d","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.21.tgz","fileCount":25,"unpackedSize":89723,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh72HbCRA9TVsSAnZWagAA0xEP/j+MhJOraDrj0W/Y2awT\nCA+PRfkzJW6Q9EVej7YEhHKMyL9j1nFMZYuJXd8uGr+diBwsQ7JyN2aQBuzR\ntbVPTjqOUKSvJQNuSFZ0xNl2iWTnqCseGVWp6PnJjQ32SV4SPMH5JrEUBR/U\nluMbgxVAksUWlckG7Oqro2PeTchGwZAyFuLH+zppfgF91zz9qbkJn2tvOp+J\n/KdqMze+vTSkl9A0yViEnuxNyJji1dMhv1a79z1DAUM+pU7aGkfCkEf4mjkl\nfgAQsgsaHEwlM29aIiM3AL3GS6xDjr1yi+gF2Ixd/kQu6VdqsjEgXsHR/Kh+\ng2kdTVyKH0Nvu3ATjFOl4SNXQYiTNVpyolSSxNKuJ5H8T291G6dIEEd8iFXc\nVaggALfkIJzgaaL9XYgRcg7QuTQcIGGHb2bSLD5NL+AMoDT2/CWlovdeuNKQ\nrkfpqtawbz5m1bYTCmxhxzBtSmiWab7FCXcoZBErbsjQIVWfs2AnffpF9pOL\nGUHgu7zZmyyB06s2YHsezr+OX2PMZW3IEGS5oZfCqeAKSJh/frwosvF8g0st\ndoM9A5APVgdiZtzv60mcCYMKFiiE9nNvaBim3mXoa2Pd9nczGvVRO68J6WXc\n9hu/nLJx030sBq9S/EgxMJOfK0mwSuhlcpv8K3QklmfO7lhyf86OfvoiRgPb\nSoG5\r\n=gJJ2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEz5tdPvkSYwFr13w9l8mXWIEI6+CnJPsN0Y9qmbLfB/AiBiR+vkoqvH2sN0jScXcs/zunOKEHaB7Ez6HOeFfoyIyg=="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.21_1643078107116_0.34879900711923484"},"_hasShrinkwrap":false},"0.6.22":{"name":"@synzen/discord-rest","version":"0.6.22","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.7"},"gitHead":"ca3240119641a32015286321dca5b10d589e3a88","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.22","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-taKffFIgShnK2iuo9w+dcg5fjHKKUkKNQ6OOPU9CJ0DLGQjzBVI8svxYvwpAn2HLYArrr3Dq6ujAB6Cn4qJT/g==","shasum":"2a21a96e69e0fa3b0a7ac0bd7cf34178541a6870","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.22.tgz","fileCount":25,"unpackedSize":89589,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh8ejTCRA9TVsSAnZWagAAxxcP/1nYyeQigWm104tASXys\nFWCNDUWyfHuAd6TbvtaX8nJKW0HHd0hoUtoghY3NvRdq0Ou1xX/bqsCQLBry\nRtd2I2JsKQUhYikuoN4+kyz4Be3BdaWvaCftr/XkmPrF2XSkNRQX8hA4WY5Y\n1/CogwO8CHCJQtjvNsbto+cydJ9pKbWAhe8abxi96Wpxs3NUr4Lf6A5ZWI/r\nsAXJKJwUCsYWE3nbjucDbwnmUGR7YfUW0DpDy00jGI23d9v7QmYSnKzzGkHt\nKOKpexHEk32gaXCH7/1AMWftsrxnef8schU9OJcQKQrTtt2w+QJSjmLLoiTk\n3Qhx5hhzW/kXGuHGPk3Xlq4mw/KsktPBznFjTifxRA5r0vwUcxMr0cfZGC72\nlP5/hBwCV3cJx4BTSNqNiGtDIl8L0W51roH0pALSKiLfHuaVhRgUZCrhIuWz\nCEE0vAczemLv0A+7NyB8OfN28q3dbENXoHOoX33i3+LSdNfqaRDZ8NflVkUH\nY37YxKtg0+2VG17tloIrH9u6tKsxKYlQckdr6efT8McLR5R0xj7nFti8fpqT\ncUP/Ng7VcM/Zyx7CJDf04lWAvwKMHpY3lTA+RAE6IATbw8cuywUOVnTq0P4o\n3jGqiMpHU9eZy4lWYoO5FJZwxI+H1YmZ2izwvHROgUIMjd+sXMBBpuq7ZVHm\ngprF\r\n=xLEo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDVPRKEIvrV+pma1VnqBL/i+cZnrba5jGmQn8nvfXlrfAIhAKYuNfth9ri/wKiUm6DTKSFO8o8kwcOSCp+Mr5KOssyG"}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.22_1643243731344_0.11047194575787489"},"_hasShrinkwrap":false},"0.6.23":{"name":"@synzen/discord-rest","version":"0.6.23","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.7"},"gitHead":"bd9059b1caf6e58563025159a0c9728e3234d37a","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.23","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-CTBzTqoq6ZWISY8JHafpu5m90dBQq7cwq8cldrFBpd7h3TaAKFNZMc44lSZ2rX8bD7aT0ms5mi2vGNsqoTyfqg==","shasum":"00e6e70158d4774ea146937bc01877dea1771bb1","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.23.tgz","fileCount":25,"unpackedSize":89718,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh8pVoCRA9TVsSAnZWagAAITwP/0H9rtzBtIuy7VeaeMLj\nnLOFf0ZAYg6TWdkjPRP8gTJFLQlr/fgckHSyIdiCRem8LQpm+4n7lmv6MJ/M\nfp3AWsTOqIWbRgSlQ3bKQrXNEWxSsxdJAC7EN0Hm5Y4ORS74+X9MSAYWF3UY\nT5OJLeYfv9YYQAfOMU/gmqWfA/TdrSD0rkngAPR/9NrIMf5K6OJA/+ykiGp9\nGsI1WRfMwogVeKDnZYuf+zEsvCZ0w2/9uOptCW0IcHXV3DISv0vQKx3q0Le4\nrWSeGT0GZZ5J2IeyfLY8ybXbqM47/NP/DeaqRgkwWXi6pzvNTooNRFAnyHjz\nL7uFkMdZecOBSUA54ywNdOXjs2m75hR8xNwYiR2k09gDX5z3w9+TiaxzXO7Q\nNnOFaP3DE7zYvEJ+CVx4qAdtzE3QLwBj4y3LKNPsBz+6S9U29Qr82hKnkhXP\nM+u5K5Fv24GdD/93DHPxdQ4FotI07LimSSt60CuTgR+ojB3HizT5mfDadspF\ngn4gmfl9sQeVzN2v6nZrCsKBJSSsiPpMWroDeYlSJn/Ua7cTQxHTlzhW3c14\ncrDNiGGqPU6asukwiRkLuyD2+edAL3YBWOp5rta41j0nL4GRLBaaYLLLgBZc\nFY9cfh1z29mo8pBMZDiKT297/xOMr5xFNM/azbb+BmKkuwt0GewKE7sCeBiF\nUuYz\r\n=knsX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBiSdtvEFMSICxBr08KgzTaGoO09CSWIDbPPQGkv1E7tAiEA0NsnLSAVngPygx6c5NiUfolg9WHcbSxQSpEuuLCznaQ="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.23_1643287912035_0.6742044025741345"},"_hasShrinkwrap":false},"0.6.24":{"name":"@synzen/discord-rest","version":"0.6.24","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.7"},"gitHead":"6b220261f31a7bd25a8cbd43396016b62ae8cb1a","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.24","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-R/LK9xNyHqpn06/WF4wBf0uQIDLri0sewFouVBe7KbUZP7FfBvI82N7wHHyAtatV3y9PJDHjVNfZU5urehs+Wg==","shasum":"8a6193d524ca57c96c686ebc81b87ef2f0bbf91c","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.24.tgz","fileCount":25,"unpackedSize":89589,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh8pn9CRA9TVsSAnZWagAAi7AP/juM8o4IKkFGoaQxw8Tj\nBgQzEn8NI6tO8qQNazq7qfnrL0DtXh9CqDWeZeVM0nrp5cemJXF9HMhFmzVW\ndg027gmHYkXJoFSggzywM9vLvc2w1LA+5b74YptuHB20L0qx3WfbB13E0OIS\nKSlP3b3hwvonCSbUqZA47DI1jfQZzIlQKDS23fQUXyA6Q6Tm8xViRxFdqOa4\nVZrWBNk42MAEiMVEYyxIHZSAAn2V5fMYbbrUW+hpJA1ZfedNb4Swk9fsDDGM\nXmJb/q0Tc8OYaOwxmFQq8atzBkeUJLPiHjPwRuKFL34K4LoaMm+ZIh9wo81Q\n7kaWTKQV/g54Wmu8+UMbdcYkgegRxOKDGXCfv05wpTNmElu/UmRk1G7pGM9s\nUvyt+8oIAoBp/E3UPyP8XrzzShUhmc0h2Jcq9+XJOmJADXbLsjNuMbvkur1j\ni7Sa92Bfi8WWXWu3nTrgoOC6UG2K1SVy+nppEe34oYJh5XgOz7LmiMzMCHrG\nvx04f2BDz+fVQglOGSub8518YCPQMr7WaMFo8FvHnTIkIEc4K2F9PiniGGZB\nB7XYt5LUdOFVstceY0CWldQLdDXUuUDN+ERSagA9D0f6b+pWLuikqzfhQkZ2\nkF6+KAqfxB5tavJhoRlgL0JkuBQcw6m3MoIwNKy8Yzbipp0GTTR72QthzjJq\niyt9\r\n=V3ZR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIByMtEoMmnUAO5E3CQXQDcA2+EvddgBCpjobp1ab646WAiEA9jwM+VJCERw2/0CHm621MfKHNiNtGsIzfDq3LRGRDpM="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.24_1643289084994_0.7714810645235131"},"_hasShrinkwrap":false},"0.6.25":{"name":"@synzen/discord-rest","version":"0.6.25","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.7"},"gitHead":"c6938d7dd1798d246fe337924793dccc97f186f0","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.25","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-eQdD24Y6gLtjX8TfvAKdiRvnlpHjekZxSOR3RhSJ02uuejHwUNgrH+Mo90k/oMge0Jhld1QYiqynU3lWELgy8A==","shasum":"1005f1cc69d3314e94e954370c8505bfb199f5cf","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.25.tgz","fileCount":25,"unpackedSize":89619,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJh9I/CCRA9TVsSAnZWagAA9SkP/1K2pLbxECppP/CigR5w\nX6qZJydMWPMqURNf01gQ//XsDezzZ1/o/xTrXvYyyKYV0uoqU6RlVG2N0ahX\n5SIJs8dYCneuKOmyd8t/Rufti/SKnW5hv+aZvxUmSSKkqxJTAb10shRAxtZm\nVrdTa3kbxX9Pw1zgO461NTuywzwddLmToD/jaOYMzZKnhh7PLBXYr0chuZ9k\nRJSWZC8HdDEFJu/UvqL8tkgIM7wyolRf7JWfxihb9zaEOyLfaB0J/TWRnPMX\niWMCPACLYmdg5IKX+p+NVy4NcvV77jeKDU9aA8HrOEOW0RO/ZldqqMfpr34x\ny1OXRWn1C0OvWcT7sWYw9ZaZw1o+YMqspZXTB89v0RJdR57lmK09B+RzC2C9\nmiWIfECsrKLjsao8JeA7cn+qlX1WQOf5fhHBJVH0+9wjW9i9e6D7QZmH/Dj2\nAacs7doDhzP5v7PHRpc0s82/yNNqw4ddlWtbvVJqaFF0hCI7OPRIrLzor8ZB\nUuW1KX6QtJXsTo2KUEitozXmSHhcYew4xMpuxxQouoiq5CAuaC7FMotNI9rD\nh5x7NJ09MPNw2gnRiaOtn83yb9a7fotdi9RVxyGAjNV2w0HwfTwROSbbDfFc\n5qOpO6/YlWOYy3X11chWdPpo7W5kk5IF8ydMJ8+ZMlsU/J4LvTvRqZVifv9L\nCSwx\r\n=ZdZ4\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDzwcMbqolQbLM1EJ2x8+AzeZ7XASi+um2TekN4ueJ4GQIgHo2wwIfdATapqwcVtwsFvz7+UEBpkKzxCLcdroDgDIU="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.25_1643417537815_0.8263073937403269"},"_hasShrinkwrap":false},"0.6.26":{"name":"@synzen/discord-rest","version":"0.6.26","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.7"},"gitHead":"6ba7002893e356c2a60a6ba9f795f4cf93e6af44","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-FE60VtMk93B3W8M427rfpgC1WYLM6wIFusFbLfrXSLzlWBGlL2LfqUqu9HtAC7aGTjF0ZWLRRJm7ruhbgAzT+w==","shasum":"e5a2b75c3311a201785272a6007962c847881d4f","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26.tgz","fileCount":25,"unpackedSize":89098,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJiATD/CRA9TVsSAnZWagAAJIAQAKLPNnnM0C3SclaliH8i\nV6AZeVLtIhJLUzYRZLq4KJV37+FRhEQRDRSA19It5lsGwqYiWam8uYjHS0HT\n3msKQWaZVoD3GutLA4GY5PK1Cy2OPS+vBEo3EUJQ+dkP0fS+GCYolyZO8Pvo\nYJJoUlMAzPZPXWA5CFyDX1g6frU9Am0GDQgAuxtWE6f3qC422aT5hAYJHIgO\nR6OVcJta5b+J/7OGx8Fd2ih4Svt14gqkf5kuzITqMc2sWc5CRE/Lh7TQ8UGS\neNi/ZQuhUfefUVjqxk6fp+Q5JmlX0AXIXb8cDHuA6a4TQtusnJAOFG27KUTM\nGFLUvQJZHdQanIbIBcMx7RRKW0CMhs3FbGe0VfnuNdKWA6l3gn1vkwYbgY7k\ns12RktvfKQ/+yChFr+DSuxR62mKOG82IcENi9haIsun6TIsTLIIiHPmxaCEh\nnxaos4JbNurP+6H86JoGMHlFbbxpnbdUieKl2pTBJzEm1LGZ2A5r+kAW2lT8\n+FB0JRF6ooO7VSzixg/CtPoj94HNbMOzhnx384Gj6YSNczbNoocQq3dZncrL\nPa5sn9GN1uVrNWUaRCpIadkDBUsBmqi7plJzlCHGKZI0/D0iJbleesctAn75\nBB00Km/OLCNIegABmsaczS5SF0SsDGJzXYYjB/YHyR4MB/2O01hj0QJuvRj2\noupF\r\n=AbsU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICIZFP0ncaBNeeUaleqsptrWQLSFesxVK4cJNRdkKARoAiBY0Sm2Xl7DwHGMLPu9BGYTVBwO86XAht/7fWsq2mZKXw=="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26_1644245247179_0.2830804936524489"},"_hasShrinkwrap":false},"0.6.26-beta.0":{"name":"@synzen/discord-rest","version":"0.6.26-beta.0","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/isomorphic-fetch":"^0.0.36","@types/jest":"^26.0.22","@types/node":"^14.14.41","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nock":"^13.2.4","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","fetch-retry":"^4.1.1","isomorphic-fetch":"^3.0.0","nanoid":"^3.3.4","p-queue":"^6.6.2","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Handle Invalid Requests](#handle-invalid-requests)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\n## Handle Invalid Requests\r\n\r\nIf you encounter too many invalid requests within a certain time frame, Discord will temporarily block your IP as noted in https://discord.com/developers/docs/topics/rate-limits#invalid-request-limit. An invalid request (as it is currently defined at the time of this writing), is a response of 429, 401, or 403. The hard limit for Discord is 10,000 invalid requests within 10 minutes. You can listen for invalid requests like so:\r\n\r\n```ts\r\nconst consumer = new RESTConsumer();\r\n\r\n// Listen for API responses with status codes 429, 401 and 403\r\nconsumer.handler.on(\"invalidRequest\", (apiRequest, countSoFar) => {\r\n  console.error(\r\n    `Invalid request for ${apiRequest.toString()} (${countSoFar} total within 10 minutes)`\r\n  );\r\n});\r\n```\r\n\r\nThis library will delay and queue up all further requests for 10 minutes after it encounters 5,000 invalid requests within 10 minutes. You can listen to this event.\r\n\r\n```ts\r\nconsumer.handler.on(\"invalidRequestsThreshold\", (threshold) => {\r\n  console.error(\r\n    `Number of invalid requests exceeded threshold (${threshold}), delaying all tasks by 10 minutes`\r\n  );\r\n});\r\n```\r\n\r\nIf you'd like to specifically listen for rate limit hits, you can use the following events.\r\n\r\n```ts\r\n// Listen for bucket rate limit encounters\r\nconsumer.handler.on(\"rateLimit\", (apiRequest, blockedDurationMs) => {\r\n  console.error(\r\n    `Bucket rate limit hit for ${apiRequest.toString()} (blocked for ${blockedDurationMs}ms)`\r\n  );\r\n});\r\n\r\n// Listen for global rate limit encounters\r\nconsumer.handler.on(\"globalRateLimit\", (apiRequest, blockedDurationMs) => {\r\n  console.error(\r\n    `Global rate limit hit for ${apiRequest.toString()} (blocked for ${blockedDurationMs}ms)`\r\n  );\r\n});\r\n\r\n// Listen for cloudflare IP bans\r\nconsumer.handler.on(\"cloudflareLimit\", (apiRequest, blockedDurationMs) => {\r\n  console.error(\r\n    `Cloudflare IP ban detected for ${apiRequest.toString()} (blocked for ${blockedDurationMs}ms)`\r\n  );\r\n});\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"55b713456df15d98947fec363ea6ea7f90c602ae","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-9d/l0FFDT2TFGK2BAU/Kt3bqMG64NT5cdd4pbtku7ymNmLo66IMVRZ6Keet2wfQI2lyPgcXuS8UGupmwmSnr0Q==","shasum":"1b76514b26edf32a7baa54070f00341526397e30","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.0.tgz","fileCount":39,"unpackedSize":156082,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDaimNyXwrGUXNNnAGaRW9lxXbdt/74yc1VwhzzjUG/cwIgV/Rp85sQoOVOmX8mrOXJcsnqOP7GhQBa7WFS5vbcxiU="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJikDrpACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrbPA//QYI2sUepfxGeVMkYX7RpCoMAkVEXph3xH/e6vVdzrcoZjp7S\r\nj2A64V53dtMX2+nd8HEPj0KOuadaAUlpBkGlPEy7ry7Vc+JNv0LiUX/z7xML\r\n80Z2UOTfehpPf8L+UF42i5nJG8+W5jpCalRwnEGx8OoB5ycrlHpC8saVbzt8\r\nGtcOgTCfN3CpaI3eCMh3atV70TPAWsWgi5+8TrrSejIbrFBMnA3dfWHEc5Tj\r\nHBmmHPgqNsf96FMcPSFJdoIc10VFeh+HeMd+H+/1bspYFoIlkte1MSnN24+S\r\n1vziRHC2GMw7XJDwt6hbtHlBqTB88kDrUU5wAyNHhG4jWxclaS6VT3leCV0w\r\nlGC9A9Cyj++74rKSRLht0inCr9zpJ18txluJuBhQNYNd0fYDaHdStb23mhN7\r\nKf8dot+jlW1hUxFC0sJCUnsDpHP1QeGjGF/dwmjScMEqcpnZANgPBmyAAw21\r\nKLfl/ZZmYRjv5egCMg0FGPdy0f+PqGMOgj9FLRgGn/HM1NhKFxhxrg4GqXo+\r\n9nyyBC5le2Sd9DRQXXiF9uAo+PHPFH91r7E7Y9spreanQVXzu7u6lmb3fCIn\r\nRFd6Aqr6es2OmBgcxIsNeQ8hoBQ4EHIF5kLb6mjLarXCVnWVbTbtfo/RSPNt\r\nZgGknizxYz0OXeNJDFGcOAF1Io2MedD48v4=\r\n=GWUP\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.0_1653619433455_0.46117937553548183"},"_hasShrinkwrap":false},"0.6.26-beta.1":{"name":"@synzen/discord-rest","version":"0.6.26-beta.1","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/isomorphic-fetch":"^0.0.36","@types/jest":"^26.0.22","@types/node":"^14.14.41","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nock":"^13.2.4","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","fetch-retry":"^4.1.1","isomorphic-fetch":"^3.0.0","nanoid":"^3.3.4","p-queue":"^6.6.2","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"a49cf1d6d50bd2d620193d52b58c21741d93615c","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.1","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-XAiVX6hj+EdnOmUQM4XC8I+GmWrBjZh0VeDmaD1TVRt1bc0vVIYXwVsv/Chkf2WTGC997DUracfvBQqzmII7zQ==","shasum":"1ecb02d2c54c037d8501f65b955c104aa3ff5827","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.1.tgz","fileCount":39,"unpackedSize":154812,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID4VyHm3RC6DxyTlm1AlPeQBXdjSZcpR3WSoDnQPD2IzAiEA9qIVib88cDZKUVcuB5Mb+yx4U6rAbPQpbRWKrZRtPcE="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJikEq/ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr8aA/+Kwg7ij1nXeHhmDXau6vxcGKwqh7GzrNOhGF6ymaBYSLh9HnQ\r\n17gRwjUMSi86Xwff6RCFVdY2M41LiLDSSFYxq1hz82xGvExdV0CYUHGr8PB0\r\nnqhNMhe7hW8k4GZxNo7mWQ4GFOTjXiM3InqGEn5MA5uATSuoA5NmJcv7j5W9\r\n7qeeWjeeTYRMxSWJzg8UiUSCD5jo4kI5HtP1EU6VK/HqXGFFSeAdvcaslHSA\r\nRRB1GW3eBoUcNZlGFT6ryoSwgNqtZy+BrRn8CAzZhmK//o10zjkipWsAryM6\r\n6Pv+y7qlkNPPT5YDE3EkYaVpSpxwmB/rWN49f/OJmlUXzIoHBxi6IwyEcjEJ\r\nhIG0Ys3xbv6mBfsDui0epXF8K+f0NHWHeFSC/JnsirAInVb6aUreE76WTrlx\r\nCNhD6R+8ZrHl3C5j+OQQ4vA1UDSzZvDpXrcPEWHWdTMXohg1O+Pmz6JdF8OB\r\nu1rIziAPvobVw2NSmkt9Yva23nhQaL3K1Zf6/+EtHfhsRKeNAONl/imPFq2d\r\nZiDmmjUT3cOVKAkYj4+01kPrEeEOAzmS43xQVGQNM3j+3eCNJFXfLbwaxgNC\r\ncMXI+kngvKlQ6hRv9v3ruqTtsDtxVf4J72nkH9Xjmogeqf69qMq8hrTgTBK6\r\nuGgVb2Eak+l/bkVIEZ3An9a/H/1dC6xHe30=\r\n=5pkW\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.1_1653623487551_0.8429062005535046"},"_hasShrinkwrap":false},"0.6.26-beta.2":{"name":"@synzen/discord-rest","version":"0.6.26-beta.2","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/isomorphic-fetch":"^0.0.36","@types/jest":"^26.0.22","@types/node":"^14.14.41","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nock":"^13.2.4","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","fetch-retry":"^4.1.1","isomorphic-fetch":"^3.0.0","nanoid":"^3.3.4","p-queue":"^6.6.2","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"c6d9da995bae276131919d1030889a3ad16b8a66","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.2","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-Q9dgJy3z9uo/cANn8Jb4bURA91voogddUjETgX2pGcujq60403LQYZkHWmkSydPtnA83md/5E7LXn529nSDwcw==","shasum":"d83a9ab23b148476bae3a13d0f801c6276c71ab4","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.2.tgz","fileCount":39,"unpackedSize":154812,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBX+xiWGgiMpOZdOMGT0Ih4jYVDSohSGB8ueuv9Vx9vZAiEAr/vOnZI+POoF08UfXIriLWqxLIUm40Vcto9MATaBOTU="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJikFBDACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmoi1w//TxKmx9W7VInksyN1gk2sjMuj8jlJn1ttf/4WTNLwPYS/5qyw\r\nfNymvO6o2S1tqLvKAV3epXCzykxasZo2OXpQbttwTRfAqC/CcUQwyfL1+seP\r\nPQh3I8U8hu0iCYCn7jDJRwADYGlHz2BTvQYpmE5qldB/R/FpVp012ruSzprD\r\nkB5GH5pV3GRQJyssAt3nmE4PPBZyIfG/v0DjNkQLWOpDR9YHh8vcIdfVc0tc\r\nafx/6izpSffh7hfEn23UQmlk5LHHNsKG2qNOunE3q/YioP+GqM4J5qHAkvZM\r\n3KByOp7Zqn6kV3vEKsBQD7hlfqF3A3pqM5s4oQqawVehthCK2lRk85tQnfDt\r\nVbcP6kPN3dedwObrr/KPYt20n9QbCNfbWWIGK7sVgaAbqnE7VQxxG6o+o4/B\r\nnIb2k0bCy1lqAxLCD2ExifyTc+KPEdIvrJfboVvbJSA7T7Imw8VTiUDd2rVn\r\nMvI9XW875tBa9bNNc8ETxn7dSpI3r6FPUfVI231PjRKX1ediPTl+y73i/GE/\r\noMQPhtWdtUOQHCs/diYtjMgjk4vbr0FbwHtdqWo+XDtiwP+/kyoCi4DzwbsS\r\nP9fIkIcn9226qbk1gO5tigI+pSVHJW4Ww0m044MbYjJnJuXizcetwNJZfkQq\r\n6uxynhbp0oCx6lDwDLPKZV6qMCwn7FTism4=\r\n=pFdq\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.2_1653624899020_0.9215906436097432"},"_hasShrinkwrap":false},"0.6.26-beta.3":{"name":"@synzen/discord-rest","version":"0.6.26-beta.3","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/isomorphic-fetch":"^0.0.36","@types/jest":"^26.0.22","@types/node":"^14.14.41","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nock":"^13.2.4","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","debug":"^4.3.1","express":"^4.17.1","fetch-retry":"^4.1.1","isomorphic-fetch":"^3.0.0","nanoid":"^3.3.4","p-queue":"^6.6.2","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"d877959dcfc9a2c29a41b8f9ce4bb3e80845ea54","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.3","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-dLIipITYZOb1lW45k0epDVXtLNomtYUBZIlgPC03ntb6MjVgiRszSmlmB/dvi6yLG8DJA1ia7l4qZvnrevVQ4A==","shasum":"b264e630b177c22c16ca167bd602d6ae65474e79","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.3.tgz","fileCount":39,"unpackedSize":155524,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD9gbv3uDst5miCkkwFKaQd/zA0XaTCbfQEhF81tpdYsgIgFHeisqXohbghLpkrgY2WZcyZF68UQpiLvKWtqP4cJxE="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJikWBlACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq1DxAAhhgl/hddJqNt0M4Va5eqnGyV9P00WT4pdl2C5mk9b2KaHIaB\r\nVBe+LTR2m+b+hpTTukwvoExu37mZhMRUcayymCI8Qh0RvIz+OzfjcfhqqGU+\r\n2smceK0UFJSgPlyTUi1ELNI94F1lcM5wbQOPQGNhQHZaF7+6RHAaZfrUmKjp\r\nHslmxHdqtmFw2r1pf1RunFuyZvTKsxZb8s7lJzbsYtvbIGhIrN2IglUiAeoh\r\nj+A48WW7u2mHhdLrLwUnzpL3yZEnYur/0iRpZ5DbCTuvZ23GHf33PM15uoF6\r\nz4daq1QolAsqmBQvnA3oT6Foykaz+yldLvSbv8umX3Jr5epsIA7y5EoKdbuE\r\nJfCGHiIzZC+TI3wXroNPEoLzILHcVxsDgxWSZ6/zJamPqnxdFU+/Ef+Ji56F\r\nHJa6w0cL6oddFm4ndbxfc65L6j0JZMPhVc5QRcNqHZumKvAEabG78UBs60y0\r\nsbrXXEYtjPa17viWdmqDm1PjLPHE6OcUAOlCtnZr2JMp4WEHLtvsSc7S4sPx\r\ndriwK3cFvpfqEtCPmapEettOYnneg6wn+0ZO4NJk/nPfZgyUNyC5b8m4ldHJ\r\nf0ff+0LHB1KKH1g7rmVHdphn8AIQKw1bpJnwStgLbSfoi9F8VhEoVXoWf9qM\r\nwe83Fix+p2Q0KjpzbU/xhDNAFSkD+whrvgg=\r\n=vfFp\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.3_1653694564814_0.07404235075795018"},"_hasShrinkwrap":false},"0.6.26-beta.4":{"name":"@synzen/discord-rest","version":"0.6.26-beta.4","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/isomorphic-fetch":"^0.0.36","@types/jest":"^26.0.22","@types/node":"^14.14.41","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nock":"^13.2.4","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","debug":"^4.3.1","express":"^4.17.1","fetch-retry":"^4.1.1","isomorphic-fetch":"^3.0.0","nanoid":"^3.3.4","p-queue":"^6.6.2","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into Redis using a producer, and is consumed from Redis by a consumer. All requests are executed FIFO.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 50/second ([the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit)).\r\n\r\n### Table of Contents\r\n\r\n- [Install](#install)\r\n- [Usage](#usage)\r\n  - [Custom Options](#custom-options)\r\n- [Handle Invalid Requests](#handle-invalid-requests)\r\n- [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n   ```ts\r\n   import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n   const consumer = new RESTConsumer(redisUri, `Bot ${botToken}`);\r\n   // You can use the consumer to listen to important events. See #handle-invalid-requests section\r\n   ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n   ```ts\r\n   import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n   const producer = new RESTProducer(redisUri);\r\n\r\n   producer\r\n     .enqueue(\r\n       discordEndpoint,\r\n       {\r\n         // node-fetch options.\r\n         method: \"POST\",\r\n         body: JSON.stringify(payload),\r\n       },\r\n       {\r\n         // Any meta info you'd like to attach to this request\r\n         meta: 1,\r\n       }\r\n     )\r\n     .then((response) => {\r\n       // Status code (200, 400, etc.)\r\n       console.log(response.status);\r\n       // JSON response\r\n       console.log(response.body);\r\n     })\r\n     .catch(console.error);\r\n   ```\r\n\r\n   If you execute multiple requests asynchronously, for example:\r\n\r\n   ```ts\r\n   for (let i = 0; i < 3; ++i) {\r\n     producer\r\n       .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n         method: \"POST\",\r\n         body: JSON.stringify({\r\n           content: i,\r\n         }),\r\n       })\r\n       .then(() => console.log(i))\r\n       .catch(console.error);\r\n   }\r\n   ```\r\n\r\n   ```shell\r\n   1\r\n   2\r\n   3\r\n   ```\r\n\r\n   You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n### Custom Options\r\n\r\nOptions can be passed into the `RESTConsumer`.\r\n\r\n```ts\r\nimport { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\nconst options = {\r\n  /**\r\n   * Maximum number of invalid requests allowed within 10\r\n   * minutes before delaying all further requests by\r\n   * 10 minutes. For more details, see the Handle Invalid\r\n   * Requests section.\r\n   *\r\n   * Default is half of the hard limit, where the hard limit\r\n   * is 10,000. Has no effect if delayOnInvalidThreshold is\r\n   * false.\r\n   */\r\n  invalidRequestsThreshold: 5000,\r\n  /**\r\n   * Whether to delay all requests by 10 minutes when the\r\n   * invalid requests threshold is reached. For more details,\r\n   * see the Handle Invalid Requests section.\r\n   *\r\n   * Default is true\r\n   */\r\n  delayOnInvalidThreshold: true,\r\n  /**\r\n   * Milliseconds to wait for an API request before automatically\r\n   * timing it out\r\n   *\r\n   * Default is 10000 (10 seconds)\r\n   */\r\n  requestTimeout: 10000,\r\n  /**\r\n   * Number of request retries on API request timeouts\r\n   *\r\n   * Default is 3\r\n   */\r\n  requestTimeoutRetries: 3,\r\n  /**\r\n   * Multiple of the duration to block the queue by when a global\r\n   * limit is hit. It could be safer to block longer than what Discord\r\n   * suggests for safety.\r\n   *\r\n   * Default is 1\r\n   */\r\n  globalBlockDurationMultiple: 1,\r\n  /**\r\n   * Maximum number of requests to execute per second.\r\n   *\r\n   * Default is 50 since it is the maximum allowed by Discord\r\n   * https://discord.com/developers/docs/topics/rate-limits#global-rate-limit\r\n   */\r\n  maxRequestsPerSecond: 50,\r\n};\r\n\r\nconst consumer = new RESTConsumer(options);\r\n```\r\n\r\n## Handle Invalid Requests\r\n\r\nIf you encounter too many invalid requests within a certain time frame, Discord will temporarily block your IP as noted in https://discord.com/developers/docs/topics/rate-limits#invalid-request-limit. An invalid request (as it is currently defined at the time of this writing), is a response of 429, 401, or 403. The hard limit for Discord is 10,000 invalid requests within 10 minutes. You can listen for invalid requests like so:\r\n\r\n```ts\r\nconst consumer = new RESTConsumer();\r\n\r\n// Listen for API responses with status codes 429, 401 and 403\r\nconsumer.handler.on(\"invalidRequest\", (apiRequest, countSoFar) => {\r\n  console.error(\r\n    `Invalid request for ${apiRequest.toString()} (${countSoFar} total within 10 minutes)`\r\n  );\r\n});\r\n```\r\n\r\nThis library will delay and queue up all further requests for 10 minutes after it encounters 5,000 invalid requests within 10 minutes. You can listen to this event.\r\n\r\n```ts\r\nconsumer.handler.on(\"invalidRequestsThreshold\", (threshold) => {\r\n  console.error(\r\n    `Number of invalid requests exceeded threshold (${threshold}), delaying all tasks by 10 minutes`\r\n  );\r\n});\r\n```\r\n\r\nIf you'd like to specifically listen for rate limit hits, you can use the following events.\r\n\r\n```ts\r\n// Listen for bucket rate limit encounters\r\nconsumer.handler.on(\"rateLimit\", (apiRequest, blockedDurationMs) => {\r\n  console.error(\r\n    `Bucket rate limit hit for ${apiRequest.toString()} (blocked for ${blockedDurationMs}ms)`\r\n  );\r\n});\r\n\r\n// Listen for global rate limit encounters\r\nconsumer.handler.on(\"globalRateLimit\", (apiRequest, blockedDurationMs) => {\r\n  console.error(\r\n    `Global rate limit hit for ${apiRequest.toString()} (blocked for ${blockedDurationMs}ms)`\r\n  );\r\n});\r\n\r\n// Listen for cloudflare IP bans\r\nconsumer.handler.on(\"cloudflareLimit\", (apiRequest, blockedDurationMs) => {\r\n  console.error(\r\n    `Cloudflare IP ban detected for ${apiRequest.toString()} (blocked for ${blockedDurationMs}ms)`\r\n  );\r\n});\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"bec964955dac7a7d42ab29ca0f63e3f173df0474","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.4","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-3kjMMNN6AkKbPTjqEgJZ4AnTYSWk2OY0HUNyNKBUF/inmdTedV2QMhIjTwoBpQt3SbRLNo11i+jX+D2KAmdSrw==","shasum":"01eeb4415e5792244337801e1c4a20445415f074","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.4.tgz","fileCount":41,"unpackedSize":158829,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDJwsxiu21rX6+5oXikt1b+dB6Ex1H4NSKV/gpUfd+AiAIhAL61TKYXviDY6rWXh6thuz1dAUQ+iGSec3MHf6eOJJXT"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJikWG2ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmqhyg//e2vhyl0KSaZ0cQWBYowU7LgLxty0b/PuVx+mQSvevV/y2FY0\r\nBDfyFCDDdqSYaGwRibQBkLAjb7pHSSKnlkdaV2rkDm3SejprS8r1TUFDcjvs\r\nTpWvCvlo3e36qOL9niNUwZlfoNCPghkdGK5ES/zfBfSHc23ONViV2ByIdFyP\r\nBnX9XQxW9nWmZrZvUrfuJC2o6SZrEqk/SdRquT2gcsQQyaSPdGfn+lQhGBVJ\r\nf7mzYYP73xVolAY36xQ8xVyDgj5Vkd5A5xHNwS24KdWeMPFLtFFXeo194X73\r\n5sK27MN3pLbt0nQczNesGc5hknUfAvNqPowRoEcNmDYWIEdpIYE/KVv0m0mE\r\nkpuBGDGvd8o/xBiDMf1RhZhRlzQftYZ1Plxb/UWBSEnDwAK6g57oGLixcw/9\r\nmUNkAwEDISMmSaKVK+at9wffAiauVuV2J8egi89IkCWUTRzWfYHAW3HRex4P\r\nuh1fOGtTsj7ESKzJ/G6XnUdMEwMGCGMLHZfIek/SptCM5UBNJOgkebbxenPY\r\nm/OasMoaCeW9UfIwisROMoUFqw2MHRsniCnUeDZagFG41ZK2CICKqJI94Rk3\r\n0Tq+r206bZR6eCjxN84hnz7cQqbjNkQHtqHUeKWt4Y9vPcZjdyoLNU7O7+pq\r\nrF8os4dJNwmslnuTqCffJXYPmeHi5TSHF/8=\r\n=l6Xq\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.4_1653694901878_0.7142484433553153"},"_hasShrinkwrap":false},"0.6.26-beta.5":{"name":"@synzen/discord-rest","version":"0.6.26-beta.5","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/isomorphic-fetch":"^0.0.36","@types/jest":"^26.0.22","@types/node":"^14.14.41","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nock":"^13.2.4","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","fetch-retry":"^4.1.1","isomorphic-fetch":"^3.0.0","nanoid":"^3.3.4","p-queue":"^6.6.2","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"8fe76725d3d01fb9353a880408a4f656fe5bca93","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.5","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-fcPbup4kIOLQ2EEvlclqwdVxzcA6QzkaA5wLWZJ5lcgG/4jkvqa5j2nlSA23BwU06gPlzWEDBpipPOFX+WRHVg==","shasum":"6e80c42bcf39b0c8adc5313a09d1a3b2d676ec85","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.5.tgz","fileCount":41,"unpackedSize":156720,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDB5yjrp7a8cPL3orJWgUmSXRuq6bqUKMLBLSughcGt5AiEAm9cDduyvK0/QZB2Br//qDNfiICabtO8B6FAyRi9p47k="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiki35ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrYBRAApDVhf7fq/qcR8MziR+3SK09frLLCWQeFqslH/by8riddTIS8\r\nJOJesMPKTNvJfK4DxCrlpoYwOuviwc/pGiTLvEEcotDmjflhDFn3CD8pUmhB\r\nCK6ujKrvv1dPpNi5cDEBrDDeQHTHA/rYpbrALY/PareD11CKFyJdSrXufuan\r\nWOtbP6KKvCcUJzfkkR+VesGYbSUGsXR6w/YnDGapdkeIRTE4oL/lUhuvMMZy\r\nbqMJ9sfhktP3E7ig72LkqLF1GLBugpsQz2rFCGZ1JH/eeQmgWypGUGhF1cd6\r\nC16rOJnU7Sd8nJntLjjd+65KZLDpxQENr2QTTbLfSfnsJ9ANk/DH29qvBCJM\r\nSf47ayHIoMvn+y+9fkFViSXqa8iG6sQo0yv/2bZLJePLaa66BZ7hVe5ZShHS\r\nJPSDrXXkaQ/rABQjsm7wdq/0+ChISlEl7bHSTw29dhnshAC3KwjtzBqMKn0n\r\nEelD/qq/DWGjLS8Tx/j+pTSUKj45lyzcSMQcUCrRYvUEtEcCSK5trJl0QEOb\r\nmSI103bfkRZ6A2Di9whkf8gHH2cZRdSIAVHtPR5OwtfUygmGzEeLaDT6jEGp\r\nFdPPUAZqWQgkhgZz59DC8awJRbwcRcbNUCnw+zyoBLMdWA+Lfz1TPm/Mn1xW\r\nI6fhA9UGKhmuKFf4BG75z6kiYzh5r7QTzoI=\r\n=MCPt\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.5_1653747193057_0.18627312214270408"},"_hasShrinkwrap":false},"0.6.26-beta.6":{"name":"@synzen/discord-rest","version":"0.6.26-beta.6","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/isomorphic-fetch":"^0.0.36","@types/jest":"^26.0.22","@types/node":"^14.14.41","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nock":"^13.2.4","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","fetch-retry":"^4.1.1","isomorphic-fetch":"^3.0.0","nanoid":"^3.3.4","p-queue":"^6.6.2","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"ecf0f59775bba8731433057a6161f2530396f830","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.6","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-hOAd8xgKJsCiRMRzKr6n8N2ACG11fFvkusR0k1kzEMzKLv3RqsY9DpnixqDoKBKEvEPgtQB5UaImaJXyHEjtsg==","shasum":"e00e5fcf9278e6b22c1417cd8f3c692d464f6273","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.6.tgz","fileCount":41,"unpackedSize":156472,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFuipH2NzKgE172CDpvcZRNxFLISmwm2TUoQeYm9oHhTAiEAnQkM1PUb/fGc74n1LL0JwkZb/h2SKLYmdnIbY/IwAJQ="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJikjBPACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp5iQ//dyRrc3K1hKO2XypTrIuB6eflAj832WM4ef9yJd3xe9qgh5wQ\r\n/6hAX7O1d/YXbbCSFuj8xiRNvciCkIc5HImenmH2gBggE2053QvY+j6Hr9+f\r\nPo00VrcBZvHdiJEYmtmYwgfmWbf5IlgS0trs34OA42K9QUp/umTJ7VPE7rMY\r\nDyA4FeXyyFaCvd2yZBcNgGXWSEhM4cKQWnUXX7nMk6sArWOBe1O24aOI2FkR\r\nUdg3PFaNVt9/flurmYb8tb9LUPAKev3W7KIBrVexF+BEgwe8yzg9aaa30Xe5\r\nb55F4tIEmWKfJgaxrPgBlXJ4PVPwavGH/HLkRYoLGKv+YIRXjA+WFC1paNlG\r\naFBe+GskL0XX2oRxbQkgPcoVb8fF480xZSqKp8eUmvPNs1uefrqyfITmyFEu\r\ndM+4XMXVGEfjGr8I/6Nd76/R7Do1N1Mbjzi/g19x4Qa0EXokIkpdfvOT6/QY\r\nrPlrUFQ0sIOcUMGN23/pv/aTWBenT7DkK411s88Hi9M1BCMHthfXtjdU8tjH\r\n4yGNO01HezdYNXGcsaIiRCqw94p1fwILpK9qktTTgDGsqdrwTVwsyd4sbS1Z\r\nTb0NaEwJIzA4ndXBSV18376mIdirVjdEsLLufqwTyflEUbphfAeSuNEKxz/V\r\nauHOG1/8lpELC4yOJyKzb6TVUc9Fym0y+I8=\r\n=pnJx\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.6_1653747790977_0.36967437785070945"},"_hasShrinkwrap":false},"0.6.26-beta.7":{"name":"@synzen/discord-rest","version":"0.6.26-beta.7","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/isomorphic-fetch":"^0.0.36","@types/jest":"^26.0.22","@types/node":"^14.14.41","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nock":"^13.2.4","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","fetch-retry":"^4.1.1","isomorphic-fetch":"^3.0.0","nanoid":"^3.3.4","p-queue":"^6.6.2","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"c770e2af6936000bdc7f683afcb463b6fe64acef","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.7","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-JJgjcO74CuDfSbHMuUrvyCv3OVi+vLLtt91xozNZiitpDdYA0yoef8wB+d/PZSXcIZTr4EJGp7LSZo1b+By+0g==","shasum":"7d8258bbdff6ca8db546b21533f01d4deff29979","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.7.tgz","fileCount":41,"unpackedSize":157438,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGVf5nDcs4pXKjjnsBwaFZPwQEwJygbBaL+Z9bxwpdomAiEA1jlV5xI6EvKbGX4YPVn6P9rsDpMCzWbx3ZwhTTibzlE="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJikjXjACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoftQ/9Fo8d1lw/X06FoI4c/76OtgG2X4e1rKMM1r5zwXPsXgO+ZVRD\r\nN5Axd+RbpipNhqXlaCCAIQ81I8FGJ7n2C6g6VMXBhttM0u7khXhb1BPQePMA\r\nrTZzR1P2x35LZ2mjB4nne7XT31kIJ/ys2smLv/MlBqycEIPPJm+HIUzzFAgp\r\nsUFYMRwJ8nB6jJiPnet+fXSuLMdOXejS1/55bxxL58xSfaxU3fQiZ1POt5tf\r\neZawtKVEIEs9ZY3t8p6lIjYaUJL6kUGsQqkhkiBtemrryv77voezxsYAJ/wa\r\nFfuRV7zGZqi1A8qfv+GBsyss5EoVB4LwtCunIJS3hFKmdgMj0nV0nS6KVvz/\r\nB5pwt0Et5Gl3O4B8/tDrf03Tpvz69HGLx0i1QVWQbWP1ZTX9gNhmWX2XE1yG\r\n3XD0OVWHq+J1BTnHHGjpHC6itl4BJLyT1R5e7FeVFzTvBkcJs4jsswpdt2DT\r\nH2UQwRYEAnEj3GX6lskR7+uDzMBzq91j3xXn7Ar8AtR3sccCRAJMZYN19qX0\r\nWNburO2RMLEuxCRyeKNhiBUpsBLPrHmalADu+LbA5upIHKQZmf14qn/hPi7z\r\n++mUBjles2Gj8YvoEyRm6wSfPqRQcVTNxOvwlov2f0p4bKuvCvkMd6XmlbVq\r\no9k116omAxSgoaxxb5h3iJefvCX2d9xdN8c=\r\n=8y8L\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.7_1653749219802_0.2007193930739508"},"_hasShrinkwrap":false},"0.6.26-beta.8":{"name":"@synzen/discord-rest","version":"0.6.26-beta.8","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/isomorphic-fetch":"^0.0.36","@types/jest":"^26.0.22","@types/node":"^14.14.41","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nock":"^13.2.4","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","fetch-retry":"^4.1.1","isomorphic-fetch":"^3.0.0","nanoid":"^3.3.4","p-queue":"^6.6.2","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"a2be70657c3c29694a115facb48572bdd9c5bdd7","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.8","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-6dMYKrjNP6Jt0Y/p/l/+5EEz1VFzNPIEuDVPk4KbrKQxb+gxdt1AG3Ihy06V9un8LHixzNF8FvgIqeEIQu+bNA==","shasum":"9515a8c0c6ee543f40aededcd9def8e4dc6a1315","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.8.tgz","fileCount":41,"unpackedSize":157858,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCdHbVEfTQGsOIO4dD3I0od4X77oKpf5ocxQaXZuN23LwIhANut7mTX6k5dsb/ATlQy2qxk21KP8kexEzPYX6cHMuWB"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJikkF4ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrJChAAkMqMWnAo6ZhN3VwvzVZoR78SxY5gbGc1CtsbiFQw6Zi2SkfS\r\nfWI3MEqiX9YlVkZjp8L9LQ6aRwm7CtBl2diRxghzxrBk56bkY5JMAKlvpGlB\r\nH16PT9N9mzmFtADK2TutdQO20LIctzu463jJEG1lQoUhkGugAqmOTh7xJzkF\r\nmVWrp1GPG9cKspigid+mWzH3MMfaEcKKrykhjg1h0vx9vCNEeNKLt1hdjb2K\r\nofz/LuFQ29u82Y/Uqj88lA4UZHBDgNzujnei1sbXpBNryb75a87qZhgUXnzu\r\nRZ2491e32775nJfAG7daU7O6hR8qGqU5OVww4o9n1t5zvu1Rio7KmHQAA1mh\r\nbm7WR2sqvnxcoN6HW2wiRUQElYhsRGW+j1bSs9liEAE3MzBYbVMajcAJYmx2\r\nbbKXm1qCSaRBpMByk/lRLMuP+nsrcMhX64nBCPbcLFNbB8sjYWh2yZTXgPxf\r\nhESkS5HrT7ORpE+nRimdKo0rR6PdO8f+BWdTDhOBY5kkRzg+pgYMkTdZp3bE\r\nBoNW/dAAQu9vnWUp1PBRdvpXh7FQM96se/j5ldl0JI6U4IYbOqQ8GzX6lVUk\r\nmE0VzV00tlclkOq5Jio7hptMTTZVRiCs9q4f/0NCjQPVG0Vl4EIn3LIixLEy\r\ngIzCDze3+H6g/4q2/Pwg19wHz+oIf0UyBGM=\r\n=ROzK\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.8_1653752184639_0.8225301812729386"},"_hasShrinkwrap":false},"0.6.26-beta.9":{"name":"@synzen/discord-rest","version":"0.6.26-beta.9","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/isomorphic-fetch":"^0.0.36","@types/jest":"^26.0.22","@types/node":"^14.14.41","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nock":"^13.2.4","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","fetch-retry":"^4.1.1","isomorphic-fetch":"^3.0.0","nanoid":"^3.3.4","p-queue":"^6.6.2","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"c46367ef99131c0bfcaebdba99b493790bcca506","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.9","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-GI4wyH57Kv+0rSxE9ITaeeD722Foplwp6rFUCt8TrFFNdevDLmgTJw4W+9oGrcD0pRBPz1JcAlOE7+IpOm6iug==","shasum":"1d44a97aa955212282e053fab886973c16286b79","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.9.tgz","fileCount":41,"unpackedSize":158011,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHxSLYn/VwNvprdOfByoqesugrvBYpNr0rtBptxtSpVEAiAJDy8B++PDi82nUhzPJsyy5EhZ/LUjQpSb3ynBqdzMiQ=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiknFpACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo8UQ/5ARljxqSsC49BmVs02R1Rdg9gGc7rmDHK/YyMZtgqKVetJYa5\r\n64EYgyD6dByRldjFBpAnd41qHIg4RDcmKFMeKJPx/sPXRm5a1z4NXkOAWKCz\r\ngachEvXyiu8gF3tYq5p23il2Kl11J7GbvkJNtLVH7DjfvPKsICe0MOOcJ6LW\r\nTgFL8Xsui0SblFHhHbDn5Lf2PtyqLiyym75O5gYxULtd07ZU1u0APZMmX5jY\r\nTad033op21XXk4pLtdvz/RVN/6tgY/eBXe/kqEQCnvjmJryQ4MtBqlrZ4rYL\r\nD7SJK/rlLuj2aSgVNKYkeGs6KwOrZLWfi7IK17ZNJco0PfgEPq/UsNgBrNTJ\r\nut+FMYvnRe1aFndfZg9S18p90aiY/dOn9caJnjBgttZNyXa8hvN9QFwDRzw7\r\nPvs45QMiJmnkMWvqlln7uAGTbvbkPNfrlNkl+dZbNjVZkg7M3pfaU+3rDqFC\r\npZWxmzunhUq7AZKiEeEdfRzjYjT2/YBDPgHJa5i5wN2R+SzaEsifedRsK20r\r\nn/eh/LB+vqx+6ztqKiie/jcYmyaI1J8Ob2W6IzQskxwVF542KAFvGTnYLojl\r\naGe3TucuqW0n5coP3jOvt+UOkosGz0QRfUmnOq5pQeTLtoNKoTzbJaamBVz8\r\nBSF1r0l/RFL/6KpQ7pyr3OOFcnD9Q5wv9q0=\r\n=D0Uw\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.9_1653764456875_0.4628132834751615"},"_hasShrinkwrap":false},"0.6.26-beta.10":{"name":"@synzen/discord-rest","version":"0.6.26-beta.10","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/isomorphic-fetch":"^0.0.36","@types/jest":"^26.0.22","@types/node":"^14.14.41","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nock":"^13.2.4","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","fetch-retry":"^4.1.1","isomorphic-fetch":"^3.0.0","nanoid":"^3.3.4","p-queue":"^6.6.2","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"fa096cd59e07b10f52b76d2e42286bdefc9bdb0b","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.10","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-d1XmyZMX0AZ+Z+XH0cwNsqx6XCeZmoA/iw2TjdRyEJgzisN/gHk4Qy2aWhOmhdjbxzJaH7I1bTzV0JWOQP21Ow==","shasum":"be40edfd9eeed30267e1e046cc8e7bf2ad7b0d9e","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.10.tgz","fileCount":41,"unpackedSize":158717,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGBfG4cfCMjWkc4EpxFA4HGcVSSnCHbGV3pn6hd7JENDAiEAs2iKiMbDFuiaK3yQSEZLiV+aDg+IDhOakeX4P+top1w="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJikncfACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmoo+w/6AlwlQuCpX0NQxRu2f0JWbPHDSTqLqTaCWjp+4CiMPpBu2y1O\r\nwEJeJnqS+NpNnUJgzEcAY0iV19VvN2t/6DQL6Eox6r8DlrZDYIaO0c7P/DNT\r\nEM6FfCGl2BlOgE10Fh1VmZ5ffHe4ZEnNWP4GVehf8tyJ+5AcQfGoV25wHJSW\r\nlNytNFdyjpmgdeBGD9/DAf359rlM09lwOQYAO3o03Ts+S559+pABQxuhDphO\r\nZJom8x49IRU8JQy2Wh/vWEA11qrPCKJvcsdNcntdAZiR5em8/JpFEpOOm8J9\r\n0pcdsMojfPXzO0n/psRXmlP1Ejr3dy7R0mDhUERPkbzEG97nwA2SMCd+zN2y\r\naSIKOHzbkxblr2VYSv6Yos8+TSuBu8PDWUd9TWzYtW1NXLE8KGzxSi0LHBC7\r\nJYnKlr1O7Wv6W6vBV1NMdHh3aL1TSedFWlPwSBZ1ojCYDKz88eIc43ErcaBs\r\n0mDrJKtqxLO/LnJwMW6HpxPCAsIQH0EFxDfacQKKkBGAfjcT+B/n2+5sINQk\r\nLB2oqQbkK7nuEF8+iVMeiwOuOvW//IG+ylFsEFW1OS7RfiRg+fxyXYPxjqOd\r\nDmfJObyZOQM2H5ecbHNX1o1maEL10G/QcHzZb1Yu01p5BANxWy0BFxnYvmX0\r\necA+Q3nCAHFQlTmcg3lvz6H/qrpAWMH2uic=\r\n=5WOT\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.10_1653765919334_0.45527664493281694"},"_hasShrinkwrap":false},"0.6.26-beta.11":{"name":"@synzen/discord-rest","version":"0.6.26-beta.11","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/isomorphic-fetch":"^0.0.36","@types/jest":"^26.0.22","@types/node":"^14.14.41","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nock":"^13.2.4","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","fetch-retry":"^4.1.1","isomorphic-fetch":"^3.0.0","nanoid":"^3.3.4","p-queue":"^6.6.2","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"d60a2f9b3cf5cc86e3c70c723f7c023f363e942c","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.11","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-vjGgI+5UPe2kFFs5UOoGLdY/sTJzvJQgM2j5GvtAuQxoNYig+CJhGk0g9Ypz5p6ypwQuMOm7dPqchx6Ia32rQg==","shasum":"d73d64567cf6180803637532813c15ef9e9dfadc","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.11.tgz","fileCount":41,"unpackedSize":158723,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCZexH7OPlTr4eHTxQzbTImndm2NId0+mJx6Zn0HHS9kAIgShxJkQuwrhdNjpVhg/9XhwSrU0CaqZwfV0MQwDleX7Q="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJikoxFACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpHJg/+OijeFQSX7cmFgcSd6DVVCRdxxW7AwOIRTVBe2yHZmT/CGPKB\r\n8KXiCBxJ9FzklMvglPWsOXYST3sZMLeM7n3pd9X3iyTXKVlszr6hPlWgmbPK\r\nnCRJYCksQzsD25dUdyVlhHF3RbCbTGLjAjRkkn/NAeKkG+sgPq1+YAxgKup4\r\ndSma4xg8boXLaYvdtlI98hDzPusfNKkG9yiDtqIO6uzSFIixEcQ3J4FobITQ\r\nlEAnb1cElGfY7x5gGhkONgzoAaT+sY0ZfGKIoB7ea/xgbLcfFAVVAm18xNLR\r\nUi53zmOXgNck6FhoXmEba2DC462+KA/t5ZRhZSD+jXBonB1ZcrNfh6KQcbKO\r\nayGTn/agBzacYAzJnATSq3JWLXKgAP3VRrRuS/+fjUCU8iq5QOWRSnvpTzc+\r\ndW5lsAls66m+d3XYCWVeVwyQY4suS2AN3JJBYPmugBMr1QhdYtIRXuCEhDbe\r\nO4SpnWT7pUmhwuIbjfB9TNQWnd4n2lk8H2R6hiTnpimLbMFb55rYnuuUVQsL\r\n9cqlT0DlEP/Vy/RBV+ugW9MJe5ihGfPlRl8TPWFA/o8K8cJYCklCsRw8l4cM\r\nmqBj8Mo/WR+KyFXqJFT3aQ8uKQe8SVyWzx49eCXIORQgYE+aVucTv4JMXpqJ\r\ncoXneysoUSyahPYkwpD81UUcHpzPfKCeeyc=\r\n=ZNLW\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.11_1653771333566_0.9058011624924949"},"_hasShrinkwrap":false},"0.6.26-beta.12":{"name":"@synzen/discord-rest","version":"0.6.26-beta.12","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"93c409be160709a330423015957c60a4abd3b337","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.12","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-ldjDO1F9+epXasDN8SCG0fryw14nH+stTXTok4DcHD2OoEhrCgT6bI4oIYAD32nK+8+BmYXrNS8yCdGLxvdmvg==","shasum":"27c32f56427bca0bc6aa1a33d6fe8e5427a0442a","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.12.tgz","fileCount":45,"unpackedSize":166431,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC8M5Ef1iqCxgmjcK/dDOSPbc0fmp3dcGXVZrlFWN/PlgIgRC/6SGBtTGYDqwRxWjZTa/uATl+65VGzNEznMi2rKSM="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJik8rQACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq1XQ//Xged1VMzQ1kYmdUujI/OfLlZLfrrZYV2dHc6D8IM4hY+ZOpQ\r\n+1LBAB+JT4Nj20yjOAxvJit2lvnT+JEt2eiWrvuF1o6gGtEeM0T5w/sRjgJr\r\nJ5+dmsvq+g7aLdgmiLQVReWAFqyOCC9m5AK5AlBUviNykjZS5uF4P2i53GgZ\r\n69+Sh7HgUG/foj8DfmpsoOUTdtUyFQh0h74IwmGgHWKV5pG8f/Fh/IQDQZv8\r\nPyMPOXO1nsnJzJEbCCcxzF++wP787XkYhxDLh6vmm5gnRLtXyoeioN9ytiqC\r\ngrXxoPQZItyptFVuKlzXx1+Q0I5M2g9Fc2+1K6mdlVJp1OB5B913vW7sXcAa\r\n/VZpRPcdXvRXafJ/YRnW86n2hf/8PRXFZuSbr5R2yyu7RXm44VbkN2y4spal\r\n3D2ui4pYTkqW1W5EzuE9YOz9bvlKnh+WtiBsebJE93Uub6s4dfgfbCmA0xY2\r\n5uaDrW5TnKlStntvFCS+KCvK4vaHbZNdmnl/PQwZxTnhfLkK4LVYSYwxuI30\r\nK0k9eu8SsNfQDfZoOvED9Sbvdl5/1O+8Cwf6NklWzqugLo8PYh5lo1ZpB3DS\r\nwcm8TKWjqPPwjKbAQHv0J3+XGvwCtWN+p4DG3BmATD2yVxZ7Q46+m+u+q084\r\n/NpF99axP3KEPWNcx9WTXllR+KcEb1PQSxU=\r\n=g61D\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.12_1653852880312_0.5730589002829687"},"_hasShrinkwrap":false},"0.6.26-beta.13":{"name":"@synzen/discord-rest","version":"0.6.26-beta.13","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"8b9bd0ca8c37a345858f78cc2eb18a95529537f3","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.13","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-aPUlwteCm72SHlF5iskaMvef7tQxD+mPqx7Sb3U1xP1ky+BJl9/N0Rt+InaVnRZg00XYGYPYKKu0UD172s6WsA==","shasum":"6c2235d2711a8b3e4640a96c4bca66fab5f6d515","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.13.tgz","fileCount":45,"unpackedSize":165435,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICnCgxQzpix56ZKMfdvZmHsnaQBpoDK6tIA4QeXyoeOrAiBaWV6z1JQL6hRt4HEBPit9PAiAaMOnAMC4yvfgonNS3w=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJik9QbACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqtYw//TZHSc8C+lK8gm3ctKrhbZGIneJhgMKzG1zKxizYxfhOIyiqK\r\nit8TxjH8GclkwRDy+oaEtOkDKAEDAgZi2vK5vV0SfcDiWPDNOpzfL9jO8iTL\r\n/io6PP+7b0bzfqtz2sLj+rVm9TNAFwBdIr6jHbg1PAOB5PXXj6Hb1vi7KsEe\r\n+yL5EFlyxLz1H1JgLj3l/PlShh2g0YPSCkwtmr95MoOGvaF+VlcPnT7B/67U\r\nRlxaWX5J3xcUcwwavj2mgCrCUNrk+ZbmjEuOAsh7tPIisgdxGDEkaQEOVzfu\r\nT+M6UxZe0E80F3wjmOhkw82pyLUN3qucC/fxNtbumV3wfAulcGjWfI194nuW\r\njUGbrC6EFB2rQlh34VpLFzGREf0uuXR8O7E9lpMA4jeY6eqv6nPLNKMyNrwH\r\nCDHUy9OeQDU+61513Por27way1/mda5nmSFftezYyrHZsqUV4OT78SF+3D9p\r\nYold6v5fodRlcGowUXY3z/896plfAvlB6l50iCNIGTDoeSWPdJOfvFkb49p0\r\nCwLli7gYhnVFVCDm41JKR2x9wIV1ElvAFUL0ADb5k2ssYvTTfkeBTXkto4r0\r\nstdhLEJq/vnWsVGur5WpC+zKd3BvKfoCWRcLT+zlY0k3jUOxHam+wuLYVGRR\r\nM4ikyPotInSinWUP/9kck6YLvU8u5R6zoOk=\r\n=Wf9y\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.13_1653855259730_0.689149049191714"},"_hasShrinkwrap":false},"0.6.26-beta.14":{"name":"@synzen/discord-rest","version":"0.6.26-beta.14","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"3bf2f7223a48d6736c3e05dd965fc5d004bfd2a4","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.14","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-lXlQyf12PIrSzXhd3i4EFnOTiUx9/LNaegaA0BIJv0ANeEHHzMgKMW+OjattzPe3c0q3fumi0TN0beRKnGU8QQ==","shasum":"ff20277e60bfffdb4a22624c8b0ed543f22b31a6","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.14.tgz","fileCount":45,"unpackedSize":165859,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDEeDdgSzJRNhj5CZ9TFff9Of7NUyfjMPxKQzvzzbKaUwIgZHY9QruwSsKvdyEifL/NqjDQq7un2iT8s4jrzFINvEg="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJik+/mACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmptLA/+MfN7R3rzfeF5hzf7up1gp45IY71JoMS0ju2GmzmYACvpaaM7\r\nvGbS9nkGLty6JZzslCwr5lxaeTdL1blizrBAovFDUJR71s/rnEai4n9qKrXU\r\nvLPRi7ABQXDw+xB2Vjlp5/qKFaW1jf4QafAbn6QKw/vbC4HRxcuy4qpECFz4\r\nvUA3qDGMlAXk/MKLPfkKxOhHRHdjFc9vEQ8irc0RTc/pSg9KMDbaBJyp7UIr\r\npfAtTZF/zHKSnWRAHuvsLpUC9nOurLgya9WsO9x09zSAcI0S76C6kCx66Q7S\r\nQHQZYJ5ribMrCJjUxuAbYlfEXak1/cO8s41zGAIIf2qOMyHWhZmY1C6rHNHR\r\n21NfKF42aje3rH6eUlW/vMuHB1J9cEJVZGCrINKhPF0Nkoz2VEJr+rerID/l\r\n2TuSpPU0XYlv3OHqRvtGpkXyAifrXzsJUpteHO/e4Bbfwei0gS59a6TwUnSb\r\nuqq0ycH/4u5LoQWMo1koqpv5cY/XYXHMqO+EMrHhQUdpfCYTp8LNXzKLNYHy\r\n4YLTcH4PnGSc1Zlpvh3nz/HUWJlkJtHohnwnj4BYwtaArvZrGu5+MlkRGhdt\r\naa0BPT9x+oxZg94qUXC0rqEoQz8AJNM06s74esFS0fypwZDYBW76d7I0qAwg\r\nSF3rdeMwgxo18nibqjxI1SkS3H51tBTAgus=\r\n=qMo3\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.14_1653862374735_0.6096856273612099"},"_hasShrinkwrap":false},"0.6.26-beta.15":{"name":"@synzen/discord-rest","version":"0.6.26-beta.15","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"18b17efa922390e92bdf436bdc6e68d38a49a5e3","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.15","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-9Et3IRtmiNfR7Azl+rWyN/M+bEXQiFL+mb/EMNVa0hfjPcwN3FNyinF0YKUQc4Hz0UlyBy5sKGqkRMZVMBH9yw==","shasum":"7e95d782bdeceaaa08ed3c4218c355e45ec0f5be","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.15.tgz","fileCount":45,"unpackedSize":166856,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDFyE5FDTuGvnkroPMNj6AuP8XA+ZcRG6bHoIRhADt5EAIgQEseyyFH+xBEvgOnoQQpxJX/o6HXZ2yCKVkf76U03hc="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJik/jdACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqjGg//X6Ec3fqhKHQTP/Qy+7ZeCVlF+PXb2mdEjO6l24y7HfavCDr4\r\ntlnsBU5WQojW+2l3BZpDyuYtDPtW1z6pffN0yBkTn6YRu7AgukML5eYUa2Ix\r\nWxCfEFBlkpSK5CL/B0iFDrI6JAqccc2GYEnpvxaLDyDD3wDx4jk9yOd+ve/I\r\nv2+M3J3neOxC5yZzw/SXUZlMXo+Dl9GJQQFOOwHunnmkYIhHgpaClmABBAMh\r\nZwDB9Q0RBsLgAePhtFJoWsx3ChGrydHsYsgXHsCmLXLinBj4g3Dtx2gwtTpV\r\nrgcSUE1snYPSjSRmW6Dud9HOG1HikJwmW+bbqkgmVEKtBY5MHwk2gsyQHG3L\r\nCsdLs/+JXEKkvSOEx2F7UAsVG6PyVcouu7I9Z1TtOui+sQLrWogeOUhRJi4U\r\nE/RvqWR/8VBAk56yEKV6FZVWA/D1zApGhm3YjvoPaB6jyrDFeXU4cjt9qDns\r\n8k5i+6K8AVzWLa3z8lNLFDiLF/jhDfwJhYBOLfquICPbjjucO2lD+SRtyH+x\r\nCAsTZT/k5lXQXhIixeOdy6aH5IP4hTmGhiuXaI41J1y1Fgwx9q2IFhWCTDG3\r\nTQBsoMk33zhmDYAhB9koOl9eZkwcufs0klwYBQbjWvLPwG6OmoC9fnrHx2/k\r\n0TRXrzJ7zhmIg15tpjQgnrAuTXg0v+j13NI=\r\n=T8fc\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.15_1653864669634_0.7453480353058584"},"_hasShrinkwrap":false},"0.6.26-beta.16":{"name":"@synzen/discord-rest","version":"0.6.26-beta.16","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"ebf7d479335024a491f23ac8a9dd9597f5138d84","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.16","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-hAZB5/0DOeW4GuMhFEtwVp5gyDpCywJAUK57E+fwUoaRVDVfWyy6FjiWnLqHG22D6k4i3aPJt/jz+1R99VtRGg==","shasum":"5e2e64bde0f00b131d22d74067e4ca6d8282f489","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.16.tgz","fileCount":47,"unpackedSize":171319,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAK/0O3DObvhV/WeOq698jx7e855oTBw4JlqfKq1AcUeAiB/Ck2CqEQfnQNim3BNmiM/6nWVv22cBBBDnkcKp6GLtA=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJilCEqACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmoojw/7BZm4kScpsX7RSTKcYhmCIDWcSUwsBef0rTnlAKknDfMrgJZh\r\nl5HX7OXco6wtg7UqsepVci5MT3OWY/K6n0sk1BTao9m9/umP2UkXU9ld8pb4\r\nIoL24yUEJ3cfHKUQyb2Ooh0G5Ij5vCTLVI9HHYHrjDJqyIyBdfZhKeK3+npN\r\ni/V6Nb6w5VzfVi4btUNleg+yiAx7RPXGjk2XnZArCWdtRdkDl79Uw0r2bq6W\r\nPYAYr4SSEIaiIpxD9Kg5QS+Ab9WfMj+YdukdSrxEZu6pJ76/Ym2rWE0ILTCV\r\nwvcqZvGwNCfesieSkXFQDZ99ZcQeH2xJsWVGN0BxAiR8UfpT62p1yxgNWWvB\r\ntMiGL7gbmreULOLz800UAlADnKmmtiKDxPqVeppk4CRPG72c5ZXQTugeELJs\r\njOWD+J1b241c90G+9FgkuHlqX7I407oUkg5ywjxTeI3aKEV6ZNMc9o5uOtBG\r\nd7ApNLOlyiBkSqcSGPecWVUhluu2OfRQt5L4Wk1M1PN+rFF6jDjqbxT356G8\r\nI2wDG9v4bSWH0uBdENq7Hm0zoeMsYgb6vgotx0HAPzjS7BKpLOW/ZfyLG8KR\r\ncBxlSn5uZZGvanp3qWMhuoFIawG+qxNEzfLL0jxPifHOilNghDaIjb3KsPdv\r\n2yi2BdD5KLrJHoGfxcCPRFJd0u5PcVCaLRg=\r\n=cNY8\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.16_1653874986671_0.8226623326759679"},"_hasShrinkwrap":false},"0.6.26-beta.17":{"name":"@synzen/discord-rest","version":"0.6.26-beta.17","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"7c74e3856a70e1e7c9a8d3c81347dd9b20304f3e","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.17","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-ofq7lhAbVZNYS49F5v1qLw4KmgbS8T1LLXu1G55J/HxAvVG7YmkaWgra0gueVrMGo5RSaQaP8xG37xzmPKbMsA==","shasum":"16d411844ad49c7e90f30419d27f85c18cda5b09","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.17.tgz","fileCount":51,"unpackedSize":173414,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDkyyK9ipdI8RK2n0TD2yoV/zT4QA76Wkb5+tqdoy5EcQIgUqOb3e8LH9L+B1juodAiP4PcahAM0KfUkOVma5jcBhY="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJilCovACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpAsQ/8CpnpyIr5cwE62K+7oEgx3WyGbY4+XwuQYoGI7ghIMm3Bty88\r\nr3j8c2Im5+M3fDRpDxe78oepWShnj4Y7K3JnSoli8vHWieR+uisrkqllqIXm\r\nBHz/7YNjALRv93UHBqIk2IhMnZlsnGslqukaeafomzurhaMW/WcVQChSILsT\r\na6amCXGdRRC4BfJXkIYZA9lq85vGHMSewGBvtR5SFEaVRIwEAQ7L731n17kL\r\nheUQMVuYQ/8+/+9zdbyrsd2gwqLxz7QYGOYHlvWyrvXprJK92I8PDW7HxRrl\r\n9j62nJr1jx1iY8NR8XQkw+WmSpZL2XQd2YC+hnT08IWSUr9CtzBpxF3Dpsun\r\nmk8HF/ZIOvVSOqkdluattHiiFSgzwVYa3dy2I0jsl4TTkOBQ16OQihqjpbT8\r\nsCW0ALEK0WC5lLNwJVVQ48Z+iYE/HAzXgNzdgcaYL3I6nfnPrZ5hK9LGemMh\r\nGd5oM6L9Hfeb59u+1km9g3mXAkyZD9UYCCJg/uQhYCB8jytKt+SPo04tF8Bl\r\nASJ/Z9iUCTfKlB2CkvBdazbXeoLLuH47eAEaRb7KQtXY8LSm784nqQCwMBJF\r\nSXBukONviV83Kd920k5NHr18MdvGHMZZHbOwEMOZZCPHZgz37C0Sm6MKGsYy\r\nehjuokatTfQyXJQEcQn/GR9G5nPvvZPitZs=\r\n=aYIP\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.17_1653877294992_0.9644740960002383"},"_hasShrinkwrap":false},"0.6.26-beta.18":{"name":"@synzen/discord-rest","version":"0.6.26-beta.18","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"8082e2d2c624b42ea5adc86ff5d16b7e45178403","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.18","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-FG4GOWDty0MRC8sxjK3j59Biwfxtf1xJFI+6FD/zCcN7RXQotXyDRTlrDVApVvfekFdDlUPYOF9xOAM4Kd2pQw==","shasum":"a3a8ef10ffe1317b040cf5ae9fa7ef95e2287291","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.18.tgz","fileCount":53,"unpackedSize":175705,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCiGZOsG3li4dERuage4Qr7+JE5DwAyKjtLknabasClSAIhALV6txaUfTX8YI64hqLJQY5NKy1xvPkzLXTSn0143GyI"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJilDCsACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmodqw/7BlNJRvNkwCBoXQlfKj0hr+XeK5HbSJoo9/sUi8TCVv/EiWvz\r\nOFFAoHYmuoMsXVvL7pJ+89bVYCYfnSag6xYOuLHhZPp6wInIVyxqEjdrVquJ\r\n/C4jW40jWfmLoB7vkByIz1hfAua//Uv+gGD4oRmWB/zo7T8YnaCmg7pt0898\r\nY9POBRdwdzDlwEfaq1v/4wZKXtkCjStRoj2StVLpLAsmX8xn7U/jaw0R6o6Y\r\nyNxw7/8WDrq5bo1vtSZLWLji7fKl/pb40CTDUOU8AYMHo++TUwCUaEzQLfwQ\r\nxjIJ3QCUOj8KZHAwhcH7WUARqHIsaCH1TqL26wvmrbhywvi603V2CNWdBeN4\r\n9sclMSi2aMEWtjfHolNiRq9yHazJRiKDP1kduzc+Fw5Cb5WTPFC96scht08Q\r\nZzGo+VLToyrazvsvgfhEgbWRSMMqD5jCSBF4PIXj+/KzBVwJRLUGfOJtfsMj\r\nGPbY5LOoFpM4RUTHAZv5nECogvV8Rguq+4uuGeVWqZRT3ir4/ucRZk14UbNt\r\n0RHntTanLEsSoQpMJpUI9Z3HdlF07zr9fKpAoR58SoTD3woZYmI0PK8OhErN\r\ns5+fnMQRLYMhLA9AH4XyBlNlDhy8l9htWsYWFKwDDcXr60AeiB458c60GxSz\r\nCwS8Df8Z/O5hQkEdyMR5ovJ0WHXuwnH4DQQ=\r\n=Gq4m\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.18_1653878956525_0.7465783642050163"},"_hasShrinkwrap":false},"0.6.26-beta.19":{"name":"@synzen/discord-rest","version":"0.6.26-beta.19","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"8b6077880751bd1e822c11767413d163d70f913f","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.19","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-cBD2N6+SYYKrhpzQ1yVTbqmSKnLAu3DWBhsj94R+niXdajXmTnYeRcO7VFtR1uQqAr5l7OZ9XR/qY2i3Wp4+OQ==","shasum":"65859c9d6528f55f7556640e75bd8e91fb5559d2","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.19.tgz","fileCount":53,"unpackedSize":180259,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCnUM4iZ6owZPblf4dV91b6YniSsHnP9zbD3niDRLcLXgIgMWpZPKWAdi6n4AjLD1lwTzvlr8GVEBBp4Tc5q80AXqM="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJilD7xACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpdhw//eyKiPJoNtwEHsoa8mzghDgqGKzDUVy/hdPIpl6TwW9RuIPtH\r\ny1JM/5yXw+jHf87iLJA+Pqokti8u/9QuBGORc+DPTS12zQadiG6KGtOv3eyn\r\neSalX/DsDLCsRZmU8J5uPSsoFsCJFQ9zE3HqYEhJE3tdLsGQvSkiiIMRW7Et\r\nZkpOaWwUZuztD9rFFBGiGOKRU6IzgsQjW8WiJ+6ww7CMnHHfKGU1Pjy0EFdc\r\nt6+PCz61d4BY6bnt9Rbt1RG4tNIghIvjI/ztaCGAn+B8VuQbkEErX8N0eHPh\r\nkvPyEHRQEdCmhetg6BLybjJo9IqXwes3RKVVv/84v7hIEUrBe7orNIIdpGpB\r\n3vABnIe8WvthGowl0ypvEg3gfQVxf0Q5Q8tWSgoeSSlXjHbX+tAUf/5VSkpK\r\nf+w8ZaNTNBMbgyUZZAqsnlBuxtrC6J873s/R3bKkEhY+rKba+LOurjFYXwuh\r\nqINqcjHL/NrLfMLWwcbw6TUa0Jk0HIllQ2U83BZwMzQ8iTECZBbnobBG1bIT\r\ngzM7FqOXx5mNJRc/QJWrW4axjGQtS23NkwrmQyipHN4qFngu2ZG5YpAuk+x8\r\nVMmYzpWKXbeFD8zS3/qx/daRN5wotH1LjnnVwo+Q+k7pD34IopKgsbVnM4W6\r\nhfmMNbzR1HkB82NsVuGS/zOb9qpR3oYy5b8=\r\n=GCUa\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.19_1653882609771_0.5226223424665846"},"_hasShrinkwrap":false},"0.6.26-beta.20":{"name":"@synzen/discord-rest","version":"0.6.26-beta.20","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"c1a9aed5ea3f743e9027469965db269b495c8fda","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.20","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-/z2W4lM+29Tm1R4annGhrwG82bsV/ODiMvI5iICDfgmL0jLMdenXicPozJmHfJ/93oOIwnuwep52ThaW6Dvyqw==","shasum":"0149355a0f72fb2132ce6d087d545f56feeb434e","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.20.tgz","fileCount":53,"unpackedSize":179885,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDlc2hgBk1dnxxEj0bwsfJhQq3RpCJWGIc4NPtEDTFtjwIhAJ4eRkY5Au0rjVu3TkFfMOUw5mlngyLpc9n19ZyfqFC3"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJilFJwACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmotXhAAkJQvYuRhiOsuvCk1/X8EGXQOCOtgnAmS5ouL8GnrrfEZFanu\r\nY7crUrmnU4rcpQKJ7JL4RPFk9jVhSNO5wuiOl4pL5wvTjXzjUBrhPQ+R4mNr\r\nERSOlEQJ+MWMChoz1birfH5iynZ0qXiLqp53XDxq6aygJdShmknPpI15S8sB\r\nq5SJBlj/8qGNK7Agjjf6qk8WI+7kcXEoD6KFuxoqSzw7MKtVtzNsqH9TdGbV\r\nZWumXH+OQirm4y7QIpQYyS9nvqHH8eyx6npWPfQ57Z9WdNrcFcy9xt1+YqpG\r\nvblZZNs9AomHOsWQ7vRRUX1jO8jiPQdEW5stnZrslw43EPYgXVqn6OfNbRw1\r\nD8jLnsDLuqTMHKP+RgR8tr9I05pD55WCdltnzH6rjjnHx9YZIiy4NuOschZk\r\n0UHS7830Nitfof9wqKj83lABSIrHkTA456J2/o63tr9OcvjYfzHlq0F9cDbZ\r\nYY6VL4Ce2cVnC8rEYYyVDLaQgRipdXhzotkiIqbIxIpcIhHGcXTklLBi4kCW\r\nH73mxfGJePbdy22Cknn9UCpr0BKs0qUxc4saX8BVTycx+iZ19bbtKh/8KfHs\r\noIQKQ6PoiyabmpONKPYiolOqLhjTJfnQd+qxh9ck6Ifcc+u34rM5RH+kqbe6\r\naG4DTuFBcGPKsxTxKQ17FjCGQcxzxBSQHCI=\r\n=T6fr\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.20_1653887600065_0.8045541047760443"},"_hasShrinkwrap":false},"0.6.26-beta.21":{"name":"@synzen/discord-rest","version":"0.6.26-beta.21","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"b72d629d7350c38ff620af64678321fc764d4bc1","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.21","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-UccVwz3MN8GYQZG34M2c9D9weiX0QsJTWTkTfseFOcnS/BkJFnKOEDYn9hbHwOvFhSkWLuvVlUimUeYWvtaNlw==","shasum":"0f0f9be9b4037cd08e448beb505e109d417fc054","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.21.tgz","fileCount":53,"unpackedSize":179907,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE+NilZIWw8mLkdS7Jwj/U8QZABPl4WCYwH2Wn82T9NLAiEAtQV6IF3swDDZmu5v/D/S9nnfxcPBOmNoNGPPsIJqUKU="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJilFclACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrArA//RA2+Q2IncexNJgQ68MOU5qEjSFhviKFDzzsSlMrdEe+LSalg\r\npq4pYcBv61o7Ky9XHiIlOOy9JWEnz1GS6hq6YLqFLrKOdSO2GjYuVpgfvyat\r\nS+MNr3GeoIZ0CykCJov+QuRC8qVr7P3vZCTZ7ftngR4VmwA2aUKBJHXCxavQ\r\n9ldIrZbAo4QP3XHmKEHrXqi321DKCUp/NaG/ZHro9rhePGcfKQQj8nWJcWAP\r\nhUtpOQhzelC0kZ8k1e/UTa4fcNXylIC25YLh9qA0mmsJcN7QmeVA4Zo6g6XK\r\nSaRXlvuYMz/GJdjWkdVMqbEODYj8tx2NSxLLN+M8EyEw35lXj/5QPcjJGWgw\r\nHgvBz/S5gRZUqEztv5+a8wEGhc5r85e7lNoUcpE9jXNvBXxTNMdJE3S63BoG\r\nTB/f9re1ogWD1xAtLieHeJvW3udp+nDF28YvZZlE2L+kVccK7THrvdxLLyX1\r\npJvq3iaXp/K8TLuiRMh9ChRc3BnGArktwlxGSPD/2Jwwb6OxcBW36gPsFtFw\r\nQd0iooNxVJPc7Q7Jw1dDtr7WxB/NoOxzXtMRi3l9SwXGmkbuZhipdnVkc9x6\r\nJ5ZEGV4Gs+BOXAZ5/AqJqU1cdIYCBkSViqyw+YZRz7HfROXgd/RtaQ7cZLDH\r\nW9UFykTsUbjDloWlvwV/uvlHNqOxsQbepPI=\r\n=6wO+\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.21_1653888804882_0.4528061245677819"},"_hasShrinkwrap":false},"0.6.26-beta.22":{"name":"@synzen/discord-rest","version":"0.6.26-beta.22","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"1cfe49d582cfca92a1edf6435aa46967e65601dc","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.22","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-qMlje8KLbMlLIh6YGEz75LZghhKWxODX3KJFGxuhzYHq43gx+Pey5DlekwjXUgPwaiRHPKRDftnmr6tBdrAVkQ==","shasum":"bdb928ae4dfb7716387f8fe6e1bb736cf22d077b","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.22.tgz","fileCount":53,"unpackedSize":179954,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAFYELeO01bNfArm356d13bA+dzcxOTR1gD8GR9XJFk0AiAOPPvIsMHBFA1HjWTQXG+wLLN3I2fYx6Cty2sR1NIBCw=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJilF/+ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq+oA/9HeehZ4O4X56dO5hOhhNJny5Zl/V/Hq/qbgLv/U9ieYVqI5Uz\r\nFq98UBsdexqtcnLu4kG9e34ApuxkvdwphAq6JVroYpq+HLrAS0K0fWAh2TJT\r\nasFAMIYQynYaz1zQIMBmNox5dUoLzdFyzwyxAXntZa08AysRedkjMvGI5Qxw\r\nNN2S2M4Df/0AJ/InOHtMWlDEdZKXVaOHHbWjRr2ULtqoP79stP8rsDuFlhJu\r\nn2Z8ceMQaNYrAwZbTk/Gft2rULC9qLCcd4V3vGZJWMVj8WwPd3il+fH5f5YS\r\nwmFWlafPKYreldRGuRY2FKMunGpUB76TrNEOfZv7Uszl4MGPFCHXN7dnmYNJ\r\nyMxbwQ5Jfby4GrPejiadLKoekmMup+AvYm218zc4RoY5uYeIWK5DfZtwBJak\r\ne4qFmXBOja0cVSZY5Bw3IBBJHJZP3+beSafijz3b1wc+9AGLELTSVPhqnh0z\r\nYoO0KDRlvIXbVLRSem+yBhBoT5a7Dk/vwy2dQcaYaSELiPe2nurQy9joDmR1\r\ntOKduHsAKaC9x1ATpb/xaHlT7OezgfmyiiphPUS8NT4VLK2bXQ/u/+dUkGHd\r\njWR1IXxClhDmLJULA7PS58dC/Q2Ao+l2wX6pSKhxeJ4AWP6lQo9bt586tdGH\r\nYWx5vEX5kHK8cuRYRzYRJdbVrIxpiHHuor8=\r\n=FYgR\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.22_1653891069922_0.3939444290057321"},"_hasShrinkwrap":false},"0.6.26-beta.23":{"name":"@synzen/discord-rest","version":"0.6.26-beta.23","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"2f7394929ece4911aac1c424d4d2e6158e24f558","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.23","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-z3lw4bF5BGsI9ib9llTpwbMV+43NL8pC55VpxlBoVRWTAbdhtxUY/j4r1Ua1BYwjIK8AU2itZSx7U0WS8iLPmA==","shasum":"3b595bc26af4ccbff1b6f7b9ca858b1479811283","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.23.tgz","fileCount":53,"unpackedSize":180870,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGpUFI0AaoATt0xBFJZopP4/dRRIe2Wm8w6eJMJTACINAiBSFIjd9L+8dWEDQ4Ifi6nUMbPlbbZKRLr26b2K1YTbMg=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJilMm0ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqafA//a0ixE39dWGk29k+oQNH1/UVAJ+q8KjbZRKFjHOpSsz+2A7EJ\r\nOvooHt5w69uvsKOzOF6w/V1UW1MvAXIf6U9dE67/eFf1vNJhCYlFpJ1KDZHY\r\nifeZxrnyCg5XAnhAZUq6ESjF1f3u8fr5mGEVqvgjEprOqrZVA1zTPXWlsZW7\r\nF/4F7kcrJWFYG2iecEXr5Hpcd9TVjo+YNy4NHVJUtWuD7jhQkWP13bG0+jvy\r\nS19qN7Zkv7n8xUoqoRI16+iQNwzdSq6A82FsG+Ku+Y49Obnp8i5P6X6I8HFT\r\nvUKy2E6FEtf9mCwNZxr5msPz4YVMvzRhzWY5oVvLYwvZBb99XRVmaiBmivzC\r\npjgCovoZTa2m0hRo6S3y07XKA9QlJsnK4fd/ypFkLWbl2q0cNKZp8Im202Q8\r\nAsLRv8fJTYsF3QIQ0MREY7VJhoxr06M2El1FtH0NwdTjGDsk/oIqFezRKRRU\r\nV5BvFP7C8UsUsrGo37rRMFdot4xaSC3610aTHr25rnBOE72ytIDRJEIEd1u9\r\nE8iu4MAz2MdoTmzvRNyhU8Q+LDxxNi5122nDdvaYyq50wPu2np48tA4SeOnA\r\nZm5K7IXl0rqbFIigb1vlQPp2B2PZL/mxlIeQd8k8COHIelsShvBocP1c4S0S\r\ngSAHoiivIHyTLXZAtLzwxA+bqSRn9quOK68=\r\n=QGX1\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.23_1653918131938_0.4957059147662797"},"_hasShrinkwrap":false},"0.6.26-beta.24":{"name":"@synzen/discord-rest","version":"0.6.26-beta.24","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"6ec07c091c01de293243019e59a2bfc21fdc87e4","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.24","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-cNk6HSlqmJBAUF3XxbW0jMLDd+tefW+nOkcEU62f9Bb1tabSudQ9+70kSibGDQOP5d6TGUgfGAdHx0pA5iIhMA==","shasum":"962dd142e8fbcd35b8516c4244d657c4a469a24f","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.24.tgz","fileCount":53,"unpackedSize":181276,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDA9HQLyQlVb058xiQKi1p4eDz7VXiMiWrPHMEU6ReggAIgQeatQGUM1tI8FdO7qAQGUaaCzgmL103jTL4a+p4hwts="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJilNY4ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpyIQ/+LGWlg7rm81QsWWlyd3u3HfOCGLthmu2kWNyvX7g1NcN8qzH6\r\nIfkUq2scmukv69KGVnRbxtgC9nWa1w2tCIoNHR7g+E1siYm+eUnLZyVORuGD\r\nY3DimV5KsNdluc4tQAMYsaXhTZsdlN0tyGexOIaobisgGtsw4UA5hpOPREzv\r\nRtgUPsVSotIisJPieH71eNtiIIZOaHzWoPngytgrINmGWxSH7e71SQLp2spC\r\nVzmZq6x0mLBwsUhc+bUisC64kRIaXNdC8vqgLkuHiFK5SyOEJ8k5998zcTA1\r\nUVIQwBfC8wZt9ffwBmqh4t54Roxg9FIlW36dZ1GaDYFqu0FPzLtAIfOUO0KG\r\nhM4dZDJ0/cv6/d3Z1MaXWZzSbka1YmWXUDASI5voUZZs9wtAtZon6x4mkT7E\r\n9pghHhnk2Z0tCiDqA9hBCml/XTVNiEaGdNDywJqU7rN6hJVa3jpGCPQrZR5O\r\nCSUlWUinbBZMOpmQVZ7ZnuZU9rWruG5WeCCv2q86rmiwHWgsMULKH2mkxJPS\r\nOxiARUdlp7+xr51LG3tXpRDar+AUOozXG7E9SF7W9XzUDDQWEXOQFW/4iV1L\r\nkHCBoPhSwGaSrMmGH8JR9s9WHQi6YpFatgAqN+NakluN5AouruTqNgHpqzOp\r\np7pxfBzlXcPCjgmeRsLyVQ31nuSEko/NnuM=\r\n=NKUZ\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.24_1653921336738_0.8495213335796008"},"_hasShrinkwrap":false},"0.6.26-beta.25":{"name":"@synzen/discord-rest","version":"0.6.26-beta.25","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"4d5a1c3de17793fbfa5f6cde070d5ed5b133bf1c","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.25","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-uOnbVHvIs5VbyPi5TZ+tEqdwXLWj6ih+WOpoYSM1Rb9z8pf+oVNgSMRw0q2qrEBhUaaIvWgSwcRJEM5jas9iIg==","shasum":"f4a4dbbe79da4cdb180de9248618eed0d2b1884f","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.25.tgz","fileCount":53,"unpackedSize":181744,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHX595PK/rTXKBaFjUKrUuUxtzslBPAcWEfi/K6qMm3PAiBI3F/dMAb2xltjhLKuX797jytTJAL5yMv2SQGmA7MefA=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJilNqbACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqFTA//UZObEIs52GOW+km1kfhMkJAjUJ7LgISQFEQYk/uzTKdS3Spd\r\n03SMuooL2xgOjrtpRz0axArp8Gw908ULKCOLYfF/YbwCwprzkhI0x7wRA3hk\r\n6ntjwny5BYvEk4eAxcFY1CaiEay9DRX3oVMam3dmnzWTJVqqBXKpSkRaHoeN\r\nL0zkx+UNGHyVzmp0AJnL8Wv44bat2Gu3xRWNFY+T12I+0tRIkWojJ5UGib21\r\nVF8Q9s5MjjXyC5T6W0Gveg5WdR6caNTM+wsbXrH52ti1krIxVoI+JvfWWqlL\r\nDqhICFQrrV91U5BrScC4sHpUFHaNMV62MvzXW50Vebuk5TmpCCdU+45OIY7S\r\nvs+QdU8evm1kBowhzLz/SUWo+MG0LRUUdKouOB2GPRevsjhE1kNybyHSZJTV\r\nrgz/x/Cz6/s5l6dDkd6OOHbTLolyNrnvEC2DLihTyzXZ9P+v8iBxtfbfpsxu\r\ny7J/DOhShlPt0ubIBOLGFmgXYCZHSCpOrcPaV/GhKqmdTeSgDwVS6aG/Trx8\r\nTPfjWDWhBn/fhRvmadvpQJAfYHVB3KDlRhG3xg0OMu1eesfc3RuA8knt11u+\r\nhMbHjawnIENXDKsfaO7IKJNpD4rxvqADH0I9FFXbY28sL0Oza9rVXDMH5bSO\r\nwI+KGWTRtZegzHkqipZ00J4suaB5g0l/usE=\r\n=hzw9\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.25_1653922459774_0.6620252680555676"},"_hasShrinkwrap":false},"0.6.26-beta.26":{"name":"@synzen/discord-rest","version":"0.6.26-beta.26","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"0ca2fbdae35e41f37842d368cb49bd2b11cb8ea1","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.26","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-ihUMDgKUxGHM39G+xXv72L2zqjW1pvx0Z4tOR2kqRTM7dxNnP/1JWPfHHicFZyDysuVQS8puLbBIrbp0cUXlgA==","shasum":"96794103bfee3ddfee54d9d3646cac4432490471","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.26.tgz","fileCount":55,"unpackedSize":180890,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD5pnG81dqtZqvLugC/JhOVulvxIBzo0nLTk2PbphF5DwIgBRoDdd8pa8L9YW3RPiiidL30sB0ePX5lFP2rWvfgVrM="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimUv+ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrRxQ//XNT7lldmjHUx1LHCI8Bgy00SmWfpG+Pp+A73ISkso1DGG+nV\r\nbLwnRGIa8HbjAbF+iiXGAAYK5whYhlgGgfdT3pvBIXn5EHaTEDa34Os0vvor\r\nA2KNJi9jiD3w7GoCiEupCziS3U+NcJaXnXdaGid33spAvGO14ZoNzUAwn2yo\r\nR9yojEacw8a3/HGMB70hPyTHBdgCTT8D/sPD/mfoHav/Sgdx+ipi81vlfi+T\r\n9vI6wazWx2pB8Eov+g6q/palsRTG0qlPouCHXA7zYTtfDvttOI6bNL7AmAML\r\nx3PV8WWOfohBAQVcwpfZF0vcW1WLziOPMbxnYgsGS6flfzAnEY9xCik1p91G\r\nLEXHRTtGAMgPyAaxUt3n+Ia6tD4Db7FcbJkEHr+CL5q9f4uYycGyuUoo2KGw\r\nY6sPa+Ly/edFp/SwnwerynnxH9VT+zlQuKgeoGsORQDXkV32GmPRGainUVeZ\r\n4XBvhtnJmdf2cTOo0vokrMFuUFd9Qmt5QGCEwDxiH3ZAhff3cyGkcirrXmPA\r\nex5PM/9lcHJnr9QNWc92oXxlFUBdZR1edYGI/3Sr2iabtKEw5GzbvFwOoY4y\r\nlgpMj5Hrv0NTt9GrxKZrKwlIPQyXSYKSkFgKtHn73UKjw4v/kK/JGkygrWbX\r\nRQe8swL4ToHWF4sYF84ErSjSWdc3N0hCYj8=\r\n=WcMl\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.26_1654213629830_0.26721156118034917"},"_hasShrinkwrap":false},"0.6.26-beta.27":{"name":"@synzen/discord-rest","version":"0.6.26-beta.27","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"d6e0776d4d2e816926f537a02b15229a511ba712","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.27","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-AGktWsf5dRZz+7T9FgtN/1W+J1IyrAhZTJOa5vGdWb0BIxpQafQl3kgVRsMoBWQl24oFQmsi296NkGJ37vozfQ==","shasum":"e5da53b8e90060ae1c24ffed2969a46fe18a0b0e","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.27.tgz","fileCount":55,"unpackedSize":182794,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCoM0ZjioRvYnodzhMw3fSw2aTY8BajN+kiFl6HkT44uQIgWKzHEymoJik8OgV+mh4XbPK/qfzS5caCz4+H7EDQYqw="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimXIAACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrqFw/9EG/KK4nZ+qxe9lSioEd+2pPWZZY98KEKBf9BqKiZUtsOgVG+\r\nJ6wI093hOwP/l6hhqfh7x+Il9qPweV1oR11ihWJVbfdok/RAoK7o2wUuJF0s\r\nXRgmX+Q25VuC3zVBe9Q2YQUif09ZkQawoD4GINxBSYe/pKWO6xMrKmfxmeAk\r\nPlM1eogtWUO/0EskeM/+GaivKfsf4UTTcZwmHhfNPIEzJW5oVKLPpz5+Pr30\r\nMwZp/JCNyNWEhkk9lUfMKb2yG1hw5Mee40Ive9VJu05eUeIPHary4GDXofI7\r\nwFB63y78a/UyavUKFERuFszcIaUhmbXVnsETxf8pcFygQ/S5J1QOR3vfXPn7\r\nysjL605cJ0of47jDQGEhQ7jm3Ixs1/eWSu/vLzrl+Fsd/uYQFYsfyOtc1jKD\r\n7cgWuLnXftN2HJoD9IlOVJG9AZ/OuJQJcdVJZfA9BMATVIe6HOQYZwn5+W4C\r\nfiPy3yLDRWenrKF/CDf51VF74LWlQGxp/4iAV9M7nLcY/Oxat9qN6Lfz1ZmQ\r\nu2nm59ULJMitZuMVQIC56sq9p1dbwzdvi0SrGBZRLiCiwOETndBrUOi+SE+L\r\nDzZFgWo+FUgt933lYZf7YX7X3cD4ctlUrM4gKggXn9LLLxA83j088ANQJczX\r\np1ZPlmaqjzqT468p5k5sTVDEFHraGyQ2D4k=\r\n=euks\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.27_1654223360083_0.807698154761693"},"_hasShrinkwrap":false},"0.6.26-beta.28":{"name":"@synzen/discord-rest","version":"0.6.26-beta.28","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"b6b95252ee89b805b77850577d4616d2ab7d3e98","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.28","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-dh2Mk6Wz1gmeD9ApkL2HaK8a3x6J/JL+wBGeTHwc5BnV5DmPH/80knq1n3NznUkj6z+BH+4AwtIO+2pNkYncBQ==","shasum":"f7c834f4790a1451c90b79d5137a280d57a05e37","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.28.tgz","fileCount":55,"unpackedSize":182851,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEAK638yQzQ7ybMNhJD3YVH9Enpax2y4pDT4OkUPYnBGAiAD2fYSGGYVgXjqFWSYQ2be+4xLUHyYo7m7BxA5cG3k/g=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimXeyACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpQFQ//fW39wcRkb7Aguwgin4/rPFHKiG4PSszC1AN87CNfT3htHKji\r\nOWoOBPLNtPksXr4ipIdRXIVthSsgnA6bzz5xODieZsIk2tm4XbL3qpJtw1uk\r\ncQyRpMjJNb3NJLk/2H1P2eobT78lx655HaDAi+STavydPe6Q/BBk/z+bjU0/\r\nS2tlt3qsG60TT1Yx80UjDR/9J1fy9ndeqjL5NAsjBo9fhrBmUqkqbyiHfGAp\r\njJCx40ju2pKvoB1FHoZ9vA7rvbcLW0HLy/80kbF/KVu0Lv8BXPx9B/emZMA3\r\nvy/ONuwf1QSIVAeZNO0MKr4T86JoNva4eIxhHJzXk5SYJWkyYi46Y68uo2S0\r\nMksb/cUMzdILw9nTDlfgwk72hKgtslQ+PiV3609hIPS7vc/cVAHAj+2d+5o3\r\nwbksXfvpsi31JlC0V/wPFmJAfJx84y1xXHsS+/kom+SphOPBv8UAjRrmUFec\r\ndwCnCBhfn9Ojqr4Rzu4FWfl62NJfiuhGmzBAA9azSZwYLD2RVxEdLSwbRiAv\r\nMfb82l3OOu52qqoNIaPkZtRhAmMoxmOXR061pXDPAfXjI0NOuaZJ9sQKfVP7\r\nJ/QVaGjXFKcvrqCOR5vBdvGeyY7AcJicFNq7Wb5OC1Vs1iFq+rt1vyydxRXk\r\nwMwh8M+vYW8cbgWbx6RYDs/Ml43OoDPspaQ=\r\n=zvRm\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.28_1654224818187_0.9786283149696433"},"_hasShrinkwrap":false},"0.6.26-beta.29":{"name":"@synzen/discord-rest","version":"0.6.26-beta.29","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"963c53c9460330aa4280341207cdb6fe361cdbef","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.29","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-uO0PZLHs9OYj61LNy2O4WzPjKSaSSgSezPBDowuV6+P/PPnMlrdAGwwerCVLKpuZCT3670M4U6Y4Wjnrt1O0Ug==","shasum":"d2e3d6d2678475b0f70f4346b036af4e4166f046","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.29.tgz","fileCount":55,"unpackedSize":183306,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC7dSEbNMhv7+LelPC5CNWYyVuKoGSlHNw2jiwLG161lAIhAMASCMjXgBna87UEbTQMnTcqzRBsAx9TFS4DXfea58qO"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimYQVACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq1RA//ciHMk8j/NG1TzXVAg6c4t73rZUdmZt7daM2WcawaFylx36fg\r\nVmvyBrSVpweUiCcqrTPk8Mm8u9HuGEARL+MxEurlwVvj5VZPyawnSANeV2LZ\r\nhRKaEGNTeqwO7MIuPTDjJpY00CLdY7woIY4ZAgBIWkiGpiKKkUWgvXVahSGl\r\nNFv1P09lP7Vf37gUN1HFq2Fjbf5zB2Lce6moMbtOCXl9ekg2+98hsXP7Dm8E\r\n20mP6f1lSJ1mCIFDbnuFMZu/FnfxxImSWHd0FqqNFooEHmgvWEkuABv22XVy\r\n3YQ2BsNu/dvoFXi/Pu5VxRT/Lt6w7xpPRn6zMqAcG1GIzakwnNDB/De+Lbyq\r\nuO8/DkAii9F7pRArG+5TZ+0Xwi7sQa65YrEuSnvR/JnFusdTJQfG4ZSpzTMl\r\ndna1vA4jC5bpuTSMdry0iLtDAUZB37KWUjtEJ7rbshjKlHbsno7QebleKTYP\r\nvm88Tt6v9JTkCZQn19LmQlNoMvdZlx5x4F+1BthckmzLDVu6C+RLpFosKelS\r\nC8xUG7hPXe8Wh4FsdDVjhcRE0N3rNFfRVKInVqevOj4ua/Vo7qR44InAFN4I\r\nqwvjvaJzFytuL4GyifclHYXMJkp5M78q9AFXHjiMIY6mI9paAkUttnxs5NIi\r\nMFqnwXkw4Ibs5PMhVgmo25102hPSQiCg8SI=\r\n=OyiW\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.29_1654227989486_0.49474829575977"},"_hasShrinkwrap":false},"0.6.26-beta.30":{"name":"@synzen/discord-rest","version":"0.6.26-beta.30","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","fastq":"^1.13.0","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"f9a6340a28db310c584b073f750a442efa7c9523","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.30","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-TRc2GP8VFPP/aVyYC/RLq/2dhp/ngksL/1pykm5Q8Lc46LUXT763yfK61of41Sama3HigcwdT52UHyUXjZn3kA==","shasum":"75e964f8635caa74808a18c7738f3054eb04a982","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.30.tgz","fileCount":57,"unpackedSize":188573,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDxmgSu/oS89BS508aj2/qdmbUV1ZIycPm5rQTvY+aWZQIhAPJFGan1GH4Nkwk6SUBjhIQRs7iLUJmNStsDNWkGqFPF"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimfqNACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrmMBAAkvEgxVlmomndLYJjKBeV3LGf5ZjB3yGUsk3lqgk4295gux+1\r\nahy6xHtayEXG0K6Fba5ezv6+kXnwQu0WaC1r/Wkt860WsOtgdv6UHTI/c/+Q\r\nL6FevIcZwcRj+0ra6sN30JkSnhReMMJ86LMyYGB0NT2yznWT+R/khQ5zC1V0\r\n39kA7rQ3mrHruvfLtUyBDov4gBFRwGg0e7PEt3jIIDo0aZzdd21EpSCXZmsS\r\nacEwZTpVjsrAetafKyIOkxK+UowaTzyuUbGS86vQzpvS4mptYF/kren5uwiD\r\nqR36yeKhyGWfVl+NO7XHfQxQCNoCsUoB/YsWBd0hQFi0cdinLMSuqgtOdK0n\r\nrx9jZoyytRyqtDMN2qTlU9dBn+b86nS5yxws0VNNvApLiCdWGAYEt0HAFeRr\r\n/hpwhh6WgyEAxrzzaa51GItNaaN6GA8PGkkubr7V8iCDs/lqyH8T5cEQ+Hix\r\nd5NTzjJ0JfaI9bYa8M6cB7lNSruOzVLcLn/UG8sZBAinpRhgrH2+eaK2HcV1\r\nb0TKq7pklp0Vf/kZF5YGw25OGgH7NXEWIUXpni7D/lSGFbdaU5QUPulRf19h\r\nkCnZnn6EkqoQZU/JUDJDzonkwZJOWAqgI29xLK/J1Jvbb4qwjIPxlIcwrpSY\r\n4TwGLah17EgBZLCahgrmM1BmLgSrTiCKnPA=\r\n=LGny\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.30_1654258317373_0.03233550051008982"},"_hasShrinkwrap":false},"0.6.26-beta.31":{"name":"@synzen/discord-rest","version":"0.6.26-beta.31","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","fastq":"^1.13.0","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"44d83305a9af0118d84921631f3cf2967a101969","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.31","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-E5vrMugW69RjGmEVzhBQJZYr7dAA7z/ZyZmLQYbx7GyAURJvLIHfc7ZfCv/M5+p8SUajfoAzIumfalQOcAKzdg==","shasum":"6a5f4e99e564278ba0232c8a2d1ea693865f557e","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.31.tgz","fileCount":57,"unpackedSize":188503,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGe/hpeYhFlrEHUQafl6aTJpavHRXwXlCrzq455++OlHAiEAlgNa3/vEP+aLB1B/JhvLbq2GxlsxTBtvhmGwYlTrudk="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimf+RACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqtThAAhTpjWXzBce1LXdvZbtwsavYX4dDWRhr+TsD1kT+tWjYPsrGx\r\nvjUNG0ytbSDdX3xdrxD2c3GHkenYT9xO9Nc/wW2QOEENnXTzAA3EItR7v6rI\r\nyu1kJfcn3tygH5tNZnO0G6UW0ZH2AUYU0K7WIE/5wFIBavMKXWoqu92tt40n\r\n2KP6jHZbDqVxRZno45zpBO4qeDDlhyFHTQNrbq5mP9GYBlvjggL753bswPN+\r\nI38BFJEo0R/Tj2S2ov/sbr8DUEpJZTGDrGKVdZHyOh8qDO+FMBsME2248z3v\r\n0bqOx2iQwpi/W1B2dpEJPV1J2zb2Ii1NSHCfHlgE6Uy0SroxHACby7Lq738x\r\n9Yg2NCIEl4p4y3/KdCzgv4JJ7SFV/ujVDmGM0+IIZk5M6zAfs/PJ9HteTiU4\r\n3fFvZaX8YpdZSDBhaC59z3iu5hFHDNF0cu/iGtWtLViGuMeMy4OLxsjPda0r\r\nRAPv7TODXwqDGzY1jF1PQkpJfNHYYkqHNiWojPjD+1DpETFzZ6MGIlPgvi4A\r\nXxgyO+1TwOcANbesMTON7wp/uTyzsXaJQnZ3SAcsTetrqPxSP2pNQsbTVsZg\r\nKbXOxGJuQ2ZbvAX4Yx9uIyD3KTlPug9BJSHE7aA8KTopCCMTtIUxtC5+rAtG\r\nLW9mxrY32ibzgKzZtBtso+zBB11ISwCYBAo=\r\n=dOu1\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.31_1654259601314_0.7113524911759721"},"_hasShrinkwrap":false},"0.6.26-beta.32":{"name":"@synzen/discord-rest","version":"0.6.26-beta.32","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","fastq":"^1.13.0","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"0f44cd74a0f536e8c7820c7922467506c2669f96","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.32","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-ckMyMlZEkwDgi0FjyoPrHbZT3kK1rIqImdiFhLeIsImYKOgGM+ch9RZWdYq3vpmoAP88psClipC4Uswj4EeTgA==","shasum":"f8f386bceacc7990d40fb10ea14b441333333fd6","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.32.tgz","fileCount":57,"unpackedSize":189226,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGtmnvb1WoNW1Ir58A/S97qllblGHbCXvaS9PUEUK10TAiBD/1vJy+y58ZOQ1A5Bw7LTs2B6qOB1GpG0FNSsVbuAFA=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimhVwACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpbAA/6A9eZIpMKoNN7OgJzgCDO1lJsOh9G/fO6611N2NvptdYzJuXT\r\n9UVo4osCoHP3/axlINY3GSLzuoetFXYuapmiFHFTRYCxoTNfMuRBEXV1XoyK\r\nbLkg0SwhmmAiMj5TmvsMT3avBZEegwP8QVQPqCHGspIf4ENXI8+FwoVmOnHW\r\nB68+RfYSu6w7otTyAGt5o9QPvKgc+/fABuLL0BelAvtO1hpcfHNw5+/ierFK\r\n+eoNXyu7m1lomsphuPgjkl8Lrgypx+WLrJYX5wfO152GG1nFYnOeNIXDySNH\r\nHrtFAsRiz9O+6TnCrwhp7p2PeiSNElWdVFbwbcoe1NCHpbc9yx7tkORfDbyV\r\nwVreReddoyXfg8WrLeLehKXoZrxkQ2Ely/oJZ8tSOU6WGMakJEJ9mcMDqu5h\r\nBEfD4z6bmkrZziviZVszfl3IDZ3SzPNknZT+ir6HBblEVAukUO5LC8CZelga\r\nRogs+YQgAAo3K8Oo1xXwVMCjTun2d0RnMmEz3L5QONoHSuFSJYUALSmdIDly\r\n/yOJZpP77ql3p7cPG3UAmGnAUgmfAj7SNyR3lFOi7XbLQuEZs6q+r7PFaO6v\r\nahKsvL7+fMDLz3qyG7ngcC2jn4hjLyx7JlQ4o21uADDERwzHTpaJ5T7oeev8\r\nFVVwfeQmzvlKNrhPT5CsL9PX7mQhRfugSnQ=\r\n=3ZHh\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.32_1654265200266_0.687019195605812"},"_hasShrinkwrap":false},"0.6.26-beta.33":{"name":"@synzen/discord-rest","version":"0.6.26-beta.33","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"c1a8cc08bf644650032efa97be560b111c928f9b","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.33","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-oUc/eNiUEsc+tfD7ADJpacnBI+s2NW+G3Ft06QQb0o1YZFcG8963Ai6KKm4IM7T3sstFDMDimSmuQK33+wqlrw==","shasum":"04a9dfd7a371dbf4e015dbd1858e9ab976e304c1","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.33.tgz","fileCount":57,"unpackedSize":190269,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEbpXw/PvhiT3El/04MHJe1TYbRh8TmlOIi5zyWOVPfnAiATlbZ8PAvrlSZAPb+cnXnP26MdN5ljnyg8iKBeXFvJ2Q=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimsw3ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpyow//fbRIdN9DyhGI/QWT+j71KLhQul3MRhWmmhC99OoNwQ/cPcB1\r\nue+zJ003BtMMwDWN6tnaRpMAxwNeE6FFz88KlRptMm6GmRFGKLzZb7lN3Q/p\r\njZL78qBSmut3HAooh5X2SWN1X0ONR9PBLvamfiTN7y6JB2s2y9We+5Mr39LE\r\nXyLOwr/V1fG7MzWpkON3OsUwgH3sn65jTghZnTaXEnIsDX7AByJM3v1VW1Ze\r\noaf1ut1randVlQRzMhbzdhuh6DMG1E0WLUqR3du4HsNUBB0f8djuLaL460y+\r\nKpNbdiLn4m8MTtuWAtkHO3gNsh22Z3zubOK8Vlw6DtXUjdkneGr2y9k+Jhtl\r\nkeBOrLr5X9Hu+U7JKEeWjyoxWYLtU7wy0gXbQP0FV4kMA4CaUku61o1d73xJ\r\nVCfIHg+ha/QyHDZaEzU2ullSs+8Ll1OaBQxtxlVWCHrhHNm8Dt1CZqCRrsUh\r\n34Dtg+v1QvzKhuFG9/NRWCiLpzmE/P4YrS2o/eGPicGaxxDZiVhGgoARgwjT\r\nR3PNnq0J2B1GutJq1kxqLai3DlfgbIxmH1qvGYqRr/R8fUmUK796Ocrhd1p3\r\nIHPEDj/YLLWK32/lb6ewDf3/9b4Sx+4nCyvjCrJaZdDgMdtchtjOoPfIeMiQ\r\nu/gUdlnqt3gI5G8y8qU0MLUdZFiiLyFVFgI=\r\n=Rc4j\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.33_1654311991543_0.2744415541947358"},"_hasShrinkwrap":false},"0.6.26-beta.34":{"name":"@synzen/discord-rest","version":"0.6.26-beta.34","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"ea3296ef306b797997c0c53d07ce88f4723b8459","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.34","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-RyoO/5k8Nfhq0EuK6KAHucBxnJrvljbt/psES+jYxUyRzXMrO8ig4nX8zvMEY1JcyXHkHArci4vFpbuq7+BmBw==","shasum":"d625e8fd99bcf42c4835b9d9d9b810a6fd26e6b4","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.34.tgz","fileCount":57,"unpackedSize":190418,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCYb3jvHR7ACXIMaV8E3MXAjcRalaLX6vaGd4IIvmsWmwIhAOn9UpK8D+Rhj3lRNtHzYxPPFRn64UNK33Two4DONsgb"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimsyuACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoGnw/+P1ga+ietWPJVlLzqFk8J42z300Mbsbh7M+pclHAUh8BQFUpY\r\nhZlMfJXDPdVbKizx5bCiHVm6nTr1Lyo88ekzzIzFOTEJiJ98I7JAYPAE32Xt\r\nG5IFj9gIOYDM7JS1/yj6Fn6qHWVIMQE6yxBlGG0qYXc/K7vTYh68FPjzk5vS\r\nvWcr/StzOJ+2QyEcdmniGqBu5Xiru4MVHvh/zrHoUwJy7nS+oY6jqdOwvn5a\r\ndKICJ2xW+m7K8bzJ7njv623ETXrVin1Em7cpPXiOL6f7i2UcZmn2xHM32/jy\r\nrKtjvwF9q2YNjNvdmKAD9mFiVQmNVwdbeaq5+hv3fEA08wdaLA/OAdXG52Zu\r\nUTh6qyd04nYdEbaa0Fq0Vxjg6nckeJWzJlPGG1Bs0aAui4ibEa32XMez5ZtQ\r\nMeQh1IsoW9TtM75NTS0b7PPT+/tkYLcFio3ZDEfFRbyER8CV0TPmgD5Ok2gJ\r\nUgxRa6qa8jxtvvvaNO6mYcDzkvqAY6Kj5+9LeAsZhbiDIAUOXN48NDA8rUez\r\npmrMV7mZlmPhxLQgca4lvQCJrOG8w9sPLBCAS/DNpZV2sZ6q5IJ4Vl0Cr/16\r\ngnwaNJRCz5kT3hlJ4Ts/ZcACOqUFGFX1ymq/SWlB9H/qzSpbmY4Gwkcs3az3\r\nlFC321WwZmSZGHYPNWM+T4L3/ATFpvtEvMc=\r\n=Bs3U\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.34_1654312110476_0.7879981808312773"},"_hasShrinkwrap":false},"0.6.26-beta.35":{"name":"@synzen/discord-rest","version":"0.6.26-beta.35","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"79a782fbea87d6f36ae82ae0b0fdf30cbe452a2d","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.35","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-d8p162TSxbZIC+jTyrwqhByg5QQ936qA5RCy2elq1apvXocp4GW5PIZZdndddDMIS8uetUKsGpeco2kowfQAFw==","shasum":"61da5ef4d374dbea09a27d9b811c8866ff41535a","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.35.tgz","fileCount":57,"unpackedSize":190615,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICWL5Jv8GvuAQaAhqd/27ZEepiTuBKzHpQu05jw+RYClAiABfm3ZkPOnQWCcQSpORJbamyv+EX65eNdJFlVsuyzPqw=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJims+OACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqO4BAAno2CwOn12cbH8HAZjQB3lc/HlGXkM1092uw6xzSlO5mPUBIJ\r\nveb633BAqj43nDplwl0Z8Ny4FIJ97ziAAdFV8IA+yi5ZFH5pyqBT3YoW8AbW\r\nI5ow2/ogkXqR5JCc3YKBBEfa09jxi26iNgBfIoNIw/sowHuGJ+7pe4daXGlx\r\nl09ACPCgn8oe+rygPdpnlq5w8yH7jaaDDPjeuWbb7ZJc76cf0FqzCNqA1kfy\r\nV5BVbdg5vlmKjVxfe156pvRQb3/w2qkfsJTHmEF17K0zALXw0oTzGQxNzyrE\r\nqRLvlLMqWR4w5x7vlG5b/rQjv6rA4RyI4u1mrLFHRwsqmThwr3jO2ENrc7O2\r\nQAVnfL+KnYZnsXxsDcHsqelj1zVS70R177f11k3qq98MCooHwHWVxHr7Yd1I\r\nCMV/PEUfVhGYtDxH/DeimZScwbAWS6He63zCeOUe5F+j78RyCIgSlohgXMIH\r\nvR5aIggaswxPp8WOD+7ZV5I4rpFJ8fIrEoodGbiuLT5UY2GrSGztknK2oKGY\r\nWvd4L2DZgBiOe8DzSqSfKkbW5nPxmWIG67zcahCrCU7C/NoIxqGRHhakwClq\r\nwEoltz78j35pnVHk0Ypr7wdWtO+EQ8a3LePWdcWyiZCWm++ndBBOowMs8r8B\r\n89EPUm47w4RZSWdCm5QrnchK9Mj5DE3K0pQ=\r\n=0Z2U\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.35_1654312846561_0.6012940336251638"},"_hasShrinkwrap":false},"0.6.26-beta.36":{"name":"@synzen/discord-rest","version":"0.6.26-beta.36","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"281d3d57f1c1679e39d1cb5ad7f2c42b7745ea74","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.36","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-QPpdtHK54ggOEWxLOAw0KVSBTCCxK9A6/wsKSMWPBJ1Ih9jadcA/Po0Z40YGGIAsRYlKQ4nYdx+8w282T37mxA==","shasum":"3bdc871c84847f05f94536c2c9cb7ddcb1eff09f","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.36.tgz","fileCount":57,"unpackedSize":190634,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCF0xkwXM2uG+3ljEVYWRYhSyhZMx9XbFwVGXey2ohKCQIgGSg+qZXB0bLqFVYsvlvpBDCGQqMjCE+qpm/0JtEA3DM="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimtEmACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmogMRAAlcxK/0U39GYLG/PeVMfCN2kMLeyp3YK8dddpPpCBL9DjR+hf\r\nRQd6iccc16Y/I+IoOqVvH2WmFkppNwmmyLh0mrpFc+uanCER2i48pt0KxmHV\r\nIvCaKRq9udLjM7rxLYx4LPGDjFC6Rrb+kZ+e2zIhVJ9dOJI5vOotjCC8SLkx\r\nADOxT2fVJsCcyVmT55PXfWn0g7PgrTEn1aTvKrRdSxOuUhuMMt0/PpXvTnMe\r\n1Yboj6gULLFYVYOgt4mm54jk5SGbhcygUlqgQeYS9Hokb2Oejpb6bvaFrmvT\r\nTTuPDjYkwtyqptUWTSoSpUw/S1lWMHjA6LUuh+DNUdZt1P5IsXwEscTrSpqN\r\nNbNN3JVRABE1+pNA/gv8ihODJIpSBQDCj6wOo43fsuO/UKAg2e4HBuY12IiT\r\nfrLtjwUW5oVgkZlXEqLW+gB7H3FQrnFl0TkY2RxbMgx5OQCV+TDeCC3eafPA\r\n8KNIkv7nWzaFNGvCTvMGboYlPaplqm5cvSaOdtF5lkk4bsar19zFVtvmO7dE\r\nPnwSM55f67/+ZMaoVC2fbfdGaYtIGXxH7Y8p3Di7SvCctY5pe+u6O7OTAQO7\r\n3OgSk+j/DIm+1kCenoV35YPghHmhlR17TE5K5AGDMRibh5SwlS+jDf3J2Sx+\r\n5DBVP/5r25/UAcpxzoISoGF9Jf6rgSDnmHE=\r\n=YMFn\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.36_1654313254737_0.7436025276930673"},"_hasShrinkwrap":false},"0.6.26-beta.37":{"name":"@synzen/discord-rest","version":"0.6.26-beta.37","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"4a50e94e062a8677be138a0a1e2d816da4e42fcf","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.37","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-h1LCbpkccgh518lvSphnEgKJo6+lq1DqrpNw9Z0t2vnXeP96DjqPg1ZxrCa/9IJWLpEFjGL3EAK+761pOD3BFg==","shasum":"b94fb0b8742a118b011179f5b1acbbbfd8b98980","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.37.tgz","fileCount":57,"unpackedSize":189412,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCMtabH/i/UayI/tSm1aqux5UlYOKkayL8KxM8oc3pozgIhALeomsKGFEPAVfAYAA8toAEJ8knie+yP6s2yYpMlFJkw"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimtY5ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmotmA//Z6MM96wgSt705tyPN4f745qZ3tw5DBSrEp18six07dsx6ArU\r\nC56IktWdP8dq1lR+oAD3p89uNaZJvYIQu1kvuevnP8IJ2avBnRatLVUOeiMD\r\n9gROvzpPlK0o96SfH66y3DHTVYfOW5izcxvOOIPI7bayml4sbl9hkwrwQf30\r\nx/u80ek6sGVuOXNe3YpfsTECrWsyXOudWdPX208LYtU1xPUrVGJq4eHNDRnc\r\nrlfeJY0eFE564A7wgTDoEYZecdhzn76zRgyY6nLn/hP1hfFnG8s1G9iUFRZ7\r\nRJSuQUytrJKGvnJztOQ3GvcVKS84fNmLKSjjZkQf/KmHDJQizxz7zXWts6w+\r\nEfRceX68bDAs5vk7BYd8Lrrh5m1llk+AcNL3m5YE4+4/fnEvbDOicWtutXvm\r\nmEfXxOzniKkzD0Ml+xOXsLQlIDVOajWNUUgzbDNjCEDNwEhO2sP9RmxDaKff\r\npibgIXusSLOs+WFtI94m1gQYRo6k22q2Wz8TvvkTmEWm+PmSwODQ2jdeDZJH\r\nbHAEi7JissmoVztkjQWr7cUI0Cg+BVAOZbXB7CZnFGiEpaxEqC5c1XxUp2Os\r\n2v2qkSTmnKMP9SeHS0XpntoUsGz4Cr/Tla9xv6r8HPzaAlT8VVs2UY66SNoJ\r\nEEQD8KJ5cLttYxuNpTokNzMV5Y5R992x0wY=\r\n=cEI7\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.37_1654314553236_0.4767985656686109"},"_hasShrinkwrap":false},"0.6.26-beta.38":{"name":"@synzen/discord-rest","version":"0.6.26-beta.38","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"a1421af57b91544b79f3a562f4e630284b86a993","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.38","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-N1QQYpCBYatU4THRQS3c7MP4bOFquwDlTwoLTEzFXKPEQ5koXWak7eR47RHIVxBEX9Ft18nDsz4oxgfu5StWDg==","shasum":"d47f445212d5dcdee204159e59603aeac8c93a7a","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.38.tgz","fileCount":57,"unpackedSize":190423,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDSe9j4R01BslKgVQuZFnFX213HSvZTToFiqSslC5wIQQIgC6FHXEKEUcGVti0pvYsxG+8s61WdxhqRkm12B5n4Pk4="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJimtjSACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp6AQ//TLPk8cOOUCOABBVDMRiESPqbA4bP3hLesM4qk9thB0N4u1rb\r\ne73M67s7BrbHB6NHW6+rws8nU8fLvdEUqAw5VDoHcVrYnYmlXMovbDl/elWu\r\nwH/wfAMmhnknfyL6oymeKjC+7c2VIcWgwbFAQnuFcxBBvOw+vem9ajww37dc\r\nSdXdfcpdR2/pck6o+Tb5IOaAIJYhJuD5LBdVgjrAk8GF8tNDiTIcF8vCkHld\r\nlEN96lRhJC7Pc/GE8rYnj5IaiiRexNBLnIWlLYeEMKJNCOngKyHJuZqfnxQc\r\n96uINvmMFwEcMYrK7UouOq5/2MyMIuzU6l3FyFgmQIL+SmhGhDNjEJT2Y5ff\r\n57QaWxBmfbQBsWVnEXgHfvLuZ7J+lOVEJwXr2IgfWluFf6QuxuxpH9Vue0lR\r\nP+EsVHqBss0B9ozvx1nW9mUz9T8jyxewjTMuGYibRjd7wbznpD35ygIk4rOX\r\nEBfkK6uyY52Ekm1dmUOE9+hhvBFpJNFPS6JIrWtqgFSBEqo5l/VWagz3pEbA\r\nEdhSIh4eh0L9NDB7kW8PjfTk9xFnX5yvCUMSfD7TdJJ5RJa5hqfXHe/3vSIR\r\ntoLWdm5uSzi66t2OpheQvY0pUZoIguZ0GirjihwfTQz/i5DTA9ybezp3DLKK\r\nfQLjUEaawOUvR4qWqLJ9GzUG+xmwrCcVUlM=\r\n=vlii\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.38_1654315218499_0.17447787429048578"},"_hasShrinkwrap":false},"0.6.26-beta.39":{"name":"@synzen/discord-rest","version":"0.6.26-beta.39","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","nodemon":"^2.0.16","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"155f97234f54c1d9186198e80814a5ba00af9543","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.39","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-mTwPhUl6xMNVltV0XmocwsCSWGrjKYVNJzWrHcxqvyYGoCTKn5VVCyyPtYYsDvhdtAaM6JXxm/ci7TpAL5Bd0g==","shasum":"5501d11918bfd322656517e5fd5e6ee6672c8247","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.39.tgz","fileCount":57,"unpackedSize":193303,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCjLXIPFDNw7m9pVqHzpiCC8ivgdiX3DkXdPLkrXdGZawIgMX1wSVBU3hi61AhGcOBenhie+dsduYY5GMg9bAxP9tg="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJim11iACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq3+Q/5AeqSWFgwnS6duKasMyEslLUB2j8pGkN+q/mZRADcWcpg+mLp\r\nvaYwamqxtVKR8CnDbGH7d3TEQRgJ/4CD0QsK+S6gdaalE0+2krPTbxuLaFT7\r\nfc8LnMwqtjLHNNZcgaTkbkzimQzUcMNAX8gxNNFjLBijoa7Wk54WCctnGb4e\r\ni2zx8uc0f/G7yku32umZsFgagB5c7TAZHbi7baHfjjtqdj+m7lYLdaMFozUd\r\nYvlD9zTmgW3VsdF5fGEdDEpFP/9Fkv2qYvvAVxdk/TmApsDgFoauEgDeQq+q\r\n7s2bByrra+sybvf9jxp+CLHq2H476ScCzp+9gOq0f1SBIf6Q04mzgpf9kTH2\r\nQUpi9m0Ny4HEDU9bHZ8tKdNji/HpQW5zUmJZ04uEx6jVWxMOu05pGGbZOhoX\r\nHvAjm5X6zd9v6nNqSa63k5eooznYRDPGS7K+GQx3gYjcmsY0vm5RHjrTN4ru\r\n7V/KvMTfo2hOdd2NftGaFy/uFcrxawTqtt9XkiJq/xU08CmzIUtWCUDiJrC/\r\nQ830rq+uVBYjHYYQ77mpWR2UnAkHsK06zL8DB8KUUL1ArN1EwYM/G4EQrOJB\r\njqOh/lqszajQ2HJae6+3WBFqwrn0wEugdJj/mdreXVMUcmhGV+LPJFH/Uosc\r\naL5UQsQCWk0D/HAM942E7RK/5WK3Fc+0q+o=\r\n=SRIQ\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.39_1654349154143_0.1922775248252857"},"_hasShrinkwrap":false},"0.6.26-beta.40":{"name":"@synzen/discord-rest","version":"0.6.26-beta.40","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.16","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"e882f6b209e0681ac057bcdb91f276a31cbf7ad5","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.40","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-VU28UAAWUKJRq4So2Unjqu8wQnRgOPb7JTkQcBWCpLs2RA++sMYSSHsjI38GkXe0dBXvdwz0DeYyQm9hQwG5bg==","shasum":"8251f1c98cf521396d15bb8b56e521375e3ce849","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.40.tgz","fileCount":53,"unpackedSize":195564,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDY61z4QFkXyd/L4fNPDBi+bksMqHusd7+gQW8w4mZr9AiAVNFx/4OD0SCvhhb8aI8kO6ujOoGETxp4Pkfe2552eIg=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJim+FtACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpsTA//YvhSRsHRl7BEi5Gf3gHCcMuxvTUUo36GfTEKOcCis77vYeJ2\r\nVqTM1wXdzE1PDkE+MpDhA+Hx6TJczgpQfvdrugSdVZx4FT/MjVqaMUtRD8DQ\r\nRPuoCAQGfTsY+HDbuBdEDm2LTrkh+AA+VkrCpDTcN7fovjzaDjnJTAbF8uuj\r\nnU0tlqKj18NWGZHPf5NkySGsTaTYczboHhJ/iEMP/im70K5IQHGNUHcnQ3Ka\r\napNRZhhGJzqkGQiDpR8/hM63J46Wt8lvM3QBjWNCSGq41hAER5BtROv1CLuA\r\nKqvsfjn5l9XpFglo5eIUYGWhwBLLeWUVKQmH8NBjy6TkOr7m3iShNN2dZJ4+\r\n9FxlNb+aeA3DyhLK4qDHx4preq5S6SDTXKqV5vv1C8zloNnM/J4w94L6UZfk\r\nD1v23Ayf2xtwOa+Z9o7W1T0pvgwqjnDgrw9eFC+JSkLODEaPBzjAosLJkk1r\r\nASET7qjrm5xJgao/1YmWJPSHnce1bvpECYwXDni/pxkHMEP/h0/7Qmcfgk3b\r\nCAWthbLmMocJD77gM04QYGGN6oTIArn/tLKJczkyr91dRu3S5hsZXsYvhFLl\r\nZz3vG0VkAGHxtcCVE1u2s/SQ43dHw/GSaV0SUZ7VYo1cYmglxWFjXLvic7PR\r\nQdkHmO/SG7PV43wSqbqaE+1BJKNQR9+xGKo=\r\n=4nm6\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.40_1654382957699_0.804474681175311"},"_hasShrinkwrap":false},"0.6.26-beta.41":{"name":"@synzen/discord-rest","version":"0.6.26-beta.41","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.16","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"416f6b499cc16be394922d29e1065160a73bd6d4","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.41","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-3UEZdlrkT5ZrufOW+IiKKMjy7auYfPzBsgq6LFwJ+Q+8Dq2No9J3O9lQwfJRLQK4h2B9MGTpqF2w+Gjz5euzLQ==","shasum":"c8c378aeff8af50984065b8a637f6dedb88c076f","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.41.tgz","fileCount":53,"unpackedSize":197313,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD+sIDFce/wAqDC6DBhSrY26ODlxmLSY/6CO1Zr6il9agIhAJotF62Th+8s2pec2I00oo9zT4g4GDqcfoBOv8y3jLXR"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJim+ZiACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrnCBAAg4KgsmrVpx9xCMCtH+wVMmhcv9Eiell9+qvA3Tc7x2i0eMZO\r\nJtCO5v8knSZw72PTcROIgwZomnNX9l5rXPugRnfHGQucXJARQ5M/qkt+EBUZ\r\nDSEfNDM0jdZRgCDxHdLThwuAJo6wmYjvKwlYBrdjdk17xaNuQQC6fWr60hEE\r\n6H7Ds4d6+tBty5cDke8P7FfIvQzspXV5orYuGkor+JLMb/6VAfY2zeJCc3OY\r\nx/af/IVxI5z2nBN8CAlfgwGFZxyiqNXX4EwVT+Pr/sPtHuCTtVb46m41hyRK\r\n8P7L34X44OMWyVvz53yPxjcDYaLNJyZMawHAfC9MW3m12jrWE1gNqmYvNIDS\r\n8KiA+tVy8zHVV48lms0k6a4Xowjm+faIiuNooiUVdMBNk3FoRUt3Hfhel55a\r\n929BmpYbdy5W8P0jh/wjlpbxzExdScxwRUuKdHSGqSDu3ZUDN1Xh03rpvaOx\r\na6fJqSOGPwMFu2ZAOY5hwxJkeTnKaEFtQST6RnxtTZNW4j8k6MP47A0pGFD7\r\n3rD7KMPyMxX5OCkgaP0Xm3R/V+Ech5qjEesvl5vhG9zrM9tAJLh+pnxNd/l+\r\nsQUTD7DWMkHBG7TzIjBKR1nWRhABMj16ZJgL+ZmOHcHTBYOCGuA+xj0baURh\r\nXynnvpWMkbhO13uDNGWj0A7hTXRo8fbSpnk=\r\n=j8K1\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.41_1654384226534_0.5766120494685432"},"_hasShrinkwrap":false},"0.6.26-beta.42":{"name":"@synzen/discord-rest","version":"0.6.26-beta.42","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.16","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"a67cffac2a724cc497de1c0f9019bc12d02c6149","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.42","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-wXVcDOmVzVTrLsYlbzRfuvn4NdhQGcwPVDZzFftdgsHQZRBg32/DL63CmI6vu1/PChL3dH6L73XwLMM7Nvgtpw==","shasum":"08881493fd7dc6fee62a95153daeb5c9e8194959","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.42.tgz","fileCount":53,"unpackedSize":198366,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFfsPVTQUl3hJwiL7n9f4SNyH8u5tXTivTivYlMxG8nHAiAzjfbILNuWHkJC/jRV2un61wYF9UrEskJ/Or6LfRWqjg=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJim+mwACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoJcQ//bDT0JprjKXuxeWVZrEnNCcisbdWK256aJFm8nBwYFDgJO0Qa\r\n5cqFk7TgMMPCb590a9fZHMJGB7wKRbzkT0Knpcv21F0/IUz3nWBE+N9RBV+Z\r\notjTS2dwFktlhfnilPfLFtQTlovzdje+43+3CT08959QYHXpN9nfwUFh7/5d\r\n1t6zrKX/rDVuy1dlXpc+ug4hnoa1oJ+T8Ia2oq88GdAeqHOB5dMbtSZvUczb\r\n/Lkk3ljz80et1ngpkkcLBJxXpJoVva19h9+MgNMethGIfDnv/4L4nrkSiz/g\r\nbt+aYyL5Uxg12tUQ3z9gl6gEzb52oGmtOZ6Wo2oISSougqfV8OcSHro1Zt4h\r\nqinWACnROvuxqf0OrzZETPsftSJr2lCfcyq7pdcyBMO6zmbCWXFINyeicTJF\r\n1ZHozdnSZyuJJ97pGJ3eJrIgPLZXF4a3Ny+YoOW8zLonILeCOYDX3hrEEaJ6\r\n6NoRyEOwKIUdy/FVM2p649p1cSmG73CThj7UYzayxYS5ZpYtuycAiKtPM/XT\r\nWNojbF69z4axlwOvRNc/EvI+1Fls2gqYQyFn4ElhDqD/SctNYjyCK3lP8pYa\r\nM44rpfQty2S6xAWT7kTbczSTFWMLF3i8zLBVR67ukMVN8+yko0To+bPcJBsx\r\n/7gYFf/1SM4Cij+hodTpuD2qRx3IJE2v71A=\r\n=kRuH\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.42_1654385072224_0.39435371852570666"},"_hasShrinkwrap":false},"0.6.26-beta.43":{"name":"@synzen/discord-rest","version":"0.6.26-beta.43","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.16","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"b7d930cfc278c2fda2053e72e55dab6246a3649d","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.43","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-8RP7Ou9FqP4NbJLKwF9B4ja3OgSr9Bp+AoIggWKiT0an5YDvYDQ/ydSt5l4J3TIrfqX1DggZRlTLGMQY/RbF/w==","shasum":"e140aaf6cbc54ea405d1a0e4ba6232899823e08e","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.43.tgz","fileCount":53,"unpackedSize":198560,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHcN+8KiJjNL2q+77u4M2vVt1n4FrfTffoT3sxB7RHe9AiBGfrAcvpzXzbQX/FzdH6SgF2TO9j94yaf+FCcojHEUUw=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJinC/oACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqJ8w//c3xHBK9Z/cyiTDaCW0U9+pi6h5yLjy6eseZ33TyQz+U0BeiL\r\n7Qsfzy1/d1S+YuRgRbcy+tdbuyymy+TTAm/JWVmOOVbRe561x2iKo4W4p7nk\r\noXkWlehOulUJG21ipJKqzyGAQXeD4mJGI/dGj/YnwK01E4ul7LX2skHBQIY7\r\ne4WtgFkKPM6iefirHICD19TvgHHOsCx3BtUF0RK5WeVQCc7paKLs01MuBKGj\r\nJMj35LbpetT04kHFa60qAkxA799YgBYfwDNF/se2Zt9eYU1Pf2SMSDgDoDAA\r\nK/YDKveIklKxlNZGcZjAspvBCH7h5BDb+RvDQAP6Wpc8H+DHZZbjpy2aXh4a\r\nV9qGCAvqCf04V9c+4hOfv69WWBtpXzWQVQi/SJWhoCYWubYN9res1LHqsJYz\r\nbaW2f2TO1LmxIzo6v7mHy+QW/3txek3/WkHNeO/FByHBNayRV3A7ttOxaN1j\r\nXEjDiQGNtibyEHz69MB1wPToGVEtVUuf3zydt1CwCloMa+ZIoW7+Pdg3cvjU\r\nG5SSpDhAe1KBIjIDZf/nLqCx7hPjfXeJMYnj2CNffpOLYev5K1UIx8/jAVja\r\n/J7m8pqWkwOAgF28gF3qVIch1k366iZwllR1YGLzxFARIpA3GH71IlH6pS/2\r\nScSrL422820MpmAJkaK8U9hoehJV2Pp4fN8=\r\n=NGwY\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.43_1654403048292_0.8698870635057427"},"_hasShrinkwrap":false},"0.6.26-beta.44":{"name":"@synzen/discord-rest","version":"0.6.26-beta.44","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.16","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"35be7f49976a0fa9be781aadb2556caec501e209","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.44","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-N7VQO4hBLvlxWyxrf4YvWn+83TA5knQtC3icBIbmZdNqbRDWGqNOLI5xYmJNQBiDrX5azNDXGVcCApi+HcX4vw==","shasum":"4e07edd0038222371eeb3ff35ce7665a58f704d8","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.44.tgz","fileCount":53,"unpackedSize":200592,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCo6nXX21ikzAfqVYRozWVjsU+YBIattUc9mzVyE9XsmgIhAN8OmsWxG5OKD0fyS42zkvshVuPW9qE+l0EEZzcV++jz"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJin1DNACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmofnw//XUjT2iernIDPhm+B6t5GD93eplb+jCuwk4kb2pfdiwx6nPUY\r\nEyuX7TJQH57l3WtLUQOWz4GldFu0ysvCBo4HLFj4qiJdWvWom64klG9YFwBG\r\ngr2HVfiDpX3W98BFEmTI90jRItG1DcBPhYJeN/6+cMQxjDaZf/0VmbXDw+Ig\r\n2ZzRuE+spDD75SDXXvditEX+KyDuhfVIKqY+d7brVFk5xnf+BDvsUSqfH52/\r\nZD0USTfK9RPSwIorpDqO/2bPxWyADSB4c+tCtTrn4T+e9CWaBS3UXZ1MR7fg\r\nfuLLRW129fmIEOBAKJp7SiLjSPj/H+BY7GP2rsaw3YO6sB0jbM/5tJgaGRVN\r\ncBzcRtueQdCiWGXOHCfNGaVicBI39P8wzvkMr29IwtlLG7hQEh9I5T7eTdO/\r\nRWpKUlmkTnRYHlRaP9o6lBnJd6ExWV0QPyR/Ywbm1fyTxshUYIRs/XzoDUBD\r\nC+f7xHNZdzh00Jc3Na/BNdXV1yuHF6wYUkC1uw8Z70+2GkbeA9U7RAEXxBia\r\nj5cgN8AHB9KoImvUUWFUhZuumFtRRetFD5CRzYjgLvkuetHCEW1DmGsCnUnW\r\nx0onHAdOGKTIGSW0JxzNwQFk8ejGI+clVxxwQQc+6I5CABj7b0e95jyx6y7n\r\nMLeUkMRaswym+xtzhgbvy+6CvzdbYW76UCU=\r\n=/L24\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.44_1654608076954_0.8189169343481868"},"_hasShrinkwrap":false},"0.6.26-beta.45":{"name":"@synzen/discord-rest","version":"0.6.26-beta.45","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.5","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.16","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","rascal":"^14.4.4","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"gitHead":"1a093d0b5b7317468188943556ae537f8350d258","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.45","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-LEsaj+WwFawmEmRD116mPLCzplmWQVA1daKGdnQpmMFl1IFc6lrifyeIN4Ij1Gu1VnsyanZ1tS7cbLp19u2pgg==","shasum":"5372afa7e44cb2de5333c4a0c32a8ab846f8b8af","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.45.tgz","fileCount":53,"unpackedSize":197461,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDUv0DWKZTs+HHQxzrqq3Qj2shoOQcqv/NWR88whI1D6QIgDfnHPM3+fNnHTzvK1SQs8gW/K5UkWgu/tjSl+JVhCHY="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJip8rRACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoLFA//VNnFgMn6tZDvQOTZj/Kt0eLr/i43aZJEgqFP1njCNtqz0bLA\r\ngBdRhgHL0FwPr/TcwrDqTe8w40JZ1AbLmkdDhqYfYDcclTTcIIQLwnQcTXNE\r\nlWMgtdf0NYNFl3cBw2HjyDxQyAz7j7ZuJxuXBBXJQbLqsm3qCG/3IOFg6Dy4\r\nkulQOiKEzbblM1SMzV6XZflh8Wm23RQP9SNvlATsldm4+D/xB8t5fG58CzuB\r\nmyP3SWIcoMA1w51qMkHTvJQYGYnT/13Dl04RWUwxp9c2tnRkgNg5wAoho+ay\r\n2PwRkJ2vkiOKrJ8LBUKIBMKEd7tbwv2tXa/X9X8fKkUtuuSjpRIsey534zfY\r\nc6cCResS29R5yJR58ddccPaeGAmkTUs3Ve5TFUkH7nTCW/L1idDIrlmCa9gC\r\nFoMtM2da93gzp3zsZOItoFZquzPjsxHrkCL2XYFQUQfbwVesBExypM6H8n4c\r\nXkhf9+uKnQNmT/7SLlwOstbOGD0xSkAEINmgFqVKybqY9e5hGLLkrV7kALXn\r\nuAuDa7BNUD/CkBfgmGhy6TFVrrIvhnwgCrOyxlvEESh+CAicLk3DaM3HW6gR\r\nRGJREF00tqIEIoBbLrj4K8+FA7r3tmH+9F6tGCJJcfMc6Siwgy6orceH+/L3\r\nDKy9Qwj026TlwXucUhI9aIjx/d2C3WsM1qQ=\r\n=i5P/\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.45_1655163601529_0.24487583659694745"},"_hasShrinkwrap":false},"0.6.27":{"name":"@synzen/discord-rest","version":"0.6.27","description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepare":"npm run build","build":"tsc","test":"jest","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/bull":"^3.15.1","@types/debug":"^4.1.5","@types/jest":"^26.0.22","@types/node":"^14.14.41","@types/node-fetch":"^2.5.10","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^26.6.3","ts-jest":"^26.5.5","ts-node":"^9.1.1","typescript":"^4.2.4"},"dependencies":{"abort-controller":"^3.0.0","bull":"^3.22.3","bull-board":"^1.7.2","debug":"^4.3.1","express":"^4.17.1","node-fetch":"^2.6.7"},"gitHead":"cc31cd2bdbe56c92e5ee32274a56295dcbd46b9f","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.27","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-+sVdfwxJ9x1mqf5F4hH7UhcDHNYR4+ejvVklu5Y6nfX3iQrYmlJ6sFUhlJLmRtwYecTiLRJr5S3Jd3aqJe5wzg==","shasum":"ad799a965f98b98a57efb3bb23e047c7dfc0cc9b","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.27.tgz","fileCount":55,"unpackedSize":116640,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC0n8k+SuzocpMtSPUooP5k7BMu4L4j2VCG8cbgARnR+gIgNUeQPzvLIOfBVkJIgl5eQp5CcRQZTK3OrAJAzTdFdSM="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJip81eACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo4XRAAlRxC8Kf0LbGqAmX2z2j0z2XiL+WcXWSyUuqLyBGKtl4mafMA\r\nbyCwHbLXdo6nAMGZW0HDzjscV8EViMlkZG3D7VIy6lUGfC8FeOf7QpkXyInf\r\n+pSYom5wzpP3geP8OmrTAjXb5dBL/qcXK2++Jpt1RdYLwPZS4/v8WgsG5isg\r\nUYhG5cFrNxUFsIMFb62wHQCF5UhOaFNVd2wQ5jF3oW5Hk68Ig/+y8EcThNFT\r\n6O3cIxIPQQkD+2v/H6AniGEwHjypjf8KmACsBHs3b94gZpWFv5g9E6FaFnIL\r\n6IHcKnRv3SSUQFFnj5cuYxOp6WjSvi5s2AX0PeejANs/y7/WTVH+EkIjhvCU\r\na0DvHRVLA715TacRsKQM3sr1GwhWDI6LAemqw+spDhJrjvKGvVERYKAcmJoz\r\nTgfv+zEs05d4JepcEqACAGyzQXHuneFY2C0Y8Bn3gsQAr3HRBu5IVdH2w83B\r\nlJxu3ZsX3ECNM4sYDtNee6rYJ74LXCtOmyzuzzF0484ikKIfGyIA2/EGd76p\r\nwbHPxn8MDXSWZL2JkVPIK1MJH31ENr+evD151/CM73RyB7M5q/wPiqCTHXFN\r\n1NswmscxBEwUxZ+TkthXC+mQYN7GZdSZKPRNM3BKuiRrD0hLMQmVWZDTyJBb\r\nDbjjXgB/a6o4zYgxbj5bfFTsADJ3XxZUz2c=\r\n=iTOY\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.27_1655164253951_0.045438657018564976"},"_hasShrinkwrap":false},"0.6.26-beta.46":{"name":"@synzen/discord-rest","version":"0.6.26-beta.46","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.5","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.16","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","rascal":"^14.4.4","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"621dac66f13eeaa1d118ef317f349ee185e189ca","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.46","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-e5c7ph1nDldJMik/oMSsymfj7hiXkWuhiNVRCth+t7lxigcEykrssD3sgt1NxvnFEOs0r+HcYpIkLgNaeyILLg==","shasum":"7340c7cab30bc8dc475719f359a45487b5bd9bcf","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.46.tgz","fileCount":55,"unpackedSize":198223,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDRNdD9QP+cQ7IvV+2ofTaEUtHAIuYq/OiNtsrTRlLuzAIhANHY6nQQbiIjv2yXosJh5vYCIReHs6i0G8mN8iWsO/WY"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJip82tACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoN1g//arNjbqcDlRpHmhd5EJLFF9uSkmyIkz7TgsxMajg+iB3Waobc\r\nwDGzNkt81rEC664lO0D3HHq/+ybNZ3nDTFd9pffAZimTpMhTXZzDxcc9UIPa\r\nIGDJzpzdQAqT9r+/Pmg2o3lAtyKeryhA2EfnORE85FVCCjzfCk8LZ2zJhcIt\r\n0XWSxfc+t1gjcPCK3K9cZ6P8H5ul3giICagByErFRaHgGBQEYJVv1rDSK4Yv\r\npQAHhZM2udNmHmKUhEq3FjwTNNXN/JzeMGYIj3cYxPxHyyjKw4LtA2EKfPYH\r\nh31I3oPHiZNgCvDyT3zyuBC3B/4Dh7A5MFaXycTcbF4CLd73QILtsitzOxWF\r\ntuyqrCoM1ObVpmuJMdRoS04IlWGJHuEgYPBMOw5eihE5kLqbv8xprDOGPn+h\r\nn3pedaCDzID7waxa/RCkfgthRDScasgY3r0TnI4VO5cqDhWg9ar5UTyQpNXd\r\nt1YzzAuyGTpZVRm5tkYI1JbxYL4ZEj8JJvM/uHJj5JlnXIJ9okxQoZPqh080\r\nNZ5p4ycOoxIbzKwJIPoe8FRNSIoT2RmQdk2ZWteScldI5Tc7w7WiljgqtGD9\r\n/48+6NCyzv+pykjT04nBmy8q28/Oxh7nZIEZCPEZlpzobxBr+TdFfrzPy9S5\r\nU22zB8XOdabgRUuranGADDsno0ee752emH8=\r\n=JlzN\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.46_1655164333017_0.034848977680913995"},"_hasShrinkwrap":false},"0.6.26-beta.47":{"name":"@synzen/discord-rest","version":"0.6.26-beta.47","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.5","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.16","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","rascal":"^14.4.4","retry":"^0.13.1","semaphore":"^1.1.0","undici":"^5.3.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"d6743c4bc1a2a25b4c53526cd7111716d27c97f0","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.47","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-InMoB6rFnU0Bstp5ZNsyAmAx40ZdX57IRYIjxgezX6ruCPMcIhAgPFp5w0OWdxXZbRYcsTnUvQds2FcI1PFc0Q==","shasum":"0075d13a2fff599026d651c23cb06db9ec38cc18","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.47.tgz","fileCount":55,"unpackedSize":198383,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIATLKTyKr5mUkRLUhGwG5VA0W4VaSB7fSTs5om9K98JJAiEAiueMBwWsEquO+4GL3xrOrbsjuvpaSsBCQjTm2fZeLZM="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJip9G1ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoikxAAnqItjI812FjTVOuNbwAPLo70u+L2GGRrQcAHMiT6+NyYmgmq\r\nJjfwPqfLwDUIY7NHow4IfuZmD/C4uG4ekiya0qnKqq8aPzLmiC89DwcwE4v8\r\nxCbVOSRLT/Vz0FGIRvgqGpPKKkicIE+6DzoZ+NvrlUaJP6VVJ5Gz3YMP4IKc\r\nzJcEoQPfM3dp9MYRK22NJji2I+HTBfxFYdulHqLzLNSR03o55ghHEN5zpsP2\r\niPId51U1ItsREXht7fCPjSSbur9XgShdnBCEo/8jRGWM44M+1gPQh73jMLud\r\nLJ/TsyBcMFbO3u4Ff5+fpBpEidPnwXCxWV88YuwsA5oTk2F7GtvB4OIm3ApE\r\nkUaUEuFNd8dHnMh9UPqxndAgvocc2mdfGV9S7/r6Oo7OYikfN4bxAvLAdB1n\r\nf6GTnm68axB3BRYcH3WSwJLTSB7/oEDwxup2zNSGevIErJRCLyYBnUbxPai5\r\nH4U1pkru6nv5uwS5A8iF2ZLPunDqrW0mGQLVNDALCiKeJvLHkn1pPEkou9zC\r\nOPw0JxrwqYdqaoQhVY/c+OvMtGR13F/SzUDxxxW4oMQ5Dsm/Ly1qrOBg6y0J\r\nkxwOkKdjLBt2hXisGGANHV9S07muFLH3HIqXz8IEL6snddE9e1sry5/7rPXF\r\nXxgqZzioD2SFcepMLVGA6fp7wXsXAItqz8k=\r\n=B0i5\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.47_1655165365459_0.24132316196740988"},"_hasShrinkwrap":false},"0.6.26-beta.48":{"name":"@synzen/discord-rest","version":"0.6.26-beta.48","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.19","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","rascal":"^14.4.5","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"38b3d0076cc0903a0d1d507f25b2cb7a1334da94","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.26-beta.48","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-m6wQ4g9TOt3Ly3jL2FuPwVoAdL/PnyfBrrc5gPsQ0dVxld8TrqvAMh6NYO0sMEvXO+Id0yiFsYb8tzwVvDfNig==","shasum":"4730245946c1db8345fef644ee49fdb714f9568d","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.26-beta.48.tgz","fileCount":55,"unpackedSize":199162,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDZxjLlscV7SQQijRXBfT0WOn5aOBzVhMdiVOxGJ8VPMgIgRIIoyVnTU69SXFxoPhicx1UkBMJ8SpY1Fy+UbKr8uw8="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjGUNoACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpZnw//b8jp6kBXdHhPZXTD807Rtb/gIp8b/6L+JkyTPW7Q21haUXDC\r\nbAT0xUEyQprjzVOb7V/PcjM9tC2PE0CxLrK6CEQaJ22CWU1URc0F7l1EoVxf\r\nU4yXmvNASg/opuqqb5pBp1DfutW6w25yLCP3s50AGHDUs2poza2bmxjV4VpQ\r\ntbNdALp/7DqZryEoU07awUlOqSeZsWb4JkVcLEn0B/aIR5Zbx0JRwlV3y+Ao\r\nWwYmCz+zu6LDBnOeLBKSB3p1zqH5QHofD7nN9MbfMbaJPrktWd91SzvbIScZ\r\npXGZcTfr7w6wwzrKh1hIgrHiL95pf7xTt+6JD9JQrQqc1lb3B8AJD1+mQD6R\r\nJDuTsQQNosP+ExIO8WA17jlHysa6QhUXMmBOessevrf1JYFH2oNc2vpwC2Zx\r\nhSl0IulSPd9NRfkb3yebRhC9I2ArFagRhY0JMYnJkaMpPU9lXegmxXgUZxUR\r\noJrRoMTiu7cs46j1rXyF+e31yXh6TdUOdY0mtsShCAjUmudah2ZUdbGR34FA\r\nDCHQ2Fh9X7/zCAeF+gRcItHaGf19TN+G+KiH7Q6kw12KzCx4EdRXHOLQmXt3\r\ntHkmM/qm1xv5bXxeIxXiTo26l9cTu4fbnXJkcje6pf9sGM4shjUs76J7MLPI\r\nuvJBX9LocCnOsb06mY5yMQiiDa6ngzupPOw=\r\n=ebcL\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.26-beta.48_1662600040695_0.7462202437540708"},"_hasShrinkwrap":false},"0.6.27-beta.0":{"name":"@synzen/discord-rest","version":"0.6.27-beta.0","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.19","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","rascal":"^14.4.5","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"e220cd6bcc3848f6c2211096ee9b90a02b9312b7","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.6.27-beta.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-aHq43PFB8/xNVk2Lgr3EbhedjHoqKtnBaWs6tkTQUqRe0yt4S2Rlq7DVENIveEM9poUKfYZOIk4f0SFbrPbNwA==","shasum":"e003e2dd44f530590e258cf9e3491750600fd995","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.6.27-beta.0.tgz","fileCount":55,"unpackedSize":199161,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCUVP/It6kwlJ0+JNLDXPmwYHq94/pdypULyOldVUaFAAIhAMzRdOHcPEncQlgaT8rHxP+lJMaHvmpWg0jbF4oow7AU"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjG8NTACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr0hQ//WZg90mtP53mGN1HZMijxnIdwGz4c8jxqc08cQTkqTHkySKKA\r\nMHyY/rFU4cuWr4Y5fnH1LWisortXBBut/Z+FUd+lIQMze3zOdmG/SMsJzKgO\r\nXizEOVOpzkC7sOJ3nNiP/VY0lW5PdFL67o/50l7VWtcmIlldkFSRHgOznLGe\r\ntBjHjrjoH9iJMiwKZUZ56rnu4oULEr6MamEXvYFAMtKSWiFpgXaA6GABjfDA\r\nIdVo/DoE+EOte/ka3eDRAm6enm5Utb8vSmT3RZ+5cVYW9+orMQAk0rMe+6dn\r\n2h4+gf+pZo3l792HE4oU8At1It78OYqyvrs3SzfGjBkwPqFsyDkPP0xZ0fRy\r\ntLBqNHSE/xfIuEno2OFkqyoWiqRVw4BKUKcH+nTjMsdr8uxSUfyQbmB4Hq/V\r\nK3iCWI12Fz0O7AOc5OBu32LKNjw6ivHPg777JkdwNaN0Y+yJKLD8s42M+GwV\r\nQPzHtl7p5uMEHQiUAIuihjgdF0zIT08JzIjT4z20Ww62F17BbmP2VY5iQ+5O\r\nWZwBnItp7GXcLAstiOjSQHCc27xGkk6tt99UWMYkX3w3aEyCDgXmk3P4qSXM\r\nNqJu04aJp6+Al/F97TVpeDlDOdcOemkhKj4ZkTpDHTlrZK3ERP+lnZTveNMj\r\n9BkK++pd1YF4Lo1gxswTwi/iaJoHBfxBnno=\r\n=Puc+\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.6.27-beta.0_1662763858859_0.1763950393393594"},"_hasShrinkwrap":false},"0.7.0-beta.0":{"name":"@synzen/discord-rest","version":"0.7.0-beta.0","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.19","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","rascal":"^14.4.5","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"932cd782436c40aeb428568b3e3f7ba817973927","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.7.0-beta.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-tVPhJY2BQohA9Vz3YeFcTc8y+oYFcoy1+LV7fet8w149O6ulZZFs6kdXU1Lnaqeew4axFpRlkddLsg0rxq5nbw==","shasum":"efdae304521f239f438a9c68d72e616882d2414e","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.0.tgz","fileCount":55,"unpackedSize":199160,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAoazPRnIvav+Eus1LbRo8F/wTLXFGui7XwRukSJiQvqAiEAr2XGOo+/alf5ewoOJrqbIdMZ2xd2jxn3RcuFzmADW88="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjG8OJACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrBlw/+NmR5cP2sZ4UaKRCBiC0HzPcARlZBmbzYhfXbFbqH01pBxmzS\r\nPOU1dWnas9uDiHEBpvEPYfxuiljaEHPIR7+1AOcX/NDpFrpx5zkKu1xtk00m\r\npJumJ9RMWnrbr439dkeIkQrzZMQ6EJ73Z9Fdsw+n5Q2xQ0nEIwtUj1Lxb4V2\r\nOdlNd7g9XN//LNpPditpAr3S15VGSA8dMUH3Rn3gy4Mm4QhK6WhUX1ZkH4NM\r\nS3UuWhZ248bN0b4xFokJy/pyZPIJfW2Z0BNNy1N7tKnm2CDJ2tRLaAjhIh0M\r\n2RogNd/XMvUv4XCQSYAGDOkysQqaz4pu+j9vQDNdZfUp/pwr/tk7/a7+VYMm\r\nvlhvG4X6CueO0iGZKyLwcYlY0Q2XIafCgyVwE6e8LzyfqRvV9QYpg3sEtqQv\r\nvBKHsUc2ArHZQPcucAljSLe4oPSilETJdU+YbmRNgx35rPUgZ39gi4J31HWG\r\n/C0mHtSvU3Ixk8iV8o9ZFfu2KtvkFNjDX1U1PhHusltf5n7MhNk51Hloubrm\r\nS84dm2CV+bXb2ZLP3uWhJV3tGmb00j4q/DP3uojZEV355bgqvhHOHYcaTfCC\r\nC7/pGde9WllbqFwcJ+ysKTt+Z6J3TqgL1e6o4S5RUaJ5K+kO9ewXK4RJ2diU\r\nhHk9HrwQ9FqrFGmvcNORWIwWkLuCxyIgL9g=\r\n=aSTP\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.0_1662763912859_0.2788242390700415"},"_hasShrinkwrap":false},"0.7.0-beta.1":{"name":"@synzen/discord-rest","version":"0.7.0-beta.1","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.19","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","rascal":"^14.4.5","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"c66849d0014b8b60df11f5afbbd9325dd04945e0","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.7.0-beta.1","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-PzxrKZ53BhdMAVZdFiJs3MjW37alLtRNzUZr42pB7J7YY9GgFrxurj4/Qd/W260wmPB28g1U2g1SoWqTF/Qhgw==","shasum":"dcc3b8ad7c98922f6515408fecd887ef522e776c","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.1.tgz","fileCount":55,"unpackedSize":199352,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICqOEl7kZRmDEnh6NbPqbhbBNxyH5SYdwpcq2R1ZauehAiEA6IlKzMwDAjv0D8/524Xh5/WYItHgUvUZy+UUyUDaaS8="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjHAsQACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmrobg//WtmnVlc3qwcknTA5YvllmPeifT1nFSCcYvtg5cAzqX9M/kTF\r\nG1P0THNkBvqz51gTq2sZR3KC+C1PoTB8jnQUifPLdQdeYbpLWAhxja/jbYs6\r\n3y2ezzXlN4FV9w1/Pl3uJkE6t3diOaTlRZCPdsS8nd7+lhOcmGFfSWCM5+Nl\r\nVcFjtn/8BN1RvyX50XTIFx/HuIdkxo6xQJXSS0KrU1ZE9oSia5NN98q4kao2\r\n/QXMGhNPTnPra3DBK3kkBjOzcjz2RcizndXWzblwu2dBbk5jSlZwqZNkFj9x\r\nKDMgRYV+9NFMjkBfyI+aOz1cjuDSardpO5tWQ7zNW/db6Ay/gg+WbUQDCJeG\r\n9kxzk8DHP9t27JCVLlHFXaCv7uhwndsUjJcUqpvnG10Lk2GiCZ6+4/cOTdrP\r\ntUhaE4A003LL8C8+YE2HLOJk6N3raGHsClAhRJ05PMc5Z5QSBQgmhsrU9m8m\r\neoQjIiAXZ1UrJ4gRBPqHuNtP7DUfe9Qm2UIxPCFtO9mZsXim6MVmpbIh5cPW\r\nAw/eISJSUExGNc29BjnR5fSmb15GvaS56vy1s/7SPLWadCPMqL1j72hBmu/U\r\ngqHWOc6FWEGJYAVpYwSqm4Ui51sGJQqVAuh/vxMaHderc73Vn9pLyq7tfvtW\r\nPe+gENpgVgEfpKXMEhbJ5DTNdwDL2JcC8yU=\r\n=l8Fi\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.1_1662782224121_0.32714236081600667"},"_hasShrinkwrap":false},"0.7.0-beta.2":{"name":"@synzen/discord-rest","version":"0.7.0-beta.2","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.19","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","rascal":"^14.4.5","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"98e41f4686c81e4fdac410cb0402a172132e9698","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.7.0-beta.2","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-AdAmkv4Z4WJ7lavnIdJ+cdPGI/fdC2MqEAa3lg+Y0yqHJ+FdPCo9Wcz4Vq/4y4N+jHxpSnm5bQJfH3sQy9KkMg==","shasum":"4382213175b9208bad74d4338bb1271d04cc4bce","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.2.tgz","fileCount":55,"unpackedSize":199335,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICOTp5ekcJVotn6TBgQIxkksgZY10QT2kiKrHz8Y1GFHAiAaS54jwu6/qbyM2yRnVKP1ZI3PtI1O2uXV4yWCbYTz5g=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjHAu7ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpTkQ//T44WKQkdczqLHjQ0Y1jFESB59Wnt0iNX/zLEuhJZ4h0TGJCC\r\nWMhiAn59+yM2R2UJuUwTd5lknyoOSuCcgPVvbUmAqVYmxpduYjg0LE5rsfSI\r\nU+rLyJno5nYlQja9vvSASTK8RVAQw79v69yPPGTU+L2N3owv6jBxNZHeukMe\r\ny6uS/ZW3nJ4SnUp/HNdr+gjkYbDPEZPC6KgYSlIaxONrUQTJKKVyzo+0+SJK\r\n0IzJgaPw6rgoCGiKKvOrQbZT6l9YiL4p810JcfGZhbY8qcDGZ6ErJBmP7D31\r\nG283Dk2i+4SjPQeq/0KqmUDNMzZDvVUni6tanTHF7RlokZwRr5MsRfdDyc21\r\nhwaSFW3SV/gxGA4vaS0dmS1vauEvmKzJrJsTarfXptQRQz1lyfxJS0qwuX/F\r\nL9JdBj8aeRjwiMy9MUiqEVHI+DjoP5Ue1omlgMjzH59Yz6xdX0ACX7Set9Z5\r\n5Kmb8Mu/PmejRs7eq/kKvb1WqQaV5cwcD9isufsLPZiewxQK5X9W8Pi1AMxc\r\nJWKOhWi505U2PFyF1VP4Gf+mKrBbM52nVb606bhLi8gRi+Xb4VL8EaEFdVK6\r\nJN2IC8pNaHQSxyQyp9op6C1lzwM+GigcGGGyci1WDZmF/CmTIAKeGv/cMFai\r\nPc6Lq8L7mbGYd3sNqZxB0maY359HTL+46QA=\r\n=XaOF\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.2_1662782395561_0.06262931458588694"},"_hasShrinkwrap":false},"0.7.0-beta.3":{"name":"@synzen/discord-rest","version":"0.7.0-beta.3","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.19","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","rascal":"^16.1.2","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"22de44a69708293793b1d03502bef03a61ad151b","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.7.0-beta.3","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-SJBJFVRjnAQrpuH0artx+a8T8giNI2hjSkC3yjEESuRDMa5N+hBbOhZzDE3zgFv6opKmrilLZCax4YdpP9xRiw==","shasum":"7c180afb8088e5073916a90ab6f0e33849bade9a","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.3.tgz","fileCount":55,"unpackedSize":199454,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDahybMYb3hhOTsi7NCZGWfif2dQpR5xHoOrZ37zSGaHQIgGDwuw7C0wkAeYncywK3xMU6r0Y/w2k4E/XFt/uU77qo="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjXpXHACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpw3xAAjYTB9mhaALRkZtRB+ITZwhgkyoNAJ+5GRB5pkb1MRzrQl34v\r\nh/aFs5f5249X4JAe28tDQE0IDrjcwvkycUXcd/1SNDRgLP+ImkGE0qyrCKkG\r\n5FcAug9agH3xa8TPSYnfzP5a4FPsXIdMaRQ1iqRxFGS9+NQBGQ8q0DW7JYt+\r\nwnZtTKIdiYZKGn0Cig0k3VohWqFsH7naDOV1jDWVCtoAw9MYt1RSlotJVCo1\r\ncM6pz3qBpYM6X8KWvKxEA2bdyWXhwyn3WEoH4M5FHKrLiF8QyzCDyV2wAtjU\r\nIiCNUgu39zmKvxdb3/X4IjD24agkYXB2KghZPMSXOeCL7A1ejVnV/jeif9KA\r\n8H47gyyXF+UZT0gcs5+OE+FPZU5ZTtCiS4UPKOG9uAvFFNxqb0t1j5u1+w++\r\njMYkwkHluq8QOKu2vwoy+goQyYxQV2dO+Lai9uWwtcT15OhxjT/nwBJRftpa\r\nTUZl2DcROXBt1rrnjmN59FmVDSgewvyqZfMunIqSQWaFc1gID9XyVVe6AHg5\r\n+7j0NfqBt2B60nQowcGSOKGvYemswkXy8Ir7DHjZ2Dnqd3Wmerz2dJSZMHZV\r\n2Ob2fbWKrXtXBunwlGuAhDMQHT4xRcz22HoouGE4ZvKTR6L7lO7ebge/TSja\r\nWNTs1ZsazJBX+GB7/GrDvZYg/gVsBtnelMk=\r\n=r8FC\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.3_1667143110961_0.48549440994900417"},"_hasShrinkwrap":false},"0.7.0-beta.4":{"name":"@synzen/discord-rest","version":"0.7.0-beta.4","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.19","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","rascal":"^16.1.2","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"425bf93473fab910dd85405e931487500f36143d","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.7.0-beta.4","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-udGCX0eHgVYB4SPz4sc5M6wMCbm0vIPLUz6CcDK7tFO/tihRpy9pYHhZAxWaoZgSvtBRCefmWwgd79VAvNHEtA==","shasum":"afe7494385167e4fa0323d2da678c360763744d5","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.4.tgz","fileCount":55,"unpackedSize":199492,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAw6ccXZgOvneh9q2TQuUlPF/023C9IPOg1yZnpBI8WvAiEA7/YX/iD7Ps9ZXubkzP3/01qj+z6fXBFBzwl/k/rxg4g="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjXpzdACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrwrA/6AkWSJCuN0MYDgTMk/P/YnRRG6wHbfCHspFMJfOpI2unceHJo\r\nJdlowALOrsNT+2C1TPWjUpcs4tJGcCObhwjyHbIOPDBRLNoKfxmSCY2kWVoR\r\nUaB6qDGGKNgoCYQr6xPfkrLhUDylEu8bRKhy3+c993rOCLSfMWFNA6j32gC0\r\nZz1k7DTFRbIQBsPdVjMsQgk+a1I9/U03rVrIlBGlaqnUqp0oCInWFXuHERec\r\n3Hy09fcSf7VR5Q+epCFYomsWE67vWqZxoetmsz8LLZwAof7Ceym6VoLKQVgd\r\n89xrxoONWKFh9QgKIca4n1/XuSXYzpzw6swQdJD0Nj/Yvy3yVKDKhE9kGzqF\r\nu5ScbV/pZx5f3sOxUcbu7hG96GBdQTaCeCoWEHTUi1OVKrhkF3+ZecqaXL0d\r\nSXW6trvKP6gOb+kAIH/pfMl65vXWf3xlOeYVqW8Z9k5bectMBeKSwbRbiVLO\r\nMjqjGibDW+UlvAKnVF9SSXcLPRPHjWSNdbIwmy5aOR122WqhB9pNSDalprDq\r\nQP3uGEk5WDJKWXP07OHcWT/h8rzUZxr6BSRdtRMmhZF7jA+ziNDij4nsAp84\r\n7uNDci142WIdtY3u60GYuqhTPqRxzflEgNHsBJ361MrQ/QQYl8ATIC+bsmia\r\nqtgilAy8QNeqMvxlBLetdxqiZnEVCoz7sHs=\r\n=nJ8H\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.4_1667144925185_0.4232508491626341"},"_hasShrinkwrap":false},"0.7.0-beta.5":{"name":"@synzen/discord-rest","version":"0.7.0-beta.5","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.19","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqplib":"^0.9.0","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","rascal":"^16.1.2","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"a2c733e6ffcd3f95a394104e0d3184d36053c570","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.7.0-beta.5","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-bbBTWpVaO9JfKwtLkzqUzoNbw/YL0Ls4U5Scy8I4M6+b8YSo+C+Eq1xmhO2+hL+CE6JOsjiHy0OlYeJ7/VV5XQ==","shasum":"11f597c6690050a14c3966dc1073f0be86ce23bc","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.5.tgz","fileCount":55,"unpackedSize":199453,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDCDCXDzt+iONO7j7o4ucTM8/k20zzEunTFsJGZaGRuzgIhANKVXpOl3nWSCLkHyT0gmq5a/0+Nk0eWuuDfL2CJcr3X"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjmm2sACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmojOw/7BGT7/xj5SH77vorReFItLJ0ihPT10UmXjvkQFNCSKDIJwgJ2\r\nDyfOZhI4EeTgli2lNnWKFu7FrfIROGDhlo0irJAJHf0c8jUr2rL7DAkyTAZs\r\nCYlDpul46OFhwRv12bsDgU6b2yVuxl8f/lyf9Qc+3vB1eOlhQbHOds8FNilY\r\nhD9xQ6glWVgsn14O3nTBccB6xCNUN9UN/u60/p4Yb4Nq6u/smwWwodBLE4y0\r\n6gAnKzeNlTZObY8EJd2VxTAxL12IPox9zpvj1zWOOho2XcD9wdulOEmlqBz/\r\neJcAzo+OuwGCcKpqemTKndiMnchVC4BakcDl5iI5tAr3LkuVOJUZlT438dev\r\nsnTS0BVCB2r6r3nPe4LvnEu88ypCzp61My4wIzgiZ25F6HtdpIIVLtqHpuNX\r\nI/WhVvsafBKhkwFwp+FTqZApFuDgEcTZgkAj4fIKRKMGr4VgsCbGV2QBl3wW\r\nctuswDrUxqk6VgUwXBtI0DuEcVfyIejXFD+mlkJorkdSR77GERP/S2a2I8i2\r\nw1T/5kvxnjF1y6xymhs2hMfj2KD+9km27sL13RlTKrl2ecYTqJ00v39xL+eQ\r\nDlLT6svcTWxEBLpKcsngLuJO1O/dMA96PnKhikzbuZPqdecGx6RS1YO/+4Jy\r\n8FQPoUyxaH9ePYB4pO7LWRnUWpYpV320Flo=\r\n=gxDd\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.5_1671065003845_0.0555300113339432"},"_hasShrinkwrap":false},"0.7.0-beta.6":{"name":"@synzen/discord-rest","version":"0.7.0-beta.6","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.19","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqp-connection-manager":"^4.1.9","amqplib":"^0.9.1","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"e75e0d6303c28de1f5a5d0e8a7454028051855db","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.7.0-beta.6","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-62bP0aSxZnbszMeXhr9F9Bu0sGGKmVS7TI38bm04SWdhTazKxROY/L130QZhSz4YekQm0JqNktg8PSd6G2fcMg==","shasum":"ed0b1e1fbed9ea6da634d714b9895fd7a1f58ec4","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.6.tgz","fileCount":55,"unpackedSize":201153,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCilG9HC+F0+/TyBWYvxp4WSqvojPZNhFrAlnETgChMzAIgLAS8qzYQiHkEwe/AhbtpGNdN0jXo13fIEBzqondwUck="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjmqGGACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpo5BAAonAHkc2nHqEhM1R6ElghHk6/mDYxFe/gn431SIZYtMS0+Gru\r\nEgdNuIZODFzUmZz6AMROannQ09OAZxCtQZGB3h3p9V60y6sFn3q4P/2SyT7i\r\nw52siocI0aoPpB6Hweelvn81ZEPxxZnnZTrisn+a1EUcoIcGOqLdvHRcvHR/\r\nSGkwZqO6JwqAd5EwjR+aHJHi68JXcxa22nVXFjxBJf7J9oumwBTdvdWlofzu\r\nnF+9K9HgrBZPtc9Yz2gqi3F6o1oyT/3B6KCifha8zfRBtdOOSTRa7U+DWiR4\r\nF7O2ABAeHYlTXaKR9PehSceSjy6nuNqTp1J2Ks5DHBBGs9q4XZ6iPLWpmQRS\r\nPPAsXYXQrxnW7jjF1CVs5PR457kCpic+PRduqEqfB/dWPUTAiZ8FotRSBFmB\r\nkikuc6hbTVNcAxPDAQBi3YTpAYlZwIHecgntzfgRBVDdyn+Rxz3NLudtOFRT\r\nqym9ejieVb9ZJ44x4wlJOTf6syzjgpuKN4HOQLlooGK5KtNCP1CWPJPTHiVH\r\noUHCecaUM+n0xGvLoGEw+FWbTYTezAWhQiGKV+84y2Qt7xpiN3MEq8AYoqQG\r\nJc3O2oJ7bQ/wSk4gL8R1qBFUyyXasbSRM5N9QTh3Bfct8nJofOy8KtQ9J5OX\r\n1hV2+o0Gl4jhFnTbX8sTm4sX6WtgxWDqw64=\r\n=3FaS\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.6_1671078278008_0.9125056236007774"},"_hasShrinkwrap":false},"0.7.0-beta.7":{"name":"@synzen/discord-rest","version":"0.7.0-beta.7","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.19","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqp-connection-manager":"^4.1.9","amqplib":"^0.9.1","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"5ab5f33dc681d5fc5bc5902994ccc38fc7159325","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.7.0-beta.7","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-5KkrUFpZMugwfYhhNrmjVW1mXLLVvLmLKtOsxxPB9tuUYaMZfanQKwnfO7W008bnUhqtCii136w1lIorXa4znw==","shasum":"1cd5e112fc3c837a31b6ecc55bae5822395bd714","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.7.tgz","fileCount":55,"unpackedSize":201243,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDVAn2jvnpeq1gqqFLR4D2XlATzX/wl9/s1NmkVyE3FCAIgXfRu+IL/gw9MP93Xvn/9Knh95tsH7rK69lLnjpqXcDk="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjnee3ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoahhAAn1oMg1p1YqMJ2n509aCypIQmvBnf4XFfJWvv9/zOuvL0Ry+M\r\nOzom+m49yvVaEqcDdClGK9/mST1cCjGkD2QM7I9V/MNeHTyC1Z2N3jKeKVTl\r\n2fdgAYR8YtcC4Ien/Vroba833gG7AbB4ElbZC7xbKxP92ACzjW0sBmibIxWv\r\n3LEbR94DPWumSlyCv1FiBnF2gGYn52TxpqBQamjR4jAyVBrKm+245WmYhR0B\r\n1L73sGwNDQviqStz2VPlB1XvKe1rgzUDynP5o2vHAt4YZt4gpKKHXEuquHJf\r\npsAmHZgqKqchwEdAcgeMn4BxCQwuNBi4hnE4laBRPfMrXJURM35ugUN6HQBU\r\nh2Kyb/YaLnkvyAR2oR3mb8+4iRHzRprycgrw/BEDI/y5N+cXaAtlFF/SfIf5\r\nKDebSz8j+l6J0KlGmeB9mJkLRDlTYvcUrCOFcqnEmj0LK+Ll7/HSmoDDmjaL\r\nTrsHkKyml7cAUjVqZ09rsblvRaIlD4p446cNKA41nbNVNdZco5zvTn+EvSgS\r\nuY1o+KIRU0xn7m86P0e7FsL13iXZX5xCsGaxjIIDd6/iC4sUbxIIUSviXyRT\r\n40FEN4dMAe+ZZiHGzd+a1Lr3Ln7eqHgt23/s2NSM9oSES4eJp7uvDCTwLb2z\r\nC+nkh+2GEJvOCV5Q+M4X9iELuaLBz4gimLY=\r\n=S6j+\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.7_1671292854954_0.5456949509314164"},"_hasShrinkwrap":false},"0.7.0-beta.8":{"name":"@synzen/discord-rest","version":"0.7.0-beta.8","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.19","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqp-connection-manager":"^4.1.9","amqplib":"^0.9.1","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"33df8bb54afcca1bd987ecaa8622dea6852f670a","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.7.0-beta.8","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-IB4/XKMaIyk0nTdSzGEUBjB/zEm1YsaRmVl0bukYfTayDurk0ehcZSQsiGTkQd8cNPPfLGMx6D7dGfVD062x/g==","shasum":"ff462777e81910a35afc79be424e5f3449d848d1","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.8.tgz","fileCount":55,"unpackedSize":201480,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCxiepD/yXSwoEW+WwK9XxJGWDf6m2viGWBQ2Io1MYyGgIgTobKlNPaHzo+0zYxYnqGY7tRbpl+s2T8kF5g6XNH5Io="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.8_1687178428828_0.8275255389885949"},"_hasShrinkwrap":false},"0.7.0-beta.9":{"name":"@synzen/discord-rest","version":"0.7.0-beta.9","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^2.0.19","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqp-connection-manager":"^4.1.9","amqplib":"^0.9.1","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"94bec06af5ad942fe1a6fb81be248660201bda8d","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.7.0-beta.9","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-p5Mqje7OqyvN0xH7uM+XzRp8rot56+sc4xv6mC8DP53DU3u+lh8jTPL/PqIF825lOsA2TneBRp9d7I27sZyRhQ==","shasum":"3b17cd3601c43c7d20c4ad3fd7a7ac035147aa5a","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.9.tgz","fileCount":55,"unpackedSize":201487,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDunk10LrWGUfSpT8572s7J9CysR3fgz7IqSm0IkeXQlwIgQzXFNFztX4FcZ7XGWFDQj4J8c5Rw0wk5wO8hkLohMR8="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.9_1687182881148_0.5568057121241372"},"_hasShrinkwrap":false},"0.7.0-beta.10":{"name":"@synzen/discord-rest","version":"0.7.0-beta.10","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^3.0.1","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqp-connection-manager":"^4.1.9","amqplib":"^0.9.1","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"204aa6b35e90379877361c48d9dfb2728c0fca7a","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.7.0-beta.10","_nodeVersion":"18.14.1","_npmVersion":"9.3.1","dist":{"integrity":"sha512-eKp81O8JqfMhDJ8LvSwgcuecjNawv2yx/6kPz0aPV/4oow699N/KlnUM0dJKwZs5VC6WtEojOL9gRn273zr00w==","shasum":"f58419e26e2eea686d1a66d40362bc558bb25b8b","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.10.tgz","fileCount":61,"unpackedSize":251650,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDx0LTNM+nW8Ij3MP+BLFnthhHV5mP0a5TB8PB6WRrW8AiBuuqOP1fw2nmfiBbXCfmC6AStNIRsM58kgCs+hBPmI2A=="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.10_1698100156440_0.008636154702497123"},"_hasShrinkwrap":false},"0.7.0-beta.11":{"name":"@synzen/discord-rest","version":"0.7.0-beta.11","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^3.0.1","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqp-connection-manager":"^4.1.9","amqplib":"^0.9.1","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"43656d0e52e0d4eca783a1a1638ac291210c4139","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_id":"@synzen/discord-rest@0.7.0-beta.11","_nodeVersion":"18.14.1","_npmVersion":"9.3.1","dist":{"integrity":"sha512-hXQtAbjsDq0OLpDQJihCAD53bEXDqHWV7poCP+DPi4ywtU9ZXF2ZJEuA0y82EJmFUp4lp5XPY4cCBNiSWraTIQ==","shasum":"cff417e797c412f9044688291e6c8be5a9ef3c66","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.11.tgz","fileCount":61,"unpackedSize":252271,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFCNy0g6c/3MKYZVIMqdN9wE3MYZfD17yd37bxQ0Hsp9AiADzHgPmu0dO1BrEL4IfwbTeYAYURrqve7IOJbFJLtJFA=="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.11_1699883753269_0.6163117142405519"},"_hasShrinkwrap":false},"0.7.0-beta.12":{"name":"@synzen/discord-rest","version":"0.7.0-beta.12","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^3.0.1","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqp-connection-manager":"^4.1.9","amqplib":"^0.9.1","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"_id":"@synzen/discord-rest@0.7.0-beta.12","readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"47656bd377cfe81fe503cb137b889f2536d65dfb","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_nodeVersion":"20.10.0","_npmVersion":"10.2.3","dist":{"integrity":"sha512-xSS5VVUgmUU6KqvxH4Y8Gj5IXY3rkwAHF1WfPnx7/41MjdSwuBWsfY9YvbSPtohZsCgn7L7bIQOsFUIHMjjgpg==","shasum":"0225d71665783a6b1d0532f7f3d34370bd55bc4b","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.12.tgz","fileCount":61,"unpackedSize":250611,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDIcnL4+4kOmEHI++5A6UCnvCtZqflPFslDRYaGb3vyGAiAWePidaAV3+LBCEl5/p68ts+6IisATzRmCUxqQ1KFBAg=="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.12_1716113974559_0.2118110712384631"},"_hasShrinkwrap":false},"0.7.0-beta.13":{"name":"@synzen/discord-rest","version":"0.7.0-beta.13","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^3.0.1","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqp-connection-manager":"^4.1.9","amqplib":"^0.9.1","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"_id":"@synzen/discord-rest@0.7.0-beta.13","readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"5ecdb02b81f3c7c9918f4165b5978d1e3dc21748","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_nodeVersion":"20.10.0","_npmVersion":"10.2.3","dist":{"integrity":"sha512-LEZLlXf4V4wsCT5x76/Z9uDEZrBoJ9sVTKtSWvftvXQSnWA+GN9xWE/SkU1JXIahfOuJ7s1VItJ+3G+OP8lFMA==","shasum":"ce1840a3e523f92363fd95300f400c88cfbbf2e7","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.13.tgz","fileCount":61,"unpackedSize":250613,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAU0Abv+tvdiHl+bMQpkzwS259AKE/LCHdItuMFLNEIWAiEAmA4G0C7pNq+85rxxV0IyRiOd5TqCSi57c3QInvzgOuM="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.13_1716114260693_0.6322492936703568"},"_hasShrinkwrap":false},"0.7.0-beta.14":{"name":"@synzen/discord-rest","version":"0.7.0-beta.14","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^3.0.1","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqp-connection-manager":"^4.1.9","amqplib":"^0.9.1","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"_id":"@synzen/discord-rest@0.7.0-beta.14","readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"96e8341ef734cb6ddbac2f5c4600ea9c0b31deaf","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_nodeVersion":"20.10.0","_npmVersion":"10.2.3","dist":{"integrity":"sha512-VGY43hztpT4dCHZc8CUkMGPpLtGO7Jg7HlMEiLfko8k2RZNloBL7EkkyABoYtmNPzNUe8icGQYx4UapaIx0u4g==","shasum":"426cbf86e97ddd2b7d395af95df10cf770a2080e","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.14.tgz","fileCount":61,"unpackedSize":251189,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCxU4DipXKKVXQPtXikZz1yZiXz9JHgLF7KZoranzd7WQIgJavdKT9NGaX3cnn+IxIxoUgnQvUL2PmFKSpobq4aMaw="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.14_1716114827099_0.7564259685689889"},"_hasShrinkwrap":false},"0.7.0-beta.15":{"name":"@synzen/discord-rest","version":"0.7.0-beta.15","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^3.0.1","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqp-connection-manager":"^4.1.9","amqplib":"^0.9.1","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"_id":"@synzen/discord-rest@0.7.0-beta.15","readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"37f7b83fabcd2f9f829c03bda07e98fa1a67cef3","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_nodeVersion":"20.10.0","_npmVersion":"10.2.3","dist":{"integrity":"sha512-uabjYJLmFyMPeKrn6YgKNOU29SJaOZBl42/rsJE+hl3YFxA4SYJIJd8MfjhLdtUJ/nCuOLdJKV41Jesjgl14Zw==","shasum":"a1673756aac7e41b73082020a6896f801f01f287","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.15.tgz","fileCount":61,"unpackedSize":250732,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEl1ZAd2/XiNvl6/A1e4sQLntBoR+ysENn/92/UvSc0aAiEA+/Op+gQMR/Nppzi+/LkO7nJ981m6XCLnzu6aZCiwMQo="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.15_1716115295388_0.34002188625128915"},"_hasShrinkwrap":false},"0.7.0-beta.16":{"name":"@synzen/discord-rest","version":"0.7.0-beta.16","description":"A distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.","main":"dist/index.js","types":"dist/index.d.ts","repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"scripts":{"prepublishOnly":"npm run build","build":"tsc","test":"jest src","test:watch":"npm run test -- --watch","test-e2e":"jest --config ./test/jest-e2e.js","test-e2e:watch":"npm run test-e2e -- --watch --detectOpenHandles","example:consumer":"nodemon examples/consumer.ts","example:producer":"nodemon examples/producer.ts","lint":"eslint ."},"keywords":[],"author":{"name":"synzen"},"license":"MIT","devDependencies":{"@types/amqplib":"^0.8.2","@types/debug":"^4.1.5","@types/jest":"^28.1.0","@types/node":"^14.14.41","@types/rascal":"^10.0.6","@types/retry":"^0.12.2","@types/semaphore":"^1.1.1","@typescript-eslint/eslint-plugin":"^3.10.1","@typescript-eslint/parser":"^3.10.1","eslint":"^7.25.0","jest":"^28.1.0","nodemon":"^3.0.1","ts-jest":"^28.0.4","ts-node":"^9.1.1","typescript":"^4.6.3"},"dependencies":{"abort-controller":"^3.0.0","amqp-connection-manager":"^4.1.9","amqplib":"^0.9.1","async-sema":"^3.1.1","dayjs":"^1.11.2","debug":"^4.3.1","express":"^4.17.1","nanoid":"^3.3.4","p-queue":"^6.6.2","p-timeout":"^4.1.0","retry":"^0.13.1","semaphore":"^1.1.0","source-map-support":"^0.5.21","undici":"^5.10.0","yup":"^1.0.0-beta.4"},"_id":"@synzen/discord-rest@0.7.0-beta.16","readme":"# Discord-REST\r\n\r\nA distributed Discord rate limit handler that uses [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)'s interface for easy use.\r\n\r\nRequesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.\r\n\r\nBy default, outgoing requests are throttled at a maximum of 30/second (lower than the [the maximum allowed by Discord](https://discord.com/developers/docs/topics/rate-limits#global-rate-limit), which is 50, to give some buffer for other requests).\r\n\r\n### Table of Contents\r\n\r\n- [Discord-REST](#discord-rest)\r\n    - [Table of Contents](#table-of-contents)\r\n  - [Install](#install)\r\n  - [Usage](#usage)\r\n  - [Debugging](#debugging)\r\n\r\n## Install\r\n\r\n```\r\nnpm i @synzen/discord-rest\r\n```\r\n\r\n## Usage\r\n\r\n1. Set up a `RESTConsumer` to get ready to consume incoming requests.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const consumer = new RESTConsumer(rabbitmqUri, {\r\n      authHeader: `Bot ${botToken}`,\r\n      clientId: 'Bot client id'\r\n    });\r\n\r\n    consumer.initialize()\r\n    .then(() => console.log('Initialized'))\r\n    .catch(console.error)\r\n\r\n    // You can use the consumer to also listen to important events. See #handle-invalid-requests section\r\n    ```\r\n\r\n2. Set up a `RESTProducer` to send out API requests. Only requests that expect `Content-Type: application/json` is currently supported for simplicity and for it to be serializable to be stored within Redis.\r\n\r\n    ```ts\r\n    import { RESTConsumer } from \"@synzen/discord-rest\";\r\n\r\n    const producer = new RESTProducer(rabbitmqUri, {\r\n    clientId: 'Bot client id'\r\n    });\r\n\r\n    producer\r\n      .enqueue(\r\n        discordEndpoint,\r\n        {\r\n          // node-fetch options.\r\n          method: \"POST\",\r\n          body: JSON.stringify(payload),\r\n        },\r\n        {\r\n          // Any meta info you'd like to attach to this request\r\n          meta: 1,\r\n        }\r\n      )\r\n      .then((response) => {\r\n        // Status code (200, 400, etc.)\r\n        console.log(response.status);\r\n        // JSON response\r\n        console.log(response.body);\r\n      })\r\n      .catch(console.error);\r\n    ```\r\n\r\n    If you execute multiple requests asynchronously, for example:\r\n\r\n    ```ts\r\n    for (let i = 0; i < 3; ++i) {\r\n      producer\r\n        .enqueue(\"https://discord.com/api/channels/channelID/messages\", {\r\n          method: \"POST\",\r\n          body: JSON.stringify({\r\n            content: i,\r\n          }),\r\n        })\r\n        .then(() => console.log(i))\r\n        .catch(console.error);\r\n    }\r\n    ```\r\n\r\n    ```shell\r\n    1\r\n    2\r\n    3\r\n    ```\r\n\r\n  You will notice that they are executed in order since they are all within the same rate limit bucket.\r\n\r\n\r\nIf you'd like to specifically listen for global blocks, you can use the following events. Note that this is\r\n\r\n```ts\r\nimport { GLOBAL_BLOCK_TYPE } from '@synzen/discord-rest';\r\n\r\nconsumer.on('globalBlock', (blockType, durationMs) => {\r\n  if (blockType === GLOBAL_BLOCK_TYPE.GLOBAL_RATE_LIMIT) {\r\n    // Listen for blocks because of global rate limits from Discord\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.CLOUDFLARE_RATE_LIMIT) {\r\n    // Listen for blocks because of cloudflare IP bans\r\n  } else if (blockType === GLOBAL_BLOCK_TYPE.INVALID_REQUEST) {\r\n    // Listen for blocks that are encountered from too many invalid requests, which are 429, 401, 403 codes.\r\n    // This is a pre-emptive safety block BEFORE an IP ban from Cloudflare is encountered.\r\n  }\r\n})\r\n```\r\n\r\n## Debugging\r\n\r\nSet the environment variable `DEBUG` to `discordrest:*`.\r\n\r\n```shell\r\nDEBUG=discordrest:*\r\n```\r\n\r\nor on Windows:\r\n\r\n```powershell\r\nset DEBUG=discordrest:*\r\n```\r\n\r\nYou will see output like below.\r\n\r\n```shell\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms\r\ndiscordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms\r\ndiscordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms\r\ndiscordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms\r\ndiscordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms\r\ndiscordrest:bucket:0123--4567- Finished entire queue +1ms\r\ndiscordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms\r\n```\r\n","readmeFilename":"README.md","gitHead":"bc45c2b5ddee65cab1483ab886dbb36243e61fe3","bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"homepage":"https://github.com/synzen/discord-rest#readme","_nodeVersion":"20.10.0","_npmVersion":"10.2.3","dist":{"integrity":"sha512-Y3Hfj9RIF3KsC0QHrPuXq3aiTTW9q7ez1tVezrR/kJQvSgOyYi6KjOpJePFpaUwL71yX5ImqEQB1S87q/241SQ==","shasum":"b01ef19c7e3aa0cbe0b3981bf982599dee6106c2","tarball":"https://registry.npmjs.org/@synzen/discord-rest/-/discord-rest-0.7.0-beta.16.tgz","fileCount":61,"unpackedSize":250194,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCLUCvMfKaLn8QVDHG1tfe/dhWM+UJClqZTA8zDMG0oDAIgTPYCEpw48XD7u9yvXwQB7zaN32Ltado3eE649DUfhGY="}]},"_npmUser":{"name":"synzen","email":"michael994664@gmail.com"},"directories":{},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/discord-rest_0.7.0-beta.16_1716116043568_0.7803670480725431"},"_hasShrinkwrap":false}},"time":{"created":"2020-08-29T00:34:22.801Z","0.0.1":"2020-08-29T00:34:23.004Z","modified":"2024-05-19T10:54:03.909Z","0.0.2":"2020-08-29T02:17:09.271Z","0.0.3":"2020-08-29T02:28:32.163Z","0.0.4":"2020-08-29T02:31:32.610Z","0.0.5":"2020-08-29T17:56:58.522Z","0.0.6":"2020-08-29T21:40:26.242Z","0.0.7":"2020-08-30T05:20:52.154Z","0.0.8":"2020-08-30T05:58:38.187Z","0.1.0":"2020-08-30T17:20:47.820Z","0.1.1":"2020-08-30T17:22:55.301Z","0.2.0":"2020-08-30T22:09:37.734Z","0.2.1":"2020-09-20T21:34:50.857Z","0.3.0":"2020-09-25T14:51:00.103Z","0.3.1":"2020-09-25T14:56:15.275Z","0.3.2":"2020-09-25T15:04:37.728Z","0.3.3":"2020-09-25T15:07:55.821Z","0.4.0":"2020-09-25T15:25:13.253Z","0.5.0":"2020-10-15T22:33:20.876Z","0.5.1":"2020-10-15T23:19:09.435Z","0.5.2":"2020-10-16T14:25:15.297Z","0.6.0":"2021-04-26T15:51:48.209Z","0.6.1":"2021-04-26T19:39:13.961Z","0.6.2":"2021-04-26T19:55:33.107Z","0.6.3":"2021-04-28T01:08:42.100Z","0.6.4":"2021-05-02T03:12:08.747Z","0.6.5":"2021-05-02T15:57:08.517Z","0.6.6":"2021-05-02T16:21:19.848Z","0.6.7":"2021-05-02T16:29:37.071Z","0.6.8":"2021-05-02T16:53:15.738Z","0.6.9":"2021-05-03T23:34:40.189Z","0.6.10":"2021-05-08T23:27:49.675Z","0.6.11":"2021-05-09T13:08:37.144Z","0.6.12":"2021-05-12T13:29:32.843Z","0.6.13":"2021-05-12T13:41:55.133Z","0.6.14":"2021-05-12T14:00:21.262Z","0.6.15":"2021-05-15T01:24:55.898Z","0.6.16":"2021-05-15T01:27:48.208Z","0.6.17":"2021-05-15T01:34:11.175Z","0.6.18":"2021-05-15T04:35:03.675Z","0.6.19":"2021-05-25T01:01:39.989Z","0.6.21":"2022-01-25T02:35:07.278Z","0.6.22":"2022-01-27T00:35:31.496Z","0.6.23":"2022-01-27T12:51:52.236Z","0.6.24":"2022-01-27T13:11:25.099Z","0.6.25":"2022-01-29T00:52:18.003Z","0.6.26":"2022-02-07T14:47:27.323Z","0.6.26-beta.0":"2022-05-27T02:43:53.687Z","0.6.26-beta.1":"2022-05-27T03:51:27.806Z","0.6.26-beta.2":"2022-05-27T04:14:59.213Z","0.6.26-beta.3":"2022-05-27T23:36:04.993Z","0.6.26-beta.4":"2022-05-27T23:41:42.034Z","0.6.26-beta.5":"2022-05-28T14:13:13.299Z","0.6.26-beta.6":"2022-05-28T14:23:11.141Z","0.6.26-beta.7":"2022-05-28T14:46:59.953Z","0.6.26-beta.8":"2022-05-28T15:36:24.834Z","0.6.26-beta.9":"2022-05-28T19:00:57.054Z","0.6.26-beta.10":"2022-05-28T19:25:19.524Z","0.6.26-beta.11":"2022-05-28T20:55:33.748Z","0.6.26-beta.12":"2022-05-29T19:34:40.458Z","0.6.26-beta.13":"2022-05-29T20:14:19.917Z","0.6.26-beta.14":"2022-05-29T22:12:54.907Z","0.6.26-beta.15":"2022-05-29T22:51:09.771Z","0.6.26-beta.16":"2022-05-30T01:43:06.865Z","0.6.26-beta.17":"2022-05-30T02:21:35.181Z","0.6.26-beta.18":"2022-05-30T02:49:16.672Z","0.6.26-beta.19":"2022-05-30T03:50:09.938Z","0.6.26-beta.20":"2022-05-30T05:13:20.287Z","0.6.26-beta.21":"2022-05-30T05:33:25.083Z","0.6.26-beta.22":"2022-05-30T06:11:10.129Z","0.6.26-beta.23":"2022-05-30T13:42:12.114Z","0.6.26-beta.24":"2022-05-30T14:35:36.892Z","0.6.26-beta.25":"2022-05-30T14:54:19.966Z","0.6.26-beta.26":"2022-06-02T23:47:09.981Z","0.6.26-beta.27":"2022-06-03T02:29:20.273Z","0.6.26-beta.28":"2022-06-03T02:53:38.387Z","0.6.26-beta.29":"2022-06-03T03:46:29.741Z","0.6.26-beta.30":"2022-06-03T12:11:57.606Z","0.6.26-beta.31":"2022-06-03T12:33:21.489Z","0.6.26-beta.32":"2022-06-03T14:06:40.459Z","0.6.26-beta.33":"2022-06-04T03:06:31.702Z","0.6.26-beta.34":"2022-06-04T03:08:30.642Z","0.6.26-beta.35":"2022-06-04T03:20:46.709Z","0.6.26-beta.36":"2022-06-04T03:27:34.922Z","0.6.26-beta.37":"2022-06-04T03:49:13.380Z","0.6.26-beta.38":"2022-06-04T04:00:18.710Z","0.6.26-beta.39":"2022-06-04T13:25:54.317Z","0.6.26-beta.40":"2022-06-04T22:49:17.902Z","0.6.26-beta.41":"2022-06-04T23:10:26.769Z","0.6.26-beta.42":"2022-06-04T23:24:32.429Z","0.6.26-beta.43":"2022-06-05T04:24:08.546Z","0.6.26-beta.44":"2022-06-07T13:21:17.168Z","0.6.26-beta.45":"2022-06-13T23:40:01.757Z","0.6.27":"2022-06-13T23:50:54.138Z","0.6.26-beta.46":"2022-06-13T23:52:13.301Z","0.6.26-beta.47":"2022-06-14T00:09:25.957Z","0.6.26-beta.48":"2022-09-08T01:20:40.934Z","0.6.27-beta.0":"2022-09-09T22:50:59.071Z","0.7.0-beta.0":"2022-09-09T22:51:53.081Z","0.7.0-beta.1":"2022-09-10T03:57:04.298Z","0.7.0-beta.2":"2022-09-10T03:59:55.714Z","0.7.0-beta.3":"2022-10-30T15:18:31.187Z","0.7.0-beta.4":"2022-10-30T15:48:45.390Z","0.7.0-beta.5":"2022-12-15T00:43:24.033Z","0.7.0-beta.6":"2022-12-15T04:24:38.163Z","0.7.0-beta.7":"2022-12-17T16:00:55.184Z","0.7.0-beta.8":"2023-06-19T12:40:29.084Z","0.7.0-beta.9":"2023-06-19T13:54:41.311Z","0.7.0-beta.10":"2023-10-23T22:29:16.794Z","0.7.0-beta.11":"2023-11-13T13:55:53.477Z","0.7.0-beta.12":"2024-05-19T10:19:34.773Z","0.7.0-beta.13":"2024-05-19T10:24:20.891Z","0.7.0-beta.14":"2024-05-19T10:33:47.292Z","0.7.0-beta.15":"2024-05-19T10:41:35.675Z","0.7.0-beta.16":"2024-05-19T10:54:03.737Z"},"maintainers":[{"name":"synzen","email":"michael994664@gmail.com"}],"description":"A distributed Discord rate limit handler that uses [node-fetch](https://github.com/node-fetch/node-fetch)'s interface for easy use.","homepage":"https://github.com/synzen/discord-rest#readme","keywords":[],"repository":{"type":"git","url":"git+https://github.com/synzen/discord-rest.git"},"author":{"name":"synzen"},"bugs":{"url":"https://github.com/synzen/discord-rest/issues"},"license":"MIT","readme":"","readmeFilename":""}