dfx 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (352) hide show
  1. package/dist/Cache/driver.d.ts +24 -0
  2. package/dist/Cache/driver.d.ts.map +1 -0
  3. package/dist/Cache/driver.js +3 -0
  4. package/dist/Cache/driver.js.map +1 -0
  5. package/dist/Cache/memory.d.ts +5 -0
  6. package/dist/Cache/memory.d.ts.map +1 -0
  7. package/dist/Cache/memory.js +48 -0
  8. package/dist/Cache/memory.js.map +1 -0
  9. package/dist/Cache/memoryTTL.d.ts +23 -0
  10. package/dist/Cache/memoryTTL.d.ts.map +1 -0
  11. package/dist/Cache/memoryTTL.js +113 -0
  12. package/dist/Cache/memoryTTL.js.map +1 -0
  13. package/dist/Cache/prelude.d.ts +32 -0
  14. package/dist/Cache/prelude.d.ts.map +1 -0
  15. package/dist/Cache/prelude.js +130 -0
  16. package/dist/Cache/prelude.js.map +1 -0
  17. package/dist/Cache.d.ts +81 -0
  18. package/dist/Cache.d.ts.map +1 -0
  19. package/dist/Cache.js +77 -0
  20. package/dist/Cache.js.map +1 -0
  21. package/dist/DiscordConfig.d.ts +35 -0
  22. package/dist/DiscordConfig.d.ts.map +1 -0
  23. package/dist/DiscordConfig.js +29 -0
  24. package/dist/DiscordConfig.js.map +1 -0
  25. package/dist/DiscordGateway/DiscordWS.d.ts +37 -0
  26. package/dist/DiscordGateway/DiscordWS.d.ts.map +1 -0
  27. package/dist/DiscordGateway/DiscordWS.js +74 -0
  28. package/dist/DiscordGateway/DiscordWS.js.map +1 -0
  29. package/dist/DiscordGateway/Messaging.d.ts +587 -0
  30. package/dist/DiscordGateway/Messaging.d.ts.map +1 -0
  31. package/dist/DiscordGateway/Messaging.js +34 -0
  32. package/dist/DiscordGateway/Messaging.js.map +1 -0
  33. package/dist/DiscordGateway/Shard/StateStore.d.ts +24 -0
  34. package/dist/DiscordGateway/Shard/StateStore.d.ts.map +1 -0
  35. package/dist/DiscordGateway/Shard/StateStore.js +41 -0
  36. package/dist/DiscordGateway/Shard/StateStore.js.map +1 -0
  37. package/dist/DiscordGateway/Shard/heartbeats.d.ts +8 -0
  38. package/dist/DiscordGateway/Shard/heartbeats.d.ts.map +1 -0
  39. package/dist/DiscordGateway/Shard/heartbeats.js +25 -0
  40. package/dist/DiscordGateway/Shard/heartbeats.js.map +1 -0
  41. package/dist/DiscordGateway/Shard/identify.d.ts +12 -0
  42. package/dist/DiscordGateway/Shard/identify.d.ts.map +1 -0
  43. package/dist/DiscordGateway/Shard/identify.js +26 -0
  44. package/dist/DiscordGateway/Shard/identify.js.map +1 -0
  45. package/dist/DiscordGateway/Shard/sendEvents.d.ts +8 -0
  46. package/dist/DiscordGateway/Shard/sendEvents.d.ts.map +1 -0
  47. package/dist/DiscordGateway/Shard/sendEvents.js +26 -0
  48. package/dist/DiscordGateway/Shard/sendEvents.js.map +1 -0
  49. package/dist/DiscordGateway/Shard/utils.d.ts +6 -0
  50. package/dist/DiscordGateway/Shard/utils.d.ts.map +1 -0
  51. package/dist/DiscordGateway/Shard/utils.js +3 -0
  52. package/dist/DiscordGateway/Shard/utils.js.map +1 -0
  53. package/dist/DiscordGateway/Shard.d.ts +29 -0
  54. package/dist/DiscordGateway/Shard.d.ts.map +1 -0
  55. package/dist/DiscordGateway/Shard.js +134 -0
  56. package/dist/DiscordGateway/Shard.js.map +1 -0
  57. package/dist/DiscordGateway/ShardStore.d.ts +19 -0
  58. package/dist/DiscordGateway/ShardStore.d.ts.map +1 -0
  59. package/dist/DiscordGateway/ShardStore.js +23 -0
  60. package/dist/DiscordGateway/ShardStore.js.map +1 -0
  61. package/dist/DiscordGateway/Sharder.d.ts +14 -0
  62. package/dist/DiscordGateway/Sharder.d.ts.map +1 -0
  63. package/dist/DiscordGateway/Sharder.js +57 -0
  64. package/dist/DiscordGateway/Sharder.js.map +1 -0
  65. package/dist/DiscordGateway.d.ts +33 -0
  66. package/dist/DiscordGateway.d.ts.map +1 -0
  67. package/dist/DiscordGateway.js +21 -0
  68. package/dist/DiscordGateway.js.map +1 -0
  69. package/dist/DiscordREST/Generated.d.ts +5577 -0
  70. package/dist/DiscordREST/Generated.d.ts.map +1 -0
  71. package/dist/DiscordREST/Generated.js +2302 -0
  72. package/dist/DiscordREST/Generated.js.map +1 -0
  73. package/dist/DiscordREST/utils.d.ts +14 -0
  74. package/dist/DiscordREST/utils.d.ts.map +1 -0
  75. package/dist/DiscordREST/utils.js +23 -0
  76. package/dist/DiscordREST/utils.js.map +1 -0
  77. package/dist/DiscordREST.d.ts +22 -0
  78. package/dist/DiscordREST.d.ts.map +1 -0
  79. package/dist/DiscordREST.js +123 -0
  80. package/dist/DiscordREST.js.map +1 -0
  81. package/dist/Helpers/flags.d.ts +28 -0
  82. package/dist/Helpers/flags.d.ts.map +1 -0
  83. package/dist/Helpers/flags.js +45 -0
  84. package/dist/Helpers/flags.js.map +1 -0
  85. package/dist/Helpers/intents.d.ts +25 -0
  86. package/dist/Helpers/intents.d.ts.map +1 -0
  87. package/dist/Helpers/intents.js +29 -0
  88. package/dist/Helpers/intents.js.map +1 -0
  89. package/dist/Helpers/interactions.d.ts +116 -0
  90. package/dist/Helpers/interactions.d.ts.map +1 -0
  91. package/dist/Helpers/interactions.js +114 -0
  92. package/dist/Helpers/interactions.js.map +1 -0
  93. package/dist/Helpers/members.d.ts +10 -0
  94. package/dist/Helpers/members.d.ts.map +1 -0
  95. package/dist/Helpers/members.js +10 -0
  96. package/dist/Helpers/members.js.map +1 -0
  97. package/dist/Helpers/permissions.d.ts +42 -0
  98. package/dist/Helpers/permissions.d.ts.map +1 -0
  99. package/dist/Helpers/permissions.js +84 -0
  100. package/dist/Helpers/permissions.js.map +1 -0
  101. package/dist/Helpers/ui.d.ts +105 -0
  102. package/dist/Helpers/ui.d.ts.map +1 -0
  103. package/dist/Helpers/ui.js +135 -0
  104. package/dist/Helpers/ui.js.map +1 -0
  105. package/dist/Interactions/builder.d.ts +48 -0
  106. package/dist/Interactions/builder.d.ts.map +1 -0
  107. package/dist/Interactions/builder.js +63 -0
  108. package/dist/Interactions/builder.js.map +1 -0
  109. package/dist/Interactions/commandHelper.d.ts +83 -0
  110. package/dist/Interactions/commandHelper.d.ts.map +1 -0
  111. package/dist/Interactions/commandHelper.js +47 -0
  112. package/dist/Interactions/commandHelper.js.map +1 -0
  113. package/dist/Interactions/context.d.ts +53 -0
  114. package/dist/Interactions/context.d.ts.map +1 -0
  115. package/dist/Interactions/context.js +35 -0
  116. package/dist/Interactions/context.js.map +1 -0
  117. package/dist/Interactions/definitions.d.ts +43 -0
  118. package/dist/Interactions/definitions.d.ts.map +1 -0
  119. package/dist/Interactions/definitions.js +51 -0
  120. package/dist/Interactions/definitions.js.map +1 -0
  121. package/dist/Interactions/error.d.ts +2 -0
  122. package/dist/Interactions/error.d.ts.map +1 -0
  123. package/dist/Interactions/error.js +2 -0
  124. package/dist/Interactions/error.js.map +1 -0
  125. package/dist/Interactions/gateway.d.ts +20 -0
  126. package/dist/Interactions/gateway.d.ts.map +1 -0
  127. package/dist/Interactions/gateway.js +75 -0
  128. package/dist/Interactions/gateway.js.map +1 -0
  129. package/dist/Interactions/handlers.d.ts +15 -0
  130. package/dist/Interactions/handlers.d.ts.map +1 -0
  131. package/dist/Interactions/handlers.js +61 -0
  132. package/dist/Interactions/handlers.js.map +1 -0
  133. package/dist/Interactions/index.d.ts +17 -0
  134. package/dist/Interactions/index.d.ts.map +1 -0
  135. package/dist/Interactions/index.js +11 -0
  136. package/dist/Interactions/index.js.map +1 -0
  137. package/dist/Interactions/utils.d.ts +61 -0
  138. package/dist/Interactions/utils.d.ts.map +1 -0
  139. package/dist/Interactions/utils.js +29 -0
  140. package/dist/Interactions/utils.js.map +1 -0
  141. package/dist/Interactions/webhook.d.ts +71 -0
  142. package/dist/Interactions/webhook.d.ts.map +1 -0
  143. package/dist/Interactions/webhook.js +56 -0
  144. package/dist/Interactions/webhook.js.map +1 -0
  145. package/dist/LICENSE +21 -0
  146. package/{examples/readme.ts → dist/README.md} +13 -3
  147. package/dist/RateLimit/memory.d.ts +3 -0
  148. package/dist/RateLimit/memory.d.ts.map +1 -0
  149. package/dist/RateLimit/memory.js +35 -0
  150. package/dist/RateLimit/memory.js.map +1 -0
  151. package/dist/RateLimit/utils.d.ts +3 -0
  152. package/dist/RateLimit/utils.d.ts.map +1 -0
  153. package/dist/RateLimit/utils.js +18 -0
  154. package/dist/RateLimit/utils.js.map +1 -0
  155. package/dist/RateLimit.d.ts +30 -0
  156. package/dist/RateLimit.d.ts.map +1 -0
  157. package/dist/RateLimit.js +28 -0
  158. package/dist/RateLimit.js.map +1 -0
  159. package/dist/gateway.d.ts +19 -0
  160. package/dist/gateway.d.ts.map +1 -0
  161. package/dist/gateway.js +19 -0
  162. package/dist/gateway.js.map +1 -0
  163. package/dist/index.d.ts +18 -0
  164. package/dist/index.d.ts.map +1 -0
  165. package/dist/index.js +18 -0
  166. package/dist/index.js.map +1 -0
  167. package/dist/mjs/Cache/driver.mjs +3 -0
  168. package/dist/mjs/Cache/driver.mjs.map +1 -0
  169. package/dist/mjs/Cache/memory.mjs +48 -0
  170. package/dist/mjs/Cache/memory.mjs.map +1 -0
  171. package/dist/mjs/Cache/memoryTTL.mjs +119 -0
  172. package/dist/mjs/Cache/memoryTTL.mjs.map +1 -0
  173. package/dist/mjs/Cache/prelude.mjs +131 -0
  174. package/dist/mjs/Cache/prelude.mjs.map +1 -0
  175. package/dist/mjs/Cache.mjs +90 -0
  176. package/dist/mjs/Cache.mjs.map +1 -0
  177. package/dist/mjs/DiscordConfig.mjs +32 -0
  178. package/dist/mjs/DiscordConfig.mjs.map +1 -0
  179. package/dist/mjs/DiscordGateway/DiscordWS.mjs +77 -0
  180. package/dist/mjs/DiscordGateway/DiscordWS.mjs.map +1 -0
  181. package/dist/mjs/DiscordGateway/Messaging.mjs +35 -0
  182. package/dist/mjs/DiscordGateway/Messaging.mjs.map +1 -0
  183. package/dist/mjs/DiscordGateway/Shard/StateStore.mjs +41 -0
  184. package/dist/mjs/DiscordGateway/Shard/StateStore.mjs.map +1 -0
  185. package/dist/mjs/DiscordGateway/Shard/heartbeats.mjs +25 -0
  186. package/dist/mjs/DiscordGateway/Shard/heartbeats.mjs.map +1 -0
  187. package/dist/mjs/DiscordGateway/Shard/identify.mjs +29 -0
  188. package/dist/mjs/DiscordGateway/Shard/identify.mjs.map +1 -0
  189. package/dist/mjs/DiscordGateway/Shard/sendEvents.mjs +26 -0
  190. package/dist/mjs/DiscordGateway/Shard/sendEvents.mjs.map +1 -0
  191. package/dist/mjs/DiscordGateway/Shard/utils.mjs +3 -0
  192. package/dist/mjs/DiscordGateway/Shard/utils.mjs.map +1 -0
  193. package/dist/mjs/DiscordGateway/Shard.mjs +147 -0
  194. package/dist/mjs/DiscordGateway/Shard.mjs.map +1 -0
  195. package/dist/mjs/DiscordGateway/ShardStore.mjs +24 -0
  196. package/dist/mjs/DiscordGateway/ShardStore.mjs.map +1 -0
  197. package/dist/mjs/DiscordGateway/Sharder.mjs +67 -0
  198. package/dist/mjs/DiscordGateway/Sharder.mjs.map +1 -0
  199. package/dist/mjs/DiscordGateway.mjs +21 -0
  200. package/dist/mjs/DiscordGateway.mjs.map +1 -0
  201. package/dist/mjs/DiscordREST/Generated.mjs +2471 -0
  202. package/dist/mjs/DiscordREST/Generated.mjs.map +1 -0
  203. package/dist/mjs/DiscordREST/utils.mjs +21 -0
  204. package/dist/mjs/DiscordREST/utils.mjs.map +1 -0
  205. package/dist/mjs/DiscordREST.mjs +119 -0
  206. package/dist/mjs/DiscordREST.mjs.map +1 -0
  207. package/dist/mjs/Helpers/flags.mjs +45 -0
  208. package/dist/mjs/Helpers/flags.mjs.map +1 -0
  209. package/dist/mjs/Helpers/intents.mjs +27 -0
  210. package/dist/mjs/Helpers/intents.mjs.map +1 -0
  211. package/dist/mjs/Helpers/interactions.mjs +115 -0
  212. package/dist/mjs/Helpers/interactions.mjs.map +1 -0
  213. package/dist/mjs/Helpers/members.mjs +9 -0
  214. package/dist/mjs/Helpers/members.mjs.map +1 -0
  215. package/dist/mjs/Helpers/permissions.mjs +84 -0
  216. package/dist/mjs/Helpers/permissions.mjs.map +1 -0
  217. package/dist/mjs/Helpers/ui.mjs +137 -0
  218. package/dist/mjs/Helpers/ui.mjs.map +1 -0
  219. package/dist/mjs/Interactions/builder.mjs +56 -0
  220. package/dist/mjs/Interactions/builder.mjs.map +1 -0
  221. package/dist/mjs/Interactions/commandHelper.mjs +49 -0
  222. package/dist/mjs/Interactions/commandHelper.mjs.map +1 -0
  223. package/dist/mjs/Interactions/context.mjs +28 -0
  224. package/dist/mjs/Interactions/context.mjs.map +1 -0
  225. package/dist/mjs/Interactions/definitions.mjs +51 -0
  226. package/dist/mjs/Interactions/definitions.mjs.map +1 -0
  227. package/dist/mjs/Interactions/error.mjs +2 -0
  228. package/dist/mjs/Interactions/error.mjs.map +1 -0
  229. package/dist/mjs/Interactions/gateway.mjs +82 -0
  230. package/dist/mjs/Interactions/gateway.mjs.map +1 -0
  231. package/dist/mjs/Interactions/handlers.mjs +64 -0
  232. package/dist/mjs/Interactions/handlers.mjs.map +1 -0
  233. package/dist/mjs/Interactions/index.mjs +11 -0
  234. package/dist/mjs/Interactions/index.mjs.map +1 -0
  235. package/dist/mjs/Interactions/utils.mjs +26 -0
  236. package/dist/mjs/Interactions/utils.mjs.map +1 -0
  237. package/dist/mjs/Interactions/webhook.mjs +75 -0
  238. package/dist/mjs/Interactions/webhook.mjs.map +1 -0
  239. package/dist/mjs/RateLimit/memory.mjs +39 -0
  240. package/dist/mjs/RateLimit/memory.mjs.map +1 -0
  241. package/dist/mjs/RateLimit/utils.mjs +18 -0
  242. package/dist/mjs/RateLimit/utils.mjs.map +1 -0
  243. package/dist/mjs/RateLimit.mjs +28 -0
  244. package/dist/mjs/RateLimit.mjs.map +1 -0
  245. package/dist/mjs/gateway.mjs +19 -0
  246. package/dist/mjs/gateway.mjs.map +1 -0
  247. package/dist/mjs/index.mjs +18 -0
  248. package/dist/mjs/index.mjs.map +1 -0
  249. package/dist/mjs/types.mjs +356 -0
  250. package/dist/mjs/types.mjs.map +1 -0
  251. package/dist/mjs/utils/Effect.mjs +44 -0
  252. package/dist/mjs/utils/Effect.mjs.map +1 -0
  253. package/dist/mjs/version.mjs +2 -0
  254. package/dist/mjs/version.mjs.map +1 -0
  255. package/dist/mjs/webhooks.mjs +6 -0
  256. package/dist/mjs/webhooks.mjs.map +1 -0
  257. package/dist/package.json +48 -0
  258. package/dist/src/Cache/driver.ts +37 -0
  259. package/dist/src/Cache/memory.ts +83 -0
  260. package/dist/src/Cache/memoryTTL.ts +225 -0
  261. package/dist/src/Cache/prelude.ts +279 -0
  262. package/dist/src/Cache.ts +261 -0
  263. package/dist/src/DiscordConfig.ts +67 -0
  264. package/dist/src/DiscordGateway/DiscordWS.ts +157 -0
  265. package/dist/src/DiscordGateway/Messaging.ts +71 -0
  266. package/dist/src/DiscordGateway/Shard/StateStore.ts +72 -0
  267. package/dist/src/DiscordGateway/Shard/heartbeats.ts +60 -0
  268. package/dist/src/DiscordGateway/Shard/identify.ts +50 -0
  269. package/dist/src/DiscordGateway/Shard/sendEvents.ts +43 -0
  270. package/dist/src/DiscordGateway/Shard/utils.ts +13 -0
  271. package/dist/src/DiscordGateway/Shard.ts +205 -0
  272. package/dist/src/DiscordGateway/ShardStore.ts +42 -0
  273. package/dist/src/DiscordGateway/Sharder.ts +118 -0
  274. package/dist/src/DiscordGateway.ts +79 -0
  275. package/dist/src/DiscordREST/Generated.ts +10832 -0
  276. package/dist/src/DiscordREST/utils.ts +42 -0
  277. package/dist/src/DiscordREST.ts +256 -0
  278. package/dist/src/Helpers/flags.ts +73 -0
  279. package/dist/src/Helpers/intents.ts +35 -0
  280. package/dist/src/Helpers/interactions.ts +317 -0
  281. package/dist/src/Helpers/members.ts +18 -0
  282. package/dist/src/Helpers/permissions.ts +145 -0
  283. package/dist/src/Helpers/ui.ts +253 -0
  284. package/dist/src/Interactions/builder.ts +171 -0
  285. package/dist/src/Interactions/commandHelper.ts +231 -0
  286. package/dist/src/Interactions/context.ts +104 -0
  287. package/dist/src/Interactions/definitions.ts +144 -0
  288. package/dist/src/Interactions/error.ts +3 -0
  289. package/dist/src/Interactions/gateway.ts +193 -0
  290. package/dist/src/Interactions/handlers.ts +108 -0
  291. package/dist/src/Interactions/index.ts +30 -0
  292. package/dist/src/Interactions/utils.ts +93 -0
  293. package/dist/src/Interactions/webhook.ts +204 -0
  294. package/dist/src/RateLimit/memory.ts +63 -0
  295. package/dist/src/RateLimit/utils.ts +28 -0
  296. package/dist/src/RateLimit.ts +90 -0
  297. package/dist/src/gateway.ts +50 -0
  298. package/dist/src/index.ts +44 -0
  299. package/dist/src/types.ts +3090 -0
  300. package/dist/src/utils/Effect.ts +65 -0
  301. package/dist/src/version.ts +1 -0
  302. package/dist/src/webhooks.ts +25 -0
  303. package/dist/types.d.ts +2458 -0
  304. package/dist/types.d.ts.map +1 -0
  305. package/dist/types.js +356 -0
  306. package/dist/types.js.map +1 -0
  307. package/dist/utils/Effect.d.ts +5 -0
  308. package/dist/utils/Effect.d.ts.map +1 -0
  309. package/dist/utils/Effect.js +42 -0
  310. package/dist/utils/Effect.js.map +1 -0
  311. package/dist/version.d.ts +2 -0
  312. package/dist/version.d.ts.map +1 -0
  313. package/dist/version.js +2 -0
  314. package/dist/version.js.map +1 -0
  315. package/dist/webhooks.d.ts +8 -0
  316. package/dist/webhooks.d.ts.map +1 -0
  317. package/dist/webhooks.js +6 -0
  318. package/dist/webhooks.js.map +1 -0
  319. package/package.json +19 -11
  320. package/src/version.ts +1 -0
  321. package/.babel.cjs.json +0 -11
  322. package/.babel.mjs.json +0 -10
  323. package/.envrc +0 -1
  324. package/.gitmodules +0 -3
  325. package/.husky/pre-commit +0 -2
  326. package/.oxlintrc.json +0 -72
  327. package/.prettierignore +0 -0
  328. package/.prettierrc.json +0 -5
  329. package/.tool-versions +0 -1
  330. package/.vscode/debug.cjs +0 -8
  331. package/.vscode/launch.json +0 -23
  332. package/.vscode/settings.json +0 -29
  333. package/.vscode/tasks.json +0 -44
  334. package/AGENTS.md +0 -15
  335. package/CHANGELOG.md +0 -1566
  336. package/examples/.env.example +0 -5
  337. package/examples/interactions.ts +0 -79
  338. package/examples/registry.ts +0 -66
  339. package/flake.lock +0 -27
  340. package/flake.nix +0 -21
  341. package/lerna.json +0 -12
  342. package/pnpm-workspace.yaml +0 -7
  343. package/scripts/generate-client.sh +0 -10
  344. package/scripts/worktree-setup.sh +0 -8
  345. package/test/index.test.ts +0 -5
  346. package/vitest.config.ts +0 -22
  347. /package/{tsconfig.base.json → dist/tsconfig.base.json} +0 -0
  348. /package/{tsconfig.build.json → dist/tsconfig.build.json} +0 -0
  349. /package/{tsconfig.examples.json → dist/tsconfig.examples.json} +0 -0
  350. /package/{tsconfig.json → dist/tsconfig.json} +0 -0
  351. /package/{tsconfig.madge.json → dist/tsconfig.madge.json} +0 -0
  352. /package/{tsconfig.test.json → dist/tsconfig.test.json} +0 -0
@@ -0,0 +1,42 @@
1
+ import * as Duration from "effect/Duration"
2
+ import { pipe } from "effect/Function"
3
+ import * as Option from "effect/Option"
4
+ import * as Headers from "effect/unstable/http/Headers"
5
+
6
+ const majorResources = ["channels", "guilds", "webhooks"] as const
7
+
8
+ export const routeFromConfig = (path: string, method: string) => {
9
+ // Only keep major ID's
10
+ const routeURL = path
11
+ .split("?")[0]
12
+ .replace(/\/([A-Za-z]+)\/(\d{16,21}|@me)/g, (match, resource) =>
13
+ majorResources.includes(resource) ? match : `/${resource}`,
14
+ )
15
+ // Strip reactions
16
+ .replace(/\/reactions\/(.*)/, "/reactions")
17
+
18
+ return `${method}-${routeURL}`
19
+ }
20
+
21
+ export const numberHeader = (headers: Headers.Headers) => (key: string) =>
22
+ pipe(
23
+ Headers.get(headers, key),
24
+ Option.fromUndefinedOr,
25
+ Option.map(parseFloat),
26
+ Option.filter(n => !isNaN(n)),
27
+ )
28
+
29
+ export const retryAfter = (headers: Headers.Headers) =>
30
+ numberHeader(headers)("x-ratelimit-reset-after").pipe(
31
+ Option.orElse(() => numberHeader(headers)("retry-after")),
32
+ Option.map(Duration.seconds),
33
+ )
34
+
35
+ export const rateLimitFromHeaders = (headers: Headers.Headers) =>
36
+ Option.all({
37
+ bucket: Option.fromUndefinedOr(Headers.get(headers, "x-ratelimit-bucket")),
38
+ retryAfter: retryAfter(headers),
39
+ limit: numberHeader(headers)("x-ratelimit-limit"),
40
+ remaining: numberHeader(headers)("x-ratelimit-remaining"),
41
+ })
42
+ export type RateLimitDetails = ReturnType<typeof rateLimitFromHeaders>
@@ -0,0 +1,256 @@
1
+ import { DiscordConfig } from "./DiscordConfig.ts"
2
+ import {
3
+ rateLimitFromHeaders,
4
+ retryAfter,
5
+ routeFromConfig,
6
+ } from "./DiscordREST/utils.ts"
7
+ import { RateLimitStore, RateLimiter, RateLimiterLive } from "./RateLimit.ts"
8
+ import * as Discord from "./types.ts"
9
+ import { LIB_VERSION } from "./version.ts"
10
+ import * as Duration from "effect/Duration"
11
+ import { millis } from "effect/Duration"
12
+ import * as Effect from "effect/Effect"
13
+ import * as Fiber from "effect/Fiber"
14
+ import { flow } from "effect/Function"
15
+ import * as Layer from "effect/Layer"
16
+ import * as Option from "effect/Option"
17
+ import * as Redacted from "effect/Redacted"
18
+ import * as ServiceMap from "effect/ServiceMap"
19
+ import * as HttpBody from "effect/unstable/http/HttpBody"
20
+ import * as HttpClient from "effect/unstable/http/HttpClient"
21
+ import type { HttpClientError } from "effect/unstable/http/HttpClientError"
22
+ import * as HttpRequest from "effect/unstable/http/HttpClientRequest"
23
+ import type * as HttpResponse from "effect/unstable/http/HttpClientResponse"
24
+
25
+ const make = Effect.gen(function* () {
26
+ const { rest, token } = yield* DiscordConfig
27
+
28
+ const store = yield* RateLimitStore
29
+ const { maybeWait } = yield* RateLimiter
30
+
31
+ const globalRateLimit = maybeWait(
32
+ "dfx.rest.global",
33
+ Duration.fromInputUnsafe(rest.globalRateLimit.window),
34
+ rest.globalRateLimit.limit,
35
+ )
36
+
37
+ // Invalid route handling (40x)
38
+ const badRoutes = new Set<string>()
39
+ const tenMinutes = Duration.minutes(10)
40
+ const tenMinutesMillis = Duration.toMillis(tenMinutes)
41
+ const addBadRoute = (route: string) =>
42
+ Effect.suspend(() => {
43
+ badRoutes.add(route)
44
+ return Effect.log("bad route")
45
+ }).pipe(
46
+ Effect.andThen(
47
+ store.incrementCounter("dfx.rest.invalid", tenMinutesMillis, 10000),
48
+ ),
49
+ Effect.annotateLogs("route", route),
50
+ )
51
+
52
+ const invalidRateLimit = (route: string) =>
53
+ Effect.suspend(() =>
54
+ badRoutes.has(route)
55
+ ? maybeWait("dfx.rest.invalid", tenMinutes, 10000)
56
+ : Effect.void,
57
+ )
58
+
59
+ // Request rate limiting
60
+ const requestRateLimit = Effect.fnUntraced(function* (
61
+ path: string,
62
+ request: HttpRequest.HttpClientRequest,
63
+ ) {
64
+ const route = routeFromConfig(path, request.method)
65
+ const maybeBucket = yield* store.getBucketForRoute(route)
66
+ yield* invalidRateLimit(route)
67
+ if (Option.isNone(maybeBucket)) return
68
+ const bucket = maybeBucket.value
69
+ yield* maybeWait(
70
+ `dfx.rest.${bucket.key}`,
71
+ millis(bucket.resetAfter),
72
+ bucket.limit,
73
+ )
74
+ })
75
+
76
+ // Update rate limit buckets
77
+ const updateBuckets = Effect.fnUntraced(function* (
78
+ request: HttpRequest.HttpClientRequest,
79
+ response: HttpResponse.HttpClientResponse,
80
+ ) {
81
+ const route = routeFromConfig(request.url, request.method)
82
+ const rateLimitOption = rateLimitFromHeaders(response.headers)
83
+ if (Option.isNone(rateLimitOption)) return
84
+ const rateLimit = rateLimitOption.value
85
+ const hasBucket = yield* store.hasBucket(rateLimit.bucket)
86
+ const fibers: Array<Fiber.Fiber<unknown, unknown>> = []
87
+
88
+ badRoutes.delete(route)
89
+ fibers.push(
90
+ yield* Effect.forkChild(store.putBucketRoute(route, rateLimit.bucket)),
91
+ )
92
+
93
+ if (!hasBucket || rateLimit.limit - 1 === rateLimit.remaining) {
94
+ fibers.push(
95
+ yield* Effect.forkChild(store.removeCounter(`dfx.rest.?.${route}`)),
96
+ )
97
+ fibers.push(
98
+ yield* Effect.forkChild(
99
+ store.putBucket({
100
+ key: rateLimit.bucket,
101
+ resetAfter: Duration.toMillis(rateLimit.retryAfter),
102
+ limit:
103
+ !hasBucket && rateLimit.remaining > 0
104
+ ? rateLimit.remaining
105
+ : rateLimit.limit,
106
+ }),
107
+ ),
108
+ )
109
+ }
110
+
111
+ yield* Fiber.awaitAll(fibers)
112
+ })
113
+
114
+ const defaultClient = (yield* HttpClient.HttpClient).pipe(
115
+ HttpClient.transformResponse(
116
+ Effect.provideService(HttpClient.TracerPropagationEnabled, false),
117
+ ),
118
+ )
119
+ const rateLimitedClient: HttpClient.HttpClient = defaultClient.pipe(
120
+ HttpClient.tapRequest(request =>
121
+ Effect.andThen(requestRateLimit(request.url, request), globalRateLimit),
122
+ ),
123
+ HttpClient.transformResponse(
124
+ flow(
125
+ Effect.tap(response => updateBuckets(response.request, response)),
126
+ Effect.flatMap(response => {
127
+ const request = response.request
128
+
129
+ switch (response.status) {
130
+ case 403:
131
+ return Effect.as(
132
+ Effect.all(
133
+ [
134
+ Effect.annotateLogs(
135
+ Effect.logDebug("403"),
136
+ "url",
137
+ request.url,
138
+ ),
139
+ addBadRoute(routeFromConfig(request.url, request.method)),
140
+ updateBuckets(request, response),
141
+ ],
142
+ { concurrency: "unbounded", discard: true },
143
+ ),
144
+ response,
145
+ )
146
+
147
+ case 429:
148
+ return Effect.annotateLogs(
149
+ Effect.logDebug("429"),
150
+ "url",
151
+ request.url,
152
+ ).pipe(
153
+ Effect.andThen(
154
+ addBadRoute(routeFromConfig(request.url, request.method)),
155
+ ),
156
+ Effect.andThen(updateBuckets(request, response)),
157
+ Effect.andThen(
158
+ Effect.sleep(
159
+ Option.getOrElse(retryAfter(response.headers), () =>
160
+ Duration.seconds(5),
161
+ ),
162
+ ),
163
+ ),
164
+ Effect.andThen(rateLimitedClient.execute(request)),
165
+ )
166
+ }
167
+
168
+ return Effect.succeed(response)
169
+ }),
170
+ Effect.annotateLogs({
171
+ package: "dfx",
172
+ module: "DiscordREST",
173
+ }),
174
+ ),
175
+ ),
176
+ )
177
+
178
+ const httpClient = HttpClient.mapRequestInputEffect(rateLimitedClient, req =>
179
+ Effect.sync(() => {
180
+ const fiber = Fiber.getCurrent()!
181
+ let request = req.pipe(
182
+ HttpRequest.prependUrl(rest.baseUrl),
183
+ HttpRequest.setHeaders({
184
+ Authorization: `Bot ${Redacted.value(token)}`,
185
+ "User-Agent": `DiscordBot (https://github.com/tim-smart/dfx, ${LIB_VERSION})`,
186
+ }),
187
+ )
188
+ const formData = ServiceMap.getOption(fiber.services, DiscordFormData)
189
+ if (Option.isSome(formData)) {
190
+ if (request.body._tag === "Uint8Array") {
191
+ formData.value.set(
192
+ "payload_json",
193
+ new Blob([request.body.body as Uint8Array<ArrayBuffer>], {
194
+ type: "application/json",
195
+ }),
196
+ "",
197
+ )
198
+ }
199
+ request = HttpRequest.setBody(
200
+ request,
201
+ HttpBody.formData(formData.value),
202
+ )
203
+ }
204
+ return request
205
+ }),
206
+ )
207
+
208
+ return DiscordREST.of({
209
+ ...Discord.make(httpClient),
210
+ withFormData(formData) {
211
+ return Effect.provideService(DiscordFormData, formData)
212
+ },
213
+ withFiles(files) {
214
+ return <A, E, R>(
215
+ effect: Effect.Effect<A, E, R>,
216
+ ): Effect.Effect<A, E, R> =>
217
+ Effect.suspend(() => {
218
+ const formData = new FormData()
219
+ for (let i = 0; i < files.length; i++) {
220
+ formData.append(`files[${i}]`, files[i])
221
+ }
222
+ return Effect.provideService(effect, DiscordFormData, formData)
223
+ })
224
+ },
225
+ })
226
+ })
227
+
228
+ export type DiscordRESTError =
229
+ | HttpClientError
230
+ | Discord.DiscordRestError<"RatelimitedResponse", Discord.RatelimitedResponse>
231
+ | Discord.DiscordRestError<"ErrorResponse", Discord.ErrorResponse>
232
+
233
+ export class DiscordFormData extends ServiceMap.Service<
234
+ DiscordFormData,
235
+ FormData
236
+ >()("dfx/DiscordREST/DiscordFormData") {}
237
+
238
+ export interface DiscordRestService extends Discord.DiscordRest {
239
+ withFormData(
240
+ formData: FormData,
241
+ ): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
242
+ withFiles(
243
+ files: ReadonlyArray<File>,
244
+ ): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
245
+ }
246
+
247
+ export class DiscordREST extends ServiceMap.Service<
248
+ DiscordREST,
249
+ DiscordRestService
250
+ >()("dfx/DiscordREST") {}
251
+
252
+ export const DiscordRESTLive: Layer.Layer<
253
+ DiscordREST,
254
+ never,
255
+ DiscordConfig | HttpClient.HttpClient | RateLimitStore
256
+ > = Layer.effect(DiscordREST, make).pipe(Layer.provide(RateLimiterLive))
@@ -0,0 +1,73 @@
1
+ export type Flags<T extends number | bigint> = Record<string, T>
2
+
3
+ /**
4
+ * Returns all the flags OR'ed together.
5
+ */
6
+ export function all(flags: Flags<number>): number
7
+ export function all(flags: Flags<bigint>): bigint
8
+ export function all(flags: Flags<any>): any {
9
+ return Object.values(flags).reduce((acc, flag) => acc | flag)
10
+ }
11
+
12
+ /**
13
+ * Returns a function that converts a bitfield to a list of flag names.
14
+ */
15
+ export function toList<T extends Flags<number>>(
16
+ flags: T,
17
+ ): (bitfield: number) => Array<keyof T>
18
+ export function toList<T extends Flags<bigint>>(
19
+ flags: T,
20
+ ): (bitfield: bigint) => Array<keyof T>
21
+ export function toList<T extends Flags<any>>(
22
+ flags: T,
23
+ ): (bitfield: any) => Array<keyof T> {
24
+ const entries = Object.entries(flags)
25
+ return val => {
26
+ const out = []
27
+ for (let i = 0; i < entries.length; i++) {
28
+ const [key, flag] = entries[i]
29
+ if ((val & flag) === flag) {
30
+ out.push(key)
31
+ }
32
+ }
33
+ return out
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Returns a function that converts a list of flags names to a bigint bitfield.
39
+ */
40
+ export const fromListBigint =
41
+ <T extends Flags<bigint>>(flags: T) =>
42
+ (list: Array<keyof T>) =>
43
+ list.reduce((acc, key) => acc | flags[key], BigInt(0))
44
+
45
+ /**
46
+ * Returns a function that converts a list of flags names to a bitfield.
47
+ */
48
+ export const fromList =
49
+ <T extends Flags<number>>(flags: T) =>
50
+ (list: Array<keyof T>) =>
51
+ list.reduce((acc, key) => acc | flags[key], 0)
52
+
53
+ /**
54
+ * Checks if a bigint bitfield contains and a flag value.
55
+ */
56
+ export const hasBigInt = (flag: bigint | string) => {
57
+ const flagBigInt = BigInt(flag)
58
+ return (bits: bigint | string) => {
59
+ const bitsBigInt = BigInt(bits)
60
+ return (bitsBigInt & flagBigInt) === flagBigInt
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Checks if a bitfield contains and a flag value.
66
+ */
67
+ export const has = (flag: number | string) => {
68
+ const flagNumber = +flag
69
+ return (bits: number | string) => {
70
+ const bitsNumber = +bits
71
+ return (bitsNumber & flagNumber) === flagNumber
72
+ }
73
+ }
@@ -0,0 +1,35 @@
1
+ import * as Flags from "./flags.ts"
2
+ import * as Discord from "../types.ts"
3
+
4
+ /**
5
+ * All the intents
6
+ */
7
+ export const ALL = Flags.all(Discord.GatewayIntentBits)
8
+
9
+ /**
10
+ * Privileged intents
11
+ */
12
+ export const PRIVILEGED =
13
+ Discord.GatewayIntentBits.GuildPresences |
14
+ Discord.GatewayIntentBits.GuildMembers |
15
+ Discord.GatewayIntentBits.MessageContent
16
+
17
+ /**
18
+ * Un-privileged intents
19
+ */
20
+ export const UNPRIVILEGED = ALL ^ PRIVILEGED
21
+
22
+ /**
23
+ * Function that converts a intents bitfield value to a list of intent names.
24
+ */
25
+ export const toList = Flags.toList(Discord.GatewayIntentBits)
26
+
27
+ /**
28
+ * Function that converts a list of intent names to a bitfield value.
29
+ */
30
+ export const fromList = Flags.fromList(Discord.GatewayIntentBits)
31
+
32
+ /**
33
+ * Check if an intent flag exists in the permissions.
34
+ */
35
+ export const has = Flags.has