dfx 0.50.1 → 0.51.1

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 (335) hide show
  1. package/Cache/driver.d.ts +17 -16
  2. package/Cache/driver.d.ts.map +1 -1
  3. package/Cache/driver.js +10 -2
  4. package/Cache/driver.js.map +1 -1
  5. package/Cache/memory.d.ts +3 -3
  6. package/Cache/memory.d.ts.map +1 -1
  7. package/Cache/memory.js +55 -45
  8. package/Cache/memory.js.map +1 -1
  9. package/Cache/memoryTTL.d.ts +7 -6
  10. package/Cache/memoryTTL.d.ts.map +1 -1
  11. package/Cache/memoryTTL.js +126 -118
  12. package/Cache/memoryTTL.js.map +1 -1
  13. package/Cache/prelude.d.ts +53 -47
  14. package/Cache/prelude.d.ts.map +1 -1
  15. package/Cache/prelude.js +125 -95
  16. package/Cache/prelude.js.map +1 -1
  17. package/Cache.d.ts +33 -32
  18. package/Cache.d.ts.map +1 -1
  19. package/Cache.js +137 -57
  20. package/Cache.js.map +1 -1
  21. package/DiscordConfig.d.ts +26 -20
  22. package/DiscordConfig.d.ts.map +1 -1
  23. package/DiscordConfig.js +43 -26
  24. package/DiscordConfig.js.map +1 -1
  25. package/DiscordGateway/DiscordWS.d.ts +17 -14
  26. package/DiscordGateway/DiscordWS.d.ts.map +1 -1
  27. package/DiscordGateway/DiscordWS.js +49 -29
  28. package/DiscordGateway/DiscordWS.js.map +1 -1
  29. package/DiscordGateway/Shard/heartbeats.d.ts +7 -3
  30. package/DiscordGateway/Shard/heartbeats.d.ts.map +1 -1
  31. package/DiscordGateway/Shard/heartbeats.js +28 -15
  32. package/DiscordGateway/Shard/heartbeats.js.map +1 -1
  33. package/DiscordGateway/Shard/identify.d.ts +11 -8
  34. package/DiscordGateway/Shard/identify.d.ts.map +1 -1
  35. package/DiscordGateway/Shard/identify.js +41 -21
  36. package/DiscordGateway/Shard/identify.js.map +1 -1
  37. package/DiscordGateway/Shard/invalidSession.d.ts +6 -3
  38. package/DiscordGateway/Shard/invalidSession.d.ts.map +1 -1
  39. package/DiscordGateway/Shard/invalidSession.js +14 -5
  40. package/DiscordGateway/Shard/invalidSession.js.map +1 -1
  41. package/DiscordGateway/Shard/sendEvents.d.ts +1 -1
  42. package/DiscordGateway/Shard/sendEvents.d.ts.map +1 -1
  43. package/DiscordGateway/Shard/sendEvents.js +30 -18
  44. package/DiscordGateway/Shard/sendEvents.js.map +1 -1
  45. package/DiscordGateway/Shard/utils.d.ts +7 -3
  46. package/DiscordGateway/Shard/utils.d.ts.map +1 -1
  47. package/DiscordGateway/Shard/utils.js +20 -8
  48. package/DiscordGateway/Shard/utils.js.map +1 -1
  49. package/DiscordGateway/Shard.d.ts +15 -10
  50. package/DiscordGateway/Shard.d.ts.map +1 -1
  51. package/DiscordGateway/Shard.js +109 -81
  52. package/DiscordGateway/Shard.js.map +1 -1
  53. package/DiscordGateway/ShardStore.d.ts +9 -6
  54. package/DiscordGateway/ShardStore.d.ts.map +1 -1
  55. package/DiscordGateway/ShardStore.js +30 -18
  56. package/DiscordGateway/ShardStore.js.map +1 -1
  57. package/DiscordGateway/Sharder.d.ts +17 -11
  58. package/DiscordGateway/Sharder.d.ts.map +1 -1
  59. package/DiscordGateway/Sharder.js +82 -51
  60. package/DiscordGateway/Sharder.js.map +1 -1
  61. package/DiscordGateway/WS.d.ts +13 -10
  62. package/DiscordGateway/WS.d.ts.map +1 -1
  63. package/DiscordGateway/WS.js +102 -71
  64. package/DiscordGateway/WS.js.map +1 -1
  65. package/DiscordGateway.d.ts +19 -13
  66. package/DiscordGateway.d.ts.map +1 -1
  67. package/DiscordGateway.js +45 -31
  68. package/DiscordGateway.js.map +1 -1
  69. package/DiscordREST/types.d.ts +5 -5
  70. package/DiscordREST/types.d.ts.map +1 -1
  71. package/DiscordREST/types.js +5 -1
  72. package/DiscordREST/types.js.map +1 -1
  73. package/DiscordREST/utils.d.ts +6 -4
  74. package/DiscordREST/utils.d.ts.map +1 -1
  75. package/DiscordREST/utils.js +27 -17
  76. package/DiscordREST/utils.js.map +1 -1
  77. package/DiscordREST.d.ts +11 -8
  78. package/DiscordREST.d.ts.map +1 -1
  79. package/DiscordREST.js +141 -123
  80. package/DiscordREST.js.map +1 -1
  81. package/Helpers/flags.js +31 -19
  82. package/Helpers/flags.js.map +1 -1
  83. package/Helpers/intents.d.ts.map +1 -1
  84. package/Helpers/intents.js +22 -10
  85. package/Helpers/intents.js.map +1 -1
  86. package/Helpers/interactions.d.ts +23 -22
  87. package/Helpers/interactions.d.ts.map +1 -1
  88. package/Helpers/interactions.js +75 -40
  89. package/Helpers/interactions.js.map +1 -1
  90. package/Helpers/members.d.ts +3 -3
  91. package/Helpers/members.d.ts.map +1 -1
  92. package/Helpers/members.js +10 -3
  93. package/Helpers/members.js.map +1 -1
  94. package/Helpers/permissions.d.ts +5 -4
  95. package/Helpers/permissions.d.ts.map +1 -1
  96. package/Helpers/permissions.js +69 -52
  97. package/Helpers/permissions.js.map +1 -1
  98. package/Helpers/ui.d.ts +1 -1
  99. package/Helpers/ui.d.ts.map +1 -1
  100. package/Helpers/ui.js +44 -29
  101. package/Helpers/ui.js.map +1 -1
  102. package/Interactions/builder.d.ts +20 -19
  103. package/Interactions/builder.d.ts.map +1 -1
  104. package/Interactions/builder.js +66 -63
  105. package/Interactions/builder.js.map +1 -1
  106. package/Interactions/context.d.ts +26 -23
  107. package/Interactions/context.d.ts.map +1 -1
  108. package/Interactions/context.js +87 -55
  109. package/Interactions/context.js.map +1 -1
  110. package/Interactions/definitions.d.ts +33 -30
  111. package/Interactions/definitions.d.ts.map +1 -1
  112. package/Interactions/definitions.js +61 -47
  113. package/Interactions/definitions.js.map +1 -1
  114. package/Interactions/gateway.d.ts +15 -10
  115. package/Interactions/gateway.d.ts.map +1 -1
  116. package/Interactions/gateway.js +55 -36
  117. package/Interactions/gateway.js.map +1 -1
  118. package/Interactions/handlers.d.ts +6 -4
  119. package/Interactions/handlers.d.ts.map +1 -1
  120. package/Interactions/handlers.js +68 -42
  121. package/Interactions/handlers.js.map +1 -1
  122. package/Interactions/index.d.ts +11 -10
  123. package/Interactions/index.d.ts.map +1 -1
  124. package/Interactions/index.js +95 -10
  125. package/Interactions/index.js.map +1 -1
  126. package/Interactions/utils.d.ts +42 -40
  127. package/Interactions/utils.d.ts.map +1 -1
  128. package/Interactions/utils.js +40 -32
  129. package/Interactions/utils.js.map +1 -1
  130. package/Interactions/webhook.d.ts +22 -17
  131. package/Interactions/webhook.d.ts.map +1 -1
  132. package/Interactions/webhook.js +74 -39
  133. package/Interactions/webhook.js.map +1 -1
  134. package/Log.d.ts +8 -5
  135. package/Log.d.ts.map +1 -1
  136. package/Log.js +23 -14
  137. package/Log.js.map +1 -1
  138. package/RateLimit/memory.d.ts +1 -1
  139. package/RateLimit/memory.d.ts.map +1 -1
  140. package/RateLimit/memory.js +46 -33
  141. package/RateLimit/memory.js.map +1 -1
  142. package/RateLimit/utils.d.ts +1 -1
  143. package/RateLimit/utils.d.ts.map +1 -1
  144. package/RateLimit/utils.js +23 -16
  145. package/RateLimit/utils.js.map +1 -1
  146. package/RateLimit.d.ts +18 -14
  147. package/RateLimit.d.ts.map +1 -1
  148. package/RateLimit.js +40 -24
  149. package/RateLimit.js.map +1 -1
  150. package/gateway.d.ts +20 -13
  151. package/gateway.d.ts.map +1 -1
  152. package/gateway.js +72 -25
  153. package/gateway.js.map +1 -1
  154. package/index.d.ts +14 -13
  155. package/index.d.ts.map +1 -1
  156. package/index.js +71 -13
  157. package/index.js.map +1 -1
  158. package/mjs/Cache/driver.mjs +3 -0
  159. package/mjs/Cache/driver.mjs.map +1 -0
  160. package/mjs/Cache/memory.mjs +48 -0
  161. package/mjs/Cache/memory.mjs.map +1 -0
  162. package/mjs/Cache/memoryTTL.mjs +119 -0
  163. package/mjs/Cache/memoryTTL.mjs.map +1 -0
  164. package/mjs/Cache/prelude.mjs +125 -0
  165. package/mjs/Cache/prelude.mjs.map +1 -0
  166. package/mjs/Cache.mjs +87 -0
  167. package/mjs/Cache.mjs.map +1 -0
  168. package/mjs/DiscordConfig.mjs +34 -0
  169. package/mjs/DiscordConfig.mjs.map +1 -0
  170. package/mjs/DiscordGateway/DiscordWS.mjs +39 -0
  171. package/mjs/DiscordGateway/DiscordWS.mjs.map +1 -0
  172. package/mjs/DiscordGateway/Shard/heartbeats.mjs +21 -0
  173. package/mjs/DiscordGateway/Shard/heartbeats.mjs.map +1 -0
  174. package/mjs/DiscordGateway/Shard/identify.mjs +37 -0
  175. package/mjs/DiscordGateway/Shard/identify.mjs.map +1 -0
  176. package/mjs/DiscordGateway/Shard/invalidSession.mjs +6 -0
  177. package/mjs/DiscordGateway/Shard/invalidSession.mjs.map +1 -0
  178. package/mjs/DiscordGateway/Shard/sendEvents.mjs +25 -0
  179. package/mjs/DiscordGateway/Shard/sendEvents.mjs.map +1 -0
  180. package/mjs/DiscordGateway/Shard/utils.mjs +11 -0
  181. package/mjs/DiscordGateway/Shard/utils.mjs.map +1 -0
  182. package/mjs/DiscordGateway/Shard.mjs +99 -0
  183. package/mjs/DiscordGateway/Shard.mjs.map +1 -0
  184. package/mjs/DiscordGateway/ShardStore.mjs +24 -0
  185. package/mjs/DiscordGateway/ShardStore.mjs.map +1 -0
  186. package/mjs/DiscordGateway/Sharder.mjs +73 -0
  187. package/mjs/DiscordGateway/Sharder.mjs.map +1 -0
  188. package/mjs/DiscordGateway/WS.mjs +94 -0
  189. package/mjs/DiscordGateway/WS.mjs.map +1 -0
  190. package/mjs/DiscordGateway.mjs +36 -0
  191. package/mjs/DiscordGateway.mjs.map +1 -0
  192. package/mjs/DiscordREST/types.mjs +2 -0
  193. package/mjs/DiscordREST/types.mjs.map +1 -0
  194. package/mjs/DiscordREST/utils.mjs +19 -0
  195. package/mjs/DiscordREST/utils.mjs.map +1 -0
  196. package/mjs/DiscordREST.mjs +129 -0
  197. package/mjs/DiscordREST.mjs.map +1 -0
  198. package/mjs/Helpers/flags.mjs +36 -0
  199. package/mjs/Helpers/flags.mjs.map +1 -0
  200. package/mjs/Helpers/intents.mjs +27 -0
  201. package/mjs/Helpers/intents.mjs.map +1 -0
  202. package/mjs/Helpers/interactions.mjs +104 -0
  203. package/mjs/Helpers/interactions.mjs.map +1 -0
  204. package/mjs/Helpers/members.mjs +9 -0
  205. package/mjs/Helpers/members.mjs.map +1 -0
  206. package/mjs/Helpers/permissions.mjs +82 -0
  207. package/mjs/Helpers/permissions.mjs.map +1 -0
  208. package/mjs/Helpers/ui.mjs +66 -0
  209. package/mjs/Helpers/ui.mjs.map +1 -0
  210. package/mjs/Interactions/builder.mjs +62 -0
  211. package/mjs/Interactions/builder.mjs.map +1 -0
  212. package/mjs/Interactions/context.mjs +63 -0
  213. package/mjs/Interactions/context.mjs.map +1 -0
  214. package/mjs/Interactions/definitions.mjs +51 -0
  215. package/mjs/Interactions/definitions.mjs.map +1 -0
  216. package/mjs/Interactions/gateway.mjs +48 -0
  217. package/mjs/Interactions/gateway.mjs.map +1 -0
  218. package/mjs/Interactions/handlers.mjs +61 -0
  219. package/mjs/Interactions/handlers.mjs.map +1 -0
  220. package/mjs/Interactions/index.mjs +12 -0
  221. package/mjs/Interactions/index.mjs.map +1 -0
  222. package/mjs/Interactions/utils.mjs +35 -0
  223. package/mjs/Interactions/utils.mjs.map +1 -0
  224. package/mjs/Interactions/webhook.mjs +73 -0
  225. package/mjs/Interactions/webhook.mjs.map +1 -0
  226. package/mjs/Log.mjs +15 -0
  227. package/mjs/Log.mjs.map +1 -0
  228. package/mjs/RateLimit/memory.mjs +39 -0
  229. package/mjs/RateLimit/memory.mjs.map +1 -0
  230. package/mjs/RateLimit/utils.mjs +18 -0
  231. package/mjs/RateLimit/utils.mjs.map +1 -0
  232. package/mjs/RateLimit.mjs +29 -0
  233. package/mjs/RateLimit.mjs.map +1 -0
  234. package/mjs/gateway.mjs +27 -0
  235. package/mjs/gateway.mjs.map +1 -0
  236. package/mjs/index.mjs +15 -0
  237. package/mjs/index.mjs.map +1 -0
  238. package/mjs/types.mjs +1211 -0
  239. package/mjs/types.mjs.map +1 -0
  240. package/mjs/utils/Effect.mjs +28 -0
  241. package/mjs/utils/Effect.mjs.map +1 -0
  242. package/mjs/utils/tsplus.mjs +2 -0
  243. package/mjs/utils/tsplus.mjs.map +1 -0
  244. package/mjs/version.mjs +2 -0
  245. package/mjs/version.mjs.map +1 -0
  246. package/mjs/webhooks.mjs +30 -0
  247. package/mjs/webhooks.mjs.map +1 -0
  248. package/package.json +42 -50
  249. package/src/Cache/driver.ts +27 -15
  250. package/src/Cache/memory.ts +13 -9
  251. package/src/Cache/memoryTTL.ts +69 -53
  252. package/src/Cache/prelude.ts +113 -91
  253. package/src/Cache.ts +86 -61
  254. package/src/DiscordConfig.ts +34 -19
  255. package/src/DiscordGateway/DiscordWS.ts +28 -25
  256. package/src/DiscordGateway/Shard/heartbeats.ts +52 -27
  257. package/src/DiscordGateway/Shard/identify.ts +29 -23
  258. package/src/DiscordGateway/Shard/invalidSession.ts +9 -7
  259. package/src/DiscordGateway/Shard/sendEvents.ts +1 -1
  260. package/src/DiscordGateway/Shard/utils.ts +36 -9
  261. package/src/DiscordGateway/Shard.ts +129 -104
  262. package/src/DiscordGateway/ShardStore.ts +12 -5
  263. package/src/DiscordGateway/Sharder.ts +98 -77
  264. package/src/DiscordGateway/WS.ts +87 -58
  265. package/src/DiscordGateway.ts +59 -18
  266. package/src/DiscordREST/types.ts +5 -5
  267. package/src/DiscordREST/utils.ts +13 -8
  268. package/src/DiscordREST.ts +160 -131
  269. package/src/Helpers/intents.ts +1 -0
  270. package/src/Helpers/interactions.ts +76 -65
  271. package/src/Helpers/members.ts +2 -0
  272. package/src/Helpers/permissions.ts +6 -5
  273. package/src/Helpers/ui.ts +1 -1
  274. package/src/Interactions/builder.ts +56 -43
  275. package/src/Interactions/context.ts +67 -37
  276. package/src/Interactions/definitions.ts +32 -24
  277. package/src/Interactions/gateway.ts +80 -46
  278. package/src/Interactions/handlers.ts +68 -48
  279. package/src/Interactions/index.ts +6 -5
  280. package/src/Interactions/utils.ts +32 -21
  281. package/src/Interactions/webhook.ts +90 -51
  282. package/src/Log.ts +5 -1
  283. package/src/RateLimit/memory.ts +10 -4
  284. package/src/RateLimit/utils.ts +1 -1
  285. package/src/RateLimit.ts +38 -25
  286. package/src/gateway.ts +62 -25
  287. package/src/index.ts +29 -15
  288. package/src/utils/Effect.ts +69 -0
  289. package/src/version.ts +1 -0
  290. package/src/webhooks.ts +47 -20
  291. package/tsconfig.base.json +48 -0
  292. package/tsconfig.build.json +10 -0
  293. package/tsconfig.examples.json +11 -0
  294. package/tsconfig.json +12 -8
  295. package/tsconfig.madge.json +12 -0
  296. package/tsconfig.test.json +10 -0
  297. package/types.d.ts.map +1 -1
  298. package/types.js +1216 -1200
  299. package/types.js.map +1 -1
  300. package/utils/Effect.d.ts +8 -0
  301. package/utils/Effect.d.ts.map +1 -0
  302. package/utils/Effect.js +38 -0
  303. package/utils/Effect.js.map +1 -0
  304. package/utils/tsplus.js +5 -1
  305. package/utils/tsplus.js.map +1 -1
  306. package/version.d.ts +2 -0
  307. package/version.d.ts.map +1 -0
  308. package/version.js +9 -0
  309. package/version.js.map +1 -0
  310. package/webhooks.d.ts +14 -9
  311. package/webhooks.d.ts.map +1 -1
  312. package/webhooks.js +76 -27
  313. package/webhooks.js.map +1 -1
  314. package/_common.d.ts +0 -37
  315. package/_common.d.ts.map +0 -1
  316. package/_common.js +0 -8
  317. package/_common.js.map +0 -1
  318. package/global.d.ts +0 -18
  319. package/global.d.ts.map +0 -1
  320. package/global.js +0 -2
  321. package/global.js.map +0 -1
  322. package/src/_common.ts +0 -43
  323. package/src/global.ts +0 -45
  324. package/src/package.json +0 -52
  325. package/src/utils/effect.ts +0 -0
  326. package/src/utils/hub.ts +0 -47
  327. package/tsplus.config.json +0 -8
  328. package/utils/effect.d.ts +0 -2
  329. package/utils/effect.d.ts.map +0 -1
  330. package/utils/effect.js +0 -2
  331. package/utils/effect.js.map +0 -1
  332. package/utils/hub.d.ts +0 -12
  333. package/utils/hub.d.ts.map +0 -1
  334. package/utils/hub.js +0 -23
  335. package/utils/hub.js.map +0 -1
@@ -1,20 +1,25 @@
1
1
  import * as Http from "@effect-http/client"
2
+ import { Tag } from "@effect/data/Context"
3
+ import * as Duration from "@effect/data/Duration"
2
4
  import { millis } from "@effect/data/Duration"
3
- import { DiscordConfig } from "./DiscordConfig.js"
4
- import { ResponseWithData, RestResponse } from "./DiscordREST/types.js"
5
+ import { pipe } from "@effect/data/Function"
6
+ import * as HashSet from "@effect/data/HashSet"
7
+ import * as Option from "@effect/data/Option"
8
+ import * as ConfigSecret from "@effect/io/Config/Secret"
9
+ import * as Effect from "@effect/io/Effect"
10
+ import * as Layer from "@effect/io/Layer"
11
+ import * as Ref from "@effect/io/Ref"
12
+ import { DiscordConfig } from "dfx/DiscordConfig"
13
+ import type { ResponseWithData, RestResponse } from "dfx/DiscordREST/types"
5
14
  import {
6
15
  rateLimitFromHeaders,
7
16
  retryAfter,
8
17
  routeFromConfig,
9
- } from "./DiscordREST/utils.js"
10
- import { Log } from "./Log.js"
11
- import {
12
- BucketDetails,
13
- LiveRateLimiter,
14
- RateLimitStore,
15
- RateLimiter,
16
- } from "./RateLimit.js"
17
- import Pkg from "./package.json" assert { type: "json" }
18
+ } from "dfx/DiscordREST/utils"
19
+ import { Log } from "dfx/Log"
20
+ import { LiveRateLimiter, RateLimitStore, RateLimiter } from "dfx/RateLimit"
21
+ import * as Discord from "dfx/types"
22
+ import { LIB_VERSION } from "dfx/version"
18
23
 
19
24
  export class DiscordRESTError {
20
25
  readonly _tag = "DiscordRESTError"
@@ -23,172 +28,194 @@ export class DiscordRESTError {
23
28
 
24
29
  export { ResponseDecodeError } from "@effect-http/client"
25
30
 
26
- const make = Do($ => {
27
- const { token, rest } = $(DiscordConfig)
31
+ const make = Effect.gen(function* (_) {
32
+ const { rest, token } = yield* _(DiscordConfig)
28
33
 
29
- const http = $(Http.HttpRequestExecutor)
30
- const log = $(Log)
31
- const store = $(RateLimitStore)
32
- const { maybeWait } = $(RateLimiter)
34
+ const http = yield* _(Http.HttpRequestExecutor)
35
+ const log = yield* _(Log)
36
+ const store = yield* _(RateLimitStore)
37
+ const { maybeWait } = yield* _(RateLimiter)
33
38
 
34
39
  const globalRateLimit = maybeWait(
35
40
  "dfx.rest.global",
36
- rest.globalRateLimit.window,
41
+ Duration.decode(rest.globalRateLimit.window),
37
42
  rest.globalRateLimit.limit,
38
43
  )
39
44
 
40
45
  // Invalid route handling (40x)
41
- const badRoutesRef = $(Ref.make(HashSet.empty<string>()))
46
+ const badRoutesRef = yield* _(Ref.make(HashSet.empty<string>()))
47
+ const tenMinutes = Duration.toMillis(Duration.minutes(10))
42
48
  const addBadRoute = (route: string) =>
43
- Effect.allParDiscard([
49
+ Effect.all(
44
50
  log.info("DiscordREST", "addBadRoute", route),
45
- badRoutesRef.update(s => s.add(route)),
46
- store.incrementCounter(
47
- "dfx.rest.invalid",
48
- Duration.minutes(10).millis,
49
- 10000,
50
- ),
51
- ])
52
- const isBadRoute = (route: string) => badRoutesRef.get.map(s => s.has(route))
51
+ Ref.update(badRoutesRef, HashSet.add(route)),
52
+ store.incrementCounter("dfx.rest.invalid", tenMinutes, 10000),
53
+ { discard: true, concurrency: "unbounded" },
54
+ )
55
+ const isBadRoute = (route: string) =>
56
+ Effect.map(Ref.get(badRoutesRef), HashSet.has(route))
53
57
  const removeBadRoute = (route: string) =>
54
- badRoutesRef.update(s => s.remove(route))
58
+ Ref.update(badRoutesRef, HashSet.remove(route))
55
59
 
56
60
  const invalidRateLimit = (route: string) =>
57
- isBadRoute(route).tap(invalid =>
58
- invalid
59
- ? maybeWait("dfx.rest.invalid", Duration.minutes(10), 10000)
60
- : Effect.unit(),
61
- ).asUnit
61
+ isBadRoute(route).pipe(
62
+ Effect.tap(invalid =>
63
+ invalid
64
+ ? maybeWait("dfx.rest.invalid", Duration.minutes(10), 10000)
65
+ : Effect.unit,
66
+ ),
67
+ Effect.asUnit,
68
+ )
62
69
 
63
70
  // Request rate limiting
64
71
  const requestRateLimit = (path: string, request: Http.Request) =>
65
- Do($ => {
66
- const route = routeFromConfig(path, request.method)
67
- const maybeBucket = $(store.getBucketForRoute(route))
68
-
69
- const effect = maybeBucket.match(
70
- () => invalidRateLimit(route),
71
- bucket =>
72
- Do($ => {
73
- $(invalidRateLimit(route))
74
- const resetAfter = millis(bucket.resetAfter)
75
-
76
- $(maybeWait(`dfx.rest.${bucket.key}`, resetAfter, bucket.limit))
77
- }),
78
- )
79
-
80
- $(effect)
81
- })
72
+ Effect.Do.pipe(
73
+ Effect.let("route", () => routeFromConfig(path, request.method)),
74
+ Effect.bind("maybeBucket", ({ route }) => store.getBucketForRoute(route)),
75
+ Effect.flatMap(({ maybeBucket, route }) =>
76
+ Option.match(maybeBucket, {
77
+ onNone: () => invalidRateLimit(route),
78
+ onSome: bucket =>
79
+ Effect.zipRight(
80
+ invalidRateLimit(route),
81
+ maybeWait(
82
+ `dfx.rest.${bucket.key}`,
83
+ millis(bucket.resetAfter),
84
+ bucket.limit,
85
+ ),
86
+ ),
87
+ }),
88
+ ),
89
+ )
82
90
 
83
91
  // Update rate limit buckets
84
92
  const updateBuckets = (request: Http.Request, response: Http.Response) =>
85
- Do($ => {
86
- const route = routeFromConfig(request.url, request.method)
87
- const { bucket, retryAfter, limit, remaining } = $(
88
- rateLimitFromHeaders(response.headers),
89
- )
90
-
91
- const effectsToRun = [
92
- removeBadRoute(route),
93
- store.putBucketRoute(route, bucket),
94
- ]
95
-
96
- const hasBucket = $(store.hasBucket(bucket))
97
- if (!hasBucket || limit - 1 === remaining) {
98
- effectsToRun.push(
99
- store.removeCounter(`dfx.rest.?.${route}`),
100
- store.putBucket({
101
- key: bucket,
102
- resetAfter: retryAfter.millis,
103
- limit: !hasBucket && remaining > 0 ? remaining : limit,
104
- }),
105
- )
106
- }
107
-
108
- $(Effect.allParDiscard(effectsToRun))
109
- }).ignore
93
+ Effect.Do.pipe(
94
+ Effect.let("route", () => routeFromConfig(request.url, request.method)),
95
+ Effect.bind("rateLimit", () => rateLimitFromHeaders(response.headers)),
96
+ Effect.bind("hasBucket", ({ rateLimit }) =>
97
+ store.hasBucket(rateLimit.bucket),
98
+ ),
99
+ Effect.flatMap(({ hasBucket, rateLimit, route }) => {
100
+ const effectsToRun = [
101
+ removeBadRoute(route),
102
+ store.putBucketRoute(route, rateLimit.bucket),
103
+ ]
104
+
105
+ if (!hasBucket || rateLimit.limit - 1 === rateLimit.remaining) {
106
+ effectsToRun.push(
107
+ store.removeCounter(`dfx.rest.?.${route}`),
108
+ store.putBucket({
109
+ key: rateLimit.bucket,
110
+ resetAfter: Duration.toMillis(rateLimit.retryAfter),
111
+ limit:
112
+ !hasBucket && rateLimit.remaining > 0
113
+ ? rateLimit.remaining
114
+ : rateLimit.limit,
115
+ }),
116
+ )
117
+ }
110
118
 
111
- const httpExecutor = http.execute.filterStatusOk
112
- .contramap(_ =>
113
- _.updateUrl(_ => `${rest.baseUrl}${_}`).setHeaders({
114
- Authorization: `Bot ${token.value}`,
115
- "User-Agent": `DiscordBot (https://github.com/tim-smart/dfx, ${Pkg.version})`,
119
+ return Effect.all(effectsToRun, {
120
+ concurrency: "unbounded",
121
+ discard: true,
122
+ })
116
123
  }),
124
+ Effect.ignore,
117
125
  )
118
- .catchAll(error =>
126
+
127
+ const httpExecutor = pipe(
128
+ http.execute,
129
+ Http.executor.filterStatusOk,
130
+ Http.executor.contramap(req =>
131
+ pipe(
132
+ Http.updateUrl(req, _ => `${rest.baseUrl}${_}`),
133
+ Http.setHeaders({
134
+ Authorization: `Bot ${ConfigSecret.value(token)}`,
135
+ "User-Agent": `DiscordBot (https://github.com/tim-smart/dfx, ${LIB_VERSION})`,
136
+ }),
137
+ ),
138
+ ),
139
+ Http.executor.catchAll(error =>
119
140
  error._tag === "StatusCodeError"
120
- ? error.response.json
121
- .mapError(_ => new DiscordRESTError(_))
122
- .flatMap(body => Effect.fail(new DiscordRESTError(error, body)))
141
+ ? error.response.json.pipe(
142
+ Effect.mapError(_ => new DiscordRESTError(_)),
143
+ Effect.flatMap(body =>
144
+ Effect.fail(new DiscordRESTError(error, body)),
145
+ ),
146
+ )
123
147
  : Effect.fail(new DiscordRESTError(error)),
124
- )
148
+ ),
149
+ )
125
150
 
126
151
  const executor = <A = unknown>(
127
152
  request: Http.Request,
128
- ): Effect<never, DiscordRESTError, ResponseWithData<A>> =>
129
- Do($ => {
130
- $(requestRateLimit(request.url, request))
131
- $(globalRateLimit)
132
-
133
- const response = $(httpExecutor(request))
134
-
135
- $(updateBuckets(request, response))
136
-
137
- return response as ResponseWithData<A>
138
- }).catchTag("DiscordRESTError", e => {
139
- if (e.error._tag !== "StatusCodeError") {
140
- return Effect.fail(e)
141
- }
142
-
143
- const response = e.error.response
153
+ ): Effect.Effect<never, DiscordRESTError, ResponseWithData<A>> =>
154
+ requestRateLimit(request.url, request).pipe(
155
+ Effect.zipLeft(globalRateLimit),
156
+ Effect.zipRight(
157
+ httpExecutor(request) as Effect.Effect<
158
+ never,
159
+ DiscordRESTError,
160
+ ResponseWithData<A>
161
+ >,
162
+ ),
163
+ Effect.tap(response => updateBuckets(request, response)),
164
+ Effect.catchTag("DiscordRESTError", e => {
165
+ if (e.error._tag !== "StatusCodeError") {
166
+ return Effect.fail(e)
167
+ }
144
168
 
145
- switch (e.error.status) {
146
- case 403:
147
- return Do($ => {
148
- $(
149
- Effect.allParDiscard([
150
- log.info("DiscordREST", "403", request.url),
151
- addBadRoute(routeFromConfig(request.url, request.method)),
152
- updateBuckets(request, response),
153
- ]),
169
+ const response = e.error.response
170
+
171
+ switch (e.error.status) {
172
+ case 403:
173
+ return Effect.zipRight(
174
+ Effect.all(
175
+ [
176
+ log.info("DiscordREST", "403", request.url),
177
+ addBadRoute(routeFromConfig(request.url, request.method)),
178
+ updateBuckets(request, response),
179
+ ],
180
+ { concurrency: "unbounded", discard: true },
181
+ ),
182
+ Effect.fail(e),
154
183
  )
155
- return $(Effect.fail(e))
156
- })
157
184
 
158
- case 429:
159
- return Do($ => {
160
- $(
161
- Effect.allParDiscard([
185
+ case 429:
186
+ return Effect.zipRight(
187
+ Effect.all(
162
188
  log.info("DiscordREST", "429", request.url),
163
189
  addBadRoute(routeFromConfig(request.url, request.method)),
164
190
  updateBuckets(request, response),
165
191
  Effect.sleep(
166
- retryAfter(response.headers).getOrElse(() =>
192
+ Option.getOrElse(retryAfter(response.headers), () =>
167
193
  Duration.seconds(5),
168
194
  ),
169
195
  ),
170
- ]),
196
+ { concurrency: "unbounded", discard: true },
197
+ ),
198
+ executor<A>(request),
171
199
  )
172
- return $(executor<A>(request))
173
- })
174
- }
200
+ }
175
201
 
176
- return Effect.fail(e)
177
- })
202
+ return Effect.fail(e)
203
+ }),
204
+ )
178
205
 
179
206
  const routes = Discord.createRoutes<Partial<Http.MakeOptions>>(
180
207
  <R, P>({
181
208
  method,
182
- url,
183
- params,
184
209
  options = {},
210
+ params,
211
+ url,
185
212
  }: Discord.Route<P, Partial<Http.MakeOptions>>): RestResponse<R> => {
186
213
  const hasBody = method !== "GET" && method !== "DELETE"
187
214
  let request = Http.make(method as any)(url, options)
188
215
 
189
216
  if (!hasBody) {
190
217
  if (params) {
191
- request = request.appendParams(params as any)
218
+ request = Http.appendParams(request, params as any)
192
219
  }
193
220
  } else if (
194
221
  params &&
@@ -197,7 +224,7 @@ const make = Do($ => {
197
224
  ) {
198
225
  request.body.value.value.append("payload_json", JSON.stringify(params))
199
226
  } else if (params) {
200
- request = request.jsonBody(params)
227
+ request = Http.jsonBody(request, params)
201
228
  }
202
229
 
203
230
  return executor(request)
@@ -214,9 +241,11 @@ export interface DiscordREST
214
241
  extends Discord.Endpoints<Partial<Http.MakeOptions>> {
215
242
  readonly executor: <A = unknown>(
216
243
  request: Http.Request,
217
- ) => Effect<never, DiscordRESTError, ResponseWithData<A>>
244
+ ) => Effect.Effect<never, DiscordRESTError, ResponseWithData<A>>
218
245
  }
219
246
 
220
247
  export const DiscordREST = Tag<DiscordREST>()
221
- export const LiveDiscordREST =
222
- LiveRateLimiter >> Layer.effect(DiscordREST, make)
248
+ export const LiveDiscordREST = Layer.provide(
249
+ LiveRateLimiter,
250
+ Layer.effect(DiscordREST, make),
251
+ )
@@ -1,4 +1,5 @@
1
1
  import * as Flags from "dfx/Helpers/flags"
2
+ import * as Discord from "dfx/types"
2
3
 
3
4
  /**
4
5
  * All the intents
@@ -1,8 +1,11 @@
1
- import { Option as Maybe, Product } from "@effect/data/Option"
1
+ import * as Option from "@effect/data/Option"
2
2
  import * as Arr from "@effect/data/ReadonlyArray"
3
+ import * as Discord from "dfx/types"
4
+ import { identity, pipe } from "@effect/data/Function"
5
+ import * as HashMap from "@effect/data/HashMap"
3
6
 
4
7
  /**
5
- * Maybe find a sub-command within the interaction options.
8
+ * Option find a sub-command within the interaction options.
6
9
  */
7
10
  export const allSubCommands = (interaction: Discord.ApplicationCommandDatum) =>
8
11
  pipe(
@@ -13,7 +16,7 @@ export const allSubCommands = (interaction: Discord.ApplicationCommandDatum) =>
13
16
  )
14
17
 
15
18
  /**
16
- * Maybe find a sub-command within the interaction options.
19
+ * Option find a sub-command within the interaction options.
17
20
  */
18
21
  export const findSubCommand =
19
22
  (name: string) => (interaction: Discord.ApplicationCommandDatum) =>
@@ -29,14 +32,16 @@ export const findSubCommand =
29
32
  /**
30
33
  * If the sub-command exists return `true`, else `false`.
31
34
  */
32
- export const isSubCommand = (name: string) =>
33
- flow(findSubCommand(name), o => o.isSome())
35
+ export const isSubCommand =
36
+ (name: string) => (_: Discord.ApplicationCommandDatum) =>
37
+ Option.isSome(findSubCommand(name)(_))
34
38
 
35
39
  /**
36
- * Maybe get the options for a sub-command
40
+ * Option get the options for a sub-command
37
41
  */
38
- export const subCommandOptions = (name: string) =>
39
- flow(findSubCommand(name), o => o.flatMapNullable(o => o.options))
42
+ export const subCommandOptions =
43
+ (name: string) => (_: Discord.ApplicationCommandDatum) =>
44
+ Option.flatMapNullable(findSubCommand(name)(_), o => o.options)
40
45
 
41
46
  /**
42
47
  * A lens for accessing nested options in a interaction.
@@ -47,13 +52,15 @@ export const optionsWithNested = (
47
52
  const optsFromOption = (
48
53
  opt: Discord.ApplicationCommandInteractionDataOption,
49
54
  ): Discord.ApplicationCommandInteractionDataOption[] =>
50
- Maybe.fromNullable(opt.options)
51
- .map(opts => [...opts, ...opts.flatMap(optsFromOption)])
52
- .match(() => [], identity)
55
+ Option.fromNullable(opt.options).pipe(
56
+ Option.map(opts => [...opts, ...opts.flatMap(optsFromOption)]),
57
+ Option.match({ onNone: () => [], onSome: identity }),
58
+ )
53
59
 
54
- return Maybe.fromNullable(data.options)
55
- .map(opts => [...opts, ...opts.flatMap(optsFromOption)])
56
- .getOrElse(() => [])
60
+ return Option.fromNullable(data.options).pipe(
61
+ Option.map(opts => [...opts, ...opts.flatMap(optsFromOption)]),
62
+ Option.getOrElse(() => []),
63
+ )
57
64
  }
58
65
 
59
66
  /**
@@ -63,43 +70,44 @@ export const transformOptions = (
63
70
  options: Discord.ApplicationCommandInteractionDataOption[],
64
71
  ) =>
65
72
  options.reduce(
66
- (map, option) => map.set(option.name, option.value),
73
+ (map, option) => HashMap.set(map, option.name, option.value),
67
74
  HashMap.empty<string, string | undefined>(),
68
75
  )
69
76
 
70
77
  /**
71
78
  * Return the interaction options as a name / value map.
72
79
  */
73
- export const optionsMap = flow(optionsWithNested, transformOptions)
80
+ export const optionsMap = (
81
+ data: Pick<Discord.ApplicationCommandDatum, "options">,
82
+ ) => transformOptions(optionsWithNested(data))
74
83
 
75
84
  /**
76
85
  * Try find a matching option from the interaction.
77
86
  */
78
- export const getOption = (name: string) =>
79
- flow(
80
- optionsWithNested,
81
- Arr.findFirst(o => o.name === name),
82
- )
87
+ export const getOption =
88
+ (name: string) => (data: Pick<Discord.ApplicationCommandDatum, "options">) =>
89
+ Arr.findFirst(optionsWithNested(data), o => o.name === name)
83
90
 
84
91
  /**
85
92
  * Try find a matching option from the interaction.
86
93
  */
87
- export const focusedOption = flow(
88
- optionsWithNested,
89
- Arr.findFirst(o => o.focused === true),
90
- )
94
+ export const focusedOption = (
95
+ data: Pick<Discord.ApplicationCommandDatum, "options">,
96
+ ) => Arr.findFirst(optionsWithNested(data), o => o.focused === true)
91
97
 
92
98
  /**
93
99
  * Try find a matching option value from the interaction.
94
100
  */
95
- export const optionValue = (name: string) =>
96
- flow(getOption(name), o => o.flatMapNullable(o => o.value))
101
+ export const optionValue =
102
+ (name: string) => (data: Pick<Discord.ApplicationCommandDatum, "options">) =>
103
+ Option.flatMapNullable(getOption(name)(data), o => o.value)
97
104
 
98
105
  /**
99
106
  * Try extract resolved data
100
107
  */
101
108
  export const resolved = (data: Discord.Interaction) =>
102
- Maybe.fromNullable(data.data).flatMapNullable(
109
+ Option.flatMapNullable(
110
+ Option.fromNullable(data.data),
103
111
  a => (a as Discord.ApplicationCommandDatum).resolved,
104
112
  )
105
113
 
@@ -111,19 +119,20 @@ export const resolveOptionValue =
111
119
  name: string,
112
120
  f: (id: Discord.Snowflake, data: Discord.ResolvedDatum) => T | undefined,
113
121
  ) =>
114
- (a: Discord.Interaction): Maybe<T> =>
115
- Do($ => {
116
- const data = $(
117
- Maybe.fromNullable(a.data as Discord.ApplicationCommandDatum),
118
- )
119
- const id = $(
120
- getOption(name)(data).flatMapNullable(
122
+ (a: Discord.Interaction): Option.Option<T> =>
123
+ Option.Do().pipe(
124
+ Option.bind("data", () =>
125
+ Option.fromNullable(a.data as Discord.ApplicationCommandDatum),
126
+ ),
127
+ Option.bind("id", ({ data }) =>
128
+ Option.flatMapNullable(
129
+ getOption(name)(data),
121
130
  ({ value }) => value as Discord.Snowflake,
122
131
  ),
123
- )
124
- const r = $(resolved(a))
125
- return $(Maybe.fromNullable(f(id, r)))
126
- })
132
+ ),
133
+ Option.bind("r", () => resolved(a)),
134
+ Option.flatMapNullable(({ id, r }) => f(id, r)),
135
+ )
127
136
 
128
137
  /**
129
138
  * Try find matching option values from the interaction.
@@ -132,18 +141,19 @@ export const resolveValues =
132
141
  <T>(
133
142
  f: (id: Discord.Snowflake, data: Discord.ResolvedDatum) => T | undefined,
134
143
  ) =>
135
- (a: Discord.Interaction): Maybe<readonly T[]> =>
136
- Do($ => {
137
- const values = $(
138
- Maybe.fromNullable(
139
- a.data as Discord.MessageComponentDatum,
140
- ).flatMapNullable(a => a.values as unknown as string[]),
141
- )
142
- const r = $(resolved(a))
143
- return $(
144
- Product.productAll(values.map(a => Maybe.fromNullable(f(a as any, r)))),
145
- )
146
- })
144
+ (a: Discord.Interaction): Option.Option<readonly T[]> =>
145
+ Option.Do().pipe(
146
+ Option.bind("values", () =>
147
+ Option.flatMapNullable(
148
+ Option.fromNullable(a.data as Discord.MessageComponentDatum),
149
+ a => a.values as unknown as string[],
150
+ ),
151
+ ),
152
+ Option.bind("r", () => resolved(a)),
153
+ Option.map(({ values, r }) =>
154
+ Arr.compact(values.map(a => Option.fromNullable(f(a as any, r)))),
155
+ ),
156
+ )
147
157
 
148
158
  const extractComponents = (c: Discord.Component): Discord.Component[] => {
149
159
  if ("components" in c) {
@@ -166,41 +176,42 @@ export const components = (
166
176
  /**
167
177
  * A lens for accessing the components in a interaction.
168
178
  */
169
- export const componentsWithValue = flow(
170
- components,
171
- Arr.filter(c => "value" in c && c.value !== undefined),
172
- )
179
+ export const componentsWithValue = (data: Discord.ModalSubmitDatum) =>
180
+ Arr.filter(components(data), c => "value" in c && c.value !== undefined)
173
181
 
174
182
  /**
175
183
  * Return the interaction components as an id / value map.
176
184
  */
177
185
  export const transformComponents = (options: Discord.Component[]) =>
178
186
  (options as Discord.TextInput[]).reduce(
179
- (map, c) => (c.custom_id ? map.set(c.custom_id, c.value) : map),
187
+ (map, c) => (c.custom_id ? HashMap.set(map, c.custom_id, c.value) : map),
180
188
  HashMap.empty<string, string | undefined>(),
181
189
  )
182
190
 
183
191
  /**
184
192
  * Return the interaction components as an id / value map.
185
193
  */
186
- export const componentsMap = flow(components, transformComponents)
194
+ export const componentsMap = (data: Discord.ModalSubmitDatum) =>
195
+ transformComponents(components(data))
187
196
 
188
197
  /**
189
198
  * Try find a matching component from the interaction.
190
199
  */
191
- export const getComponent = (id: string) =>
192
- flow(
193
- components,
194
- Arr.findFirst(o => (o as Discord.TextInput).custom_id === id),
200
+ export const getComponent = (id: string) => (data: Discord.ModalSubmitDatum) =>
201
+ Arr.findFirst(
202
+ components(data),
203
+ o => (o as Discord.TextInput).custom_id === id,
195
204
  )
196
205
 
197
206
  /**
198
207
  * Try find a matching component value from the interaction.
199
208
  */
200
- export const componentValue = (id: string) =>
201
- flow(getComponent(id), o =>
202
- o.flatMapNullable(o => (o as Discord.TextInput).value),
203
- )
209
+ export const componentValue =
210
+ (id: string) => (data: Discord.ModalSubmitDatum) =>
211
+ Option.flatMapNullable(
212
+ getComponent(id)(data),
213
+ o => (o as Discord.TextInput).value,
214
+ )
204
215
 
205
216
  export type InteractionResponse =
206
217
  | {
@@ -1,3 +1,5 @@
1
+ import * as Discord from "dfx/types"
2
+
1
3
  /**
2
4
  * From a list of roles, filter out the ones the guild member has.
3
5
  */
@@ -1,5 +1,8 @@
1
+ import { pipe } from "@effect/data/Function"
2
+ import * as Effect from "@effect/io/Effect"
1
3
  import * as Flags from "dfx/Helpers/flags"
2
4
  import * as Members from "dfx/Helpers/members"
5
+ import * as Discord from "dfx/types"
3
6
 
4
7
  /**
5
8
  * A constant of all the permissions
@@ -109,7 +112,7 @@ export const applyOverwrites =
109
112
  interface RolesCache<E> {
110
113
  getForParent: (
111
114
  parentId: string,
112
- ) => Effect<never, E, ReadonlyMap<string, Discord.Role>>
115
+ ) => Effect.Effect<never, E, ReadonlyMap<string, Discord.Role>>
113
116
  }
114
117
 
115
118
  export const hasInChannel =
@@ -118,8 +121,7 @@ export const hasInChannel =
118
121
  channel: Discord.Channel,
119
122
  memberOrRole: Discord.GuildMember | Discord.Role,
120
123
  ) =>
121
- Do($ => {
122
- const roles = $(rolesCache.getForParent(channel.guild_id!))
124
+ Effect.map(rolesCache.getForParent(channel.guild_id!), roles => {
123
125
  const channelPerms = forChannel([...roles.values()])(channel)(
124
126
  memberOrRole,
125
127
  )
@@ -129,8 +131,7 @@ export const hasInChannel =
129
131
  export const hasInGuild =
130
132
  <E>(rolesCache: RolesCache<E>, permission: bigint) =>
131
133
  (guildId: Discord.Snowflake, member: Discord.GuildMember) =>
132
- Do($ => {
133
- const roles = $(rolesCache.getForParent(guildId))
134
+ Effect.map(rolesCache.getForParent(guildId), roles => {
134
135
  const hasPerm = has(permission)
135
136
 
136
137
  return member.roles.some(id => {