dfx 0.3.0 → 0.5.0

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 (312) hide show
  1. package/dist/DiscordConfig/index.d.ts +40 -0
  2. package/dist/DiscordConfig/index.d.ts.map +1 -0
  3. package/dist/DiscordConfig/index.js +29 -0
  4. package/dist/DiscordConfig/index.js.map +1 -0
  5. package/dist/DiscordGateway/DiscordWS/index.d.ts +23 -0
  6. package/dist/DiscordGateway/DiscordWS/index.d.ts.map +1 -0
  7. package/dist/DiscordGateway/DiscordWS/index.js +25 -0
  8. package/dist/DiscordGateway/DiscordWS/index.js.map +1 -0
  9. package/dist/DiscordGateway/Shard/heartbeats.d.ts +3 -0
  10. package/dist/DiscordGateway/Shard/heartbeats.d.ts.map +1 -0
  11. package/dist/DiscordGateway/Shard/heartbeats.js +23 -0
  12. package/dist/DiscordGateway/Shard/heartbeats.js.map +1 -0
  13. package/dist/DiscordGateway/Shard/identify.d.ts +13 -0
  14. package/dist/DiscordGateway/Shard/identify.d.ts.map +1 -0
  15. package/dist/DiscordGateway/Shard/identify.js +30 -0
  16. package/dist/DiscordGateway/Shard/identify.js.map +1 -0
  17. package/dist/DiscordGateway/Shard/index.d.ts +9 -0
  18. package/dist/DiscordGateway/Shard/index.d.ts.map +1 -0
  19. package/dist/DiscordGateway/Shard/index.js +51 -0
  20. package/dist/DiscordGateway/Shard/index.js.map +1 -0
  21. package/dist/DiscordGateway/Shard/invalidSession.d.ts +3 -0
  22. package/dist/DiscordGateway/Shard/invalidSession.d.ts.map +1 -0
  23. package/dist/DiscordGateway/Shard/invalidSession.js +9 -0
  24. package/dist/DiscordGateway/Shard/invalidSession.js.map +1 -0
  25. package/dist/DiscordGateway/Shard/sendEvents.d.ts +8 -0
  26. package/dist/DiscordGateway/Shard/sendEvents.d.ts.map +1 -0
  27. package/dist/DiscordGateway/Shard/sendEvents.js +26 -0
  28. package/dist/DiscordGateway/Shard/sendEvents.js.map +1 -0
  29. package/dist/DiscordGateway/Shard/utils.d.ts +4 -0
  30. package/dist/DiscordGateway/Shard/utils.d.ts.map +1 -0
  31. package/dist/DiscordGateway/Shard/utils.js +9 -0
  32. package/dist/DiscordGateway/Shard/utils.js.map +1 -0
  33. package/dist/DiscordGateway/ShardStore/index.d.ts +13 -0
  34. package/dist/DiscordGateway/ShardStore/index.d.ts.map +1 -0
  35. package/dist/DiscordGateway/ShardStore/index.js +22 -0
  36. package/dist/DiscordGateway/ShardStore/index.js.map +1 -0
  37. package/dist/DiscordGateway/Sharder/index.d.ts +10 -0
  38. package/dist/DiscordGateway/Sharder/index.d.ts.map +1 -0
  39. package/dist/DiscordGateway/Sharder/index.js +60 -0
  40. package/dist/DiscordGateway/Sharder/index.js.map +1 -0
  41. package/dist/DiscordGateway/WS/index.d.ts +28 -0
  42. package/dist/DiscordGateway/WS/index.d.ts.map +1 -0
  43. package/dist/DiscordGateway/WS/index.js +82 -0
  44. package/dist/DiscordGateway/WS/index.js.map +1 -0
  45. package/dist/DiscordGateway/index.d.ts +21 -0
  46. package/dist/DiscordGateway/index.d.ts.map +1 -0
  47. package/dist/DiscordGateway/index.js +27 -0
  48. package/dist/DiscordGateway/index.js.map +1 -0
  49. package/dist/DiscordREST/index.d.ts +13 -0
  50. package/dist/DiscordREST/index.d.ts.map +1 -0
  51. package/dist/DiscordREST/index.js +85 -0
  52. package/dist/DiscordREST/index.js.map +1 -0
  53. package/dist/DiscordREST/types.d.ts +10 -0
  54. package/dist/DiscordREST/types.d.ts.map +1 -0
  55. package/dist/DiscordREST/types.js +2 -0
  56. package/{esm → dist}/DiscordREST/types.js.map +1 -1
  57. package/dist/DiscordREST/utils.d.ts +11 -0
  58. package/dist/DiscordREST/utils.d.ts.map +1 -0
  59. package/dist/DiscordREST/utils.js +22 -0
  60. package/dist/DiscordREST/utils.js.map +1 -0
  61. package/dist/Helpers/flags.d.ts +28 -0
  62. package/dist/Helpers/flags.d.ts.map +1 -0
  63. package/dist/Helpers/flags.js +36 -0
  64. package/dist/Helpers/flags.js.map +1 -0
  65. package/dist/Helpers/intents.d.ts +25 -0
  66. package/dist/Helpers/intents.d.ts.map +1 -0
  67. package/dist/Helpers/intents.js +28 -0
  68. package/dist/Helpers/intents.js.map +1 -0
  69. package/dist/Helpers/interactions.d.ts +74 -0
  70. package/dist/Helpers/interactions.d.ts.map +1 -0
  71. package/dist/Helpers/interactions.js +93 -0
  72. package/dist/Helpers/interactions.js.map +1 -0
  73. package/dist/Helpers/members.d.ts +10 -0
  74. package/dist/Helpers/members.d.ts.map +1 -0
  75. package/dist/Helpers/members.js +10 -0
  76. package/dist/Helpers/members.js.map +1 -0
  77. package/dist/Helpers/permissions.d.ts +35 -0
  78. package/dist/Helpers/permissions.d.ts.map +1 -0
  79. package/dist/Helpers/permissions.js +69 -0
  80. package/dist/Helpers/permissions.js.map +1 -0
  81. package/dist/Helpers/ui.d.ts +48 -0
  82. package/dist/Helpers/ui.d.ts.map +1 -0
  83. package/dist/Helpers/ui.js +67 -0
  84. package/dist/Helpers/ui.js.map +1 -0
  85. package/dist/Http/index.d.ts +31 -0
  86. package/dist/Http/index.d.ts.map +1 -0
  87. package/dist/Http/index.js +54 -0
  88. package/dist/Http/index.js.map +1 -0
  89. package/dist/Interactions/context.d.ts +29 -0
  90. package/dist/Interactions/context.d.ts.map +1 -0
  91. package/dist/Interactions/context.js +23 -0
  92. package/dist/Interactions/context.js.map +1 -0
  93. package/dist/Interactions/definitions.d.ts +55 -0
  94. package/dist/Interactions/definitions.d.ts.map +1 -0
  95. package/dist/Interactions/definitions.js +52 -0
  96. package/dist/Interactions/definitions.js.map +1 -0
  97. package/dist/Interactions/gateway.d.ts +6 -0
  98. package/dist/Interactions/gateway.d.ts.map +1 -0
  99. package/dist/Interactions/gateway.js +17 -0
  100. package/dist/Interactions/gateway.js.map +1 -0
  101. package/dist/Interactions/handlers.d.ts +9 -0
  102. package/dist/Interactions/handlers.d.ts.map +1 -0
  103. package/dist/Interactions/handlers.js +49 -0
  104. package/dist/Interactions/handlers.js.map +1 -0
  105. package/dist/Interactions/index.d.ts +20 -0
  106. package/dist/Interactions/index.d.ts.map +1 -0
  107. package/dist/Interactions/index.js +31 -0
  108. package/dist/Interactions/index.js.map +1 -0
  109. package/dist/Interactions/utils.d.ts +10 -0
  110. package/dist/Interactions/utils.d.ts.map +1 -0
  111. package/dist/Interactions/utils.js +20 -0
  112. package/dist/Interactions/utils.js.map +1 -0
  113. package/dist/Interactions/webhook.d.ts +18 -0
  114. package/dist/Interactions/webhook.d.ts.map +1 -0
  115. package/dist/Interactions/webhook.js +26 -0
  116. package/dist/Interactions/webhook.js.map +1 -0
  117. package/dist/Log/index.d.ts +13 -0
  118. package/dist/Log/index.d.ts.map +1 -0
  119. package/dist/Log/index.js +19 -0
  120. package/dist/Log/index.js.map +1 -0
  121. package/dist/RateLimitStore/index.d.ts +25 -0
  122. package/dist/RateLimitStore/index.d.ts.map +1 -0
  123. package/dist/RateLimitStore/index.js +24 -0
  124. package/dist/RateLimitStore/index.js.map +1 -0
  125. package/dist/RateLimitStore/memory.d.ts +3 -0
  126. package/dist/RateLimitStore/memory.d.ts.map +1 -0
  127. package/dist/RateLimitStore/memory.js +31 -0
  128. package/dist/RateLimitStore/memory.js.map +1 -0
  129. package/dist/RateLimitStore/utils.d.ts +3 -0
  130. package/dist/RateLimitStore/utils.d.ts.map +1 -0
  131. package/dist/RateLimitStore/utils.js +18 -0
  132. package/dist/RateLimitStore/utils.js.map +1 -0
  133. package/dist/common.d.ts +34 -0
  134. package/dist/common.d.ts.map +1 -0
  135. package/dist/common.js +21 -0
  136. package/dist/common.js.map +1 -0
  137. package/dist/example.d.ts +2 -0
  138. package/dist/example.d.ts.map +1 -0
  139. package/dist/example.js +47 -0
  140. package/dist/example.js.map +1 -0
  141. package/dist/global.d.ts +14 -0
  142. package/dist/global.d.ts.map +1 -0
  143. package/dist/global.js +2 -0
  144. package/dist/global.js.map +1 -0
  145. package/dist/index.d.ts +21 -0
  146. package/dist/index.d.ts.map +1 -0
  147. package/dist/index.js +33 -0
  148. package/dist/index.js.map +1 -0
  149. package/{types.d.ts → dist/types.d.ts} +1456 -825
  150. package/dist/types.d.ts.map +1 -0
  151. package/{esm → dist}/types.js +283 -46
  152. package/dist/types.js.map +1 -0
  153. package/dist/utils/effect.d.ts +3 -0
  154. package/dist/utils/effect.d.ts.map +1 -0
  155. package/dist/utils/effect.js +2 -0
  156. package/dist/utils/effect.js.map +1 -0
  157. package/dist/utils/tsplus.d.ts +14 -0
  158. package/dist/utils/tsplus.d.ts.map +1 -0
  159. package/dist/utils/tsplus.js +2 -0
  160. package/dist/utils/tsplus.js.map +1 -0
  161. package/package.json +36 -51
  162. package/src/DiscordConfig/index.ts +52 -0
  163. package/src/DiscordGateway/DiscordWS/index.ts +50 -0
  164. package/src/DiscordGateway/Shard/heartbeats.ts +39 -0
  165. package/src/DiscordGateway/Shard/identify.ts +61 -0
  166. package/src/DiscordGateway/Shard/index.ts +90 -0
  167. package/src/DiscordGateway/Shard/invalidSession.ts +11 -0
  168. package/src/DiscordGateway/Shard/sendEvents.ts +35 -0
  169. package/src/DiscordGateway/Shard/utils.ts +14 -0
  170. package/src/DiscordGateway/ShardStore/index.ts +33 -0
  171. package/src/DiscordGateway/Sharder/index.ts +95 -0
  172. package/src/DiscordGateway/WS/index.ts +99 -0
  173. package/src/DiscordGateway/index.ts +55 -0
  174. package/src/DiscordREST/index.ts +132 -0
  175. package/src/DiscordREST/types.ts +14 -0
  176. package/src/DiscordREST/utils.ts +35 -0
  177. package/src/Helpers/flags.ts +68 -0
  178. package/src/Helpers/intents.ts +32 -0
  179. package/src/Helpers/interactions.ts +180 -0
  180. package/src/Helpers/members.ts +14 -0
  181. package/src/Helpers/permissions.ts +102 -0
  182. package/src/Helpers/ui.ts +103 -0
  183. package/src/Http/index.ts +65 -0
  184. package/src/Interactions/context.ts +76 -0
  185. package/src/Interactions/definitions.ts +124 -0
  186. package/src/Interactions/gateway.ts +44 -0
  187. package/src/Interactions/handlers.ts +139 -0
  188. package/src/Interactions/index.ts +57 -0
  189. package/src/Interactions/utils.ts +47 -0
  190. package/src/Interactions/webhook.ts +59 -0
  191. package/src/Log/index.ts +23 -0
  192. package/src/RateLimitStore/index.ts +65 -0
  193. package/src/RateLimitStore/memory.ts +48 -0
  194. package/src/RateLimitStore/utils.ts +27 -0
  195. package/src/common.ts +35 -0
  196. package/src/example.ts +52 -0
  197. package/src/global.ts +50 -0
  198. package/src/index.ts +45 -0
  199. package/src/json.d.ts +1 -0
  200. package/{types.ts → src/types.ts} +1616 -876
  201. package/src/utils/effect.ts +7 -0
  202. package/src/utils/tsplus.ts +11 -0
  203. package/DiscordConfig/index.d.ts +0 -29
  204. package/DiscordConfig/index.js +0 -31
  205. package/DiscordConfig/index.js.map +0 -1
  206. package/DiscordConfig/index.ts +0 -45
  207. package/DiscordGateway/index.d.ts +0 -23
  208. package/DiscordGateway/index.js +0 -25
  209. package/DiscordGateway/index.js.map +0 -1
  210. package/DiscordGateway/index.ts +0 -34
  211. package/DiscordGateway/utils.d.ts +0 -3
  212. package/DiscordGateway/utils.js +0 -12
  213. package/DiscordGateway/utils.js.map +0 -1
  214. package/DiscordGateway/utils.ts +0 -17
  215. package/DiscordREST/http.d.ts +0 -3
  216. package/DiscordREST/http.js +0 -20
  217. package/DiscordREST/http.js.map +0 -1
  218. package/DiscordREST/http.ts +0 -21
  219. package/DiscordREST/index.d.ts +0 -15
  220. package/DiscordREST/index.js +0 -63
  221. package/DiscordREST/index.js.map +0 -1
  222. package/DiscordREST/index.ts +0 -79
  223. package/DiscordREST/types.d.ts +0 -14
  224. package/DiscordREST/types.js +0 -6
  225. package/DiscordREST/types.js.map +0 -1
  226. package/DiscordREST/types.ts +0 -15
  227. package/DiscordShard/commands.d.ts +0 -7
  228. package/DiscordShard/commands.js +0 -38
  229. package/DiscordShard/commands.js.map +0 -1
  230. package/DiscordShard/commands.ts +0 -40
  231. package/DiscordShard/heartbeats.d.ts +0 -6
  232. package/DiscordShard/heartbeats.js +0 -29
  233. package/DiscordShard/heartbeats.js.map +0 -1
  234. package/DiscordShard/heartbeats.ts +0 -65
  235. package/DiscordShard/identify.d.ts +0 -15
  236. package/DiscordShard/identify.js +0 -35
  237. package/DiscordShard/identify.js.map +0 -1
  238. package/DiscordShard/identify.ts +0 -75
  239. package/DiscordShard/index.d.ts +0 -32
  240. package/DiscordShard/index.js +0 -63
  241. package/DiscordShard/index.js.map +0 -1
  242. package/DiscordShard/index.ts +0 -122
  243. package/DiscordShard/invalidSession.d.ts +0 -6
  244. package/DiscordShard/invalidSession.js +0 -17
  245. package/DiscordShard/invalidSession.js.map +0 -1
  246. package/DiscordShard/invalidSession.ts +0 -24
  247. package/DiscordShard/utils.d.ts +0 -7
  248. package/DiscordShard/utils.js +0 -17
  249. package/DiscordShard/utils.js.map +0 -1
  250. package/DiscordShard/utils.ts +0 -32
  251. package/DiscordWS/index.d.ts +0 -36
  252. package/DiscordWS/index.js +0 -39
  253. package/DiscordWS/index.js.map +0 -1
  254. package/DiscordWS/index.ts +0 -82
  255. package/Log/index.d.ts +0 -15
  256. package/Log/index.js +0 -28
  257. package/Log/index.js.map +0 -1
  258. package/Log/index.ts +0 -30
  259. package/Utils/memoize.d.ts +0 -3
  260. package/Utils/memoize.js +0 -16
  261. package/Utils/memoize.js.map +0 -1
  262. package/Utils/memoize.ts +0 -15
  263. package/WS/index.d.ts +0 -30
  264. package/WS/index.js +0 -70
  265. package/WS/index.js.map +0 -1
  266. package/WS/index.ts +0 -113
  267. package/bot.d.ts +0 -1
  268. package/bot.js +0 -28
  269. package/bot.js.map +0 -1
  270. package/bot.ts +0 -48
  271. package/esm/DiscordConfig/index.js +0 -26
  272. package/esm/DiscordConfig/index.js.map +0 -1
  273. package/esm/DiscordGateway/index.js +0 -20
  274. package/esm/DiscordGateway/index.js.map +0 -1
  275. package/esm/DiscordGateway/utils.js +0 -7
  276. package/esm/DiscordGateway/utils.js.map +0 -1
  277. package/esm/DiscordREST/http.js +0 -15
  278. package/esm/DiscordREST/http.js.map +0 -1
  279. package/esm/DiscordREST/index.js +0 -59
  280. package/esm/DiscordREST/index.js.map +0 -1
  281. package/esm/DiscordREST/types.js +0 -3
  282. package/esm/DiscordShard/commands.js +0 -28
  283. package/esm/DiscordShard/commands.js.map +0 -1
  284. package/esm/DiscordShard/heartbeats.js +0 -24
  285. package/esm/DiscordShard/heartbeats.js.map +0 -1
  286. package/esm/DiscordShard/identify.js +0 -30
  287. package/esm/DiscordShard/identify.js.map +0 -1
  288. package/esm/DiscordShard/index.js +0 -58
  289. package/esm/DiscordShard/index.js.map +0 -1
  290. package/esm/DiscordShard/invalidSession.js +0 -12
  291. package/esm/DiscordShard/invalidSession.js.map +0 -1
  292. package/esm/DiscordShard/utils.js +0 -11
  293. package/esm/DiscordShard/utils.js.map +0 -1
  294. package/esm/DiscordWS/index.js +0 -34
  295. package/esm/DiscordWS/index.js.map +0 -1
  296. package/esm/Log/index.js +0 -22
  297. package/esm/Log/index.js.map +0 -1
  298. package/esm/Utils/memoize.js +0 -12
  299. package/esm/Utils/memoize.js.map +0 -1
  300. package/esm/WS/index.js +0 -65
  301. package/esm/WS/index.js.map +0 -1
  302. package/esm/bot.js +0 -25
  303. package/esm/bot.js.map +0 -1
  304. package/esm/mod.js +0 -16
  305. package/esm/mod.js.map +0 -1
  306. package/esm/types.js.map +0 -1
  307. package/mod.d.ts +0 -7
  308. package/mod.js +0 -25
  309. package/mod.js.map +0 -1
  310. package/mod.ts +0 -19
  311. package/types.js +0 -1564
  312. package/types.js.map +0 -1
@@ -0,0 +1,139 @@
1
+ import * as Ctx from "./context.js"
2
+ import * as D from "./definitions.js"
3
+ import * as Arr from "@fp-ts/data/ReadonlyArray"
4
+ import { splitDefinitions } from "./utils.js"
5
+
6
+ export class InteractionNotFound {
7
+ readonly _tag = "InteractionNotFound"
8
+ constructor(readonly interaction: Discord.Interaction) {}
9
+ }
10
+
11
+ export const handlers = <R, E>(
12
+ definitions: D.InteractionDefinition<R, E>[],
13
+ ): Record<
14
+ Discord.InteractionType,
15
+ (i: Discord.Interaction) => Effect<R, E, Discord.InteractionResponse>
16
+ > => {
17
+ const { allCommands, autocompletes, messageComponents, modalSubmits } =
18
+ splitDefinitions(definitions)
19
+
20
+ return {
21
+ [Discord.InteractionType.PING]: () =>
22
+ Effect.succeed({
23
+ type: Discord.InteractionCallbackType.PONG,
24
+ }),
25
+
26
+ [Discord.InteractionType.APPLICATION_COMMAND]: (i) => {
27
+ const data = i.data as Discord.ApplicationCommandDatum
28
+
29
+ return pipe(
30
+ Maybe.fromNullable(allCommands[data.name]).match(
31
+ () =>
32
+ Effect.fail(new InteractionNotFound(i)) as any as Effect<
33
+ R,
34
+ E,
35
+ Discord.InteractionResponse
36
+ >,
37
+ (command) => command.handle,
38
+ ),
39
+ Effect.provideService(Ctx.InteractionContext)(i),
40
+ Effect.provideService(Ctx.ApplicationCommandContext)(data),
41
+ )
42
+ },
43
+
44
+ [Discord.InteractionType.MODAL_SUBMIT]: (i: Discord.Interaction) => {
45
+ const data = i.data as Discord.ModalSubmitDatum
46
+
47
+ return pipe(
48
+ modalSubmits,
49
+ Arr.map((a) =>
50
+ Effect.struct({
51
+ command: Effect.succeed(a),
52
+ match: a.predicate(data.custom_id),
53
+ }),
54
+ ),
55
+ (a) =>
56
+ a.collectAllPar.flatMap((a) =>
57
+ a
58
+ .findFirst((a) => a.match)
59
+ .match(
60
+ () =>
61
+ Effect.fail(new InteractionNotFound(i)) as any as Effect<
62
+ R,
63
+ E,
64
+ Discord.InteractionResponse
65
+ >,
66
+ (a) => a.command.handle,
67
+ ),
68
+ ),
69
+ Effect.provideService(Ctx.InteractionContext)(i),
70
+ Effect.provideService(Ctx.ModalSubmitContext)(data),
71
+ )
72
+ },
73
+
74
+ [Discord.InteractionType.MESSAGE_COMPONENT]: (i) => {
75
+ const data = i.data as Discord.MessageComponentDatum
76
+
77
+ return pipe(
78
+ messageComponents,
79
+ Arr.map((a) =>
80
+ Effect.struct({
81
+ command: Effect.succeed(a),
82
+ match: a.predicate(data.custom_id),
83
+ }),
84
+ ),
85
+ (a) =>
86
+ a.collectAllPar.flatMap((a) =>
87
+ a
88
+ .findFirst((a) => a.match)
89
+ .match(
90
+ () =>
91
+ Effect.fail(new InteractionNotFound(i)) as any as Effect<
92
+ R,
93
+ E,
94
+ Discord.InteractionResponse
95
+ >,
96
+ (a) => a.command.handle,
97
+ ),
98
+ ),
99
+ Effect.provideService(Ctx.InteractionContext)(i),
100
+ Effect.provideService(Ctx.MessageComponentContext)(data),
101
+ )
102
+ },
103
+
104
+ [Discord.InteractionType.APPLICATION_COMMAND_AUTOCOMPLETE]: (i) => {
105
+ const data = i.data as Discord.ApplicationCommandDatum
106
+
107
+ return IxHelpers.focusedOption(data)
108
+ .map((focusedOption) =>
109
+ pipe(
110
+ autocompletes,
111
+ Arr.map((a) =>
112
+ Effect.struct({
113
+ command: Effect.succeed(a),
114
+ match: a.predicate(focusedOption),
115
+ }),
116
+ ),
117
+ (a) =>
118
+ a.collectAllPar.flatMap((a) =>
119
+ a
120
+ .findFirst((a) => a.match)
121
+ .match(
122
+ () =>
123
+ Effect.fail(new InteractionNotFound(i)) as any as Effect<
124
+ R,
125
+ E,
126
+ Discord.InteractionResponse
127
+ >,
128
+ (a) => a.command.handle,
129
+ ),
130
+ ),
131
+ Effect.provideService(Ctx.InteractionContext)(i),
132
+ Effect.provideService(Ctx.ApplicationCommandContext)(data),
133
+ Effect.provideService(Ctx.FocusedOptionContext)({ focusedOption }),
134
+ ),
135
+ )
136
+ .getOrElse(() => Effect.fail(new InteractionNotFound(i)) as any)
137
+ },
138
+ }
139
+ }
@@ -0,0 +1,57 @@
1
+ import * as D from "./definitions.js"
2
+ import * as Gateway from "./gateway.js"
3
+ import * as Webhook from "./webhook.js"
4
+
5
+ export * from "./context.js"
6
+
7
+ export {
8
+ global,
9
+ guild,
10
+ messageComponent,
11
+ modalSubmit,
12
+ autocomplete,
13
+ InteractionDefinition,
14
+ } from "./definitions.js"
15
+
16
+ export {
17
+ makeConfig as makeWebhookConfig,
18
+ WebhookConfig,
19
+ WebhookParseError,
20
+ BadWebhookSignature,
21
+ } from "./webhook.js"
22
+
23
+ class InteractionBuilder<R, E> {
24
+ constructor(readonly definitions: D.InteractionDefinition<R, E>[]) {}
25
+
26
+ add<R1, E1>(definition: D.InteractionDefinition<R1, E1>) {
27
+ return new InteractionBuilder<R | R1, E | E1>([
28
+ ...this.definitions,
29
+ definition,
30
+ ])
31
+ }
32
+
33
+ runGateway(opts: Gateway.RunOpts = {}) {
34
+ return Gateway.run(this.definitions, opts)
35
+ }
36
+
37
+ handleWebhook(headers: Record<string, string>, rawBody: string) {
38
+ return Webhook.run(this.definitions, headers, rawBody)
39
+ }
40
+ }
41
+
42
+ export const builder = new InteractionBuilder<never, never>([])
43
+
44
+ // Filters
45
+ export const id = (query: string) => (customId: string) =>
46
+ Effect.succeed(query === customId)
47
+
48
+ export const idStartsWith = (query: string) => (customId: string) =>
49
+ Effect.succeed(customId.startsWith(query))
50
+
51
+ export const regex = (query: RegExp) => (customId: string) =>
52
+ Effect.succeed(query.test(customId))
53
+
54
+ export const option =
55
+ (name: string) =>
56
+ (focusedOption: Discord.ApplicationCommandInteractionDataOption) =>
57
+ Effect.succeed(focusedOption.name === name)
@@ -0,0 +1,47 @@
1
+ import * as D from "./definitions.js"
2
+
3
+ export const splitDefinitions = <R, E>(
4
+ definitions: D.InteractionDefinition<R, E>[],
5
+ ) => {
6
+ const globalCommands = definitions.filter(
7
+ (a): a is D.GlobalApplicationCommand<R, E> =>
8
+ a._tag === "GlobalApplicationCommand",
9
+ )
10
+
11
+ const guildCommands = definitions.filter(
12
+ (a): a is D.GuildApplicationCommand<R, E> =>
13
+ a._tag === "GuildApplicationCommand",
14
+ )
15
+
16
+ const messageComponents = definitions.filter(
17
+ (a): a is D.MessageComponent<R, E> => a._tag === "MessageComponent",
18
+ )
19
+
20
+ const modalSubmits = definitions.filter(
21
+ (a): a is D.ModalSubmit<R, E> => a._tag === "ModalSubmit",
22
+ )
23
+
24
+ const autocompletes = definitions.filter(
25
+ (a): a is D.Autocomplete<R, E> => a._tag === "Autocomplete",
26
+ )
27
+
28
+ const allCommands = [...globalCommands, ...guildCommands].reduce(
29
+ (acc, a) => ({
30
+ ...acc,
31
+ [a.command.name]: a,
32
+ }),
33
+ {} as Record<
34
+ string,
35
+ D.GlobalApplicationCommand<R, E> | D.GuildApplicationCommand<R, E>
36
+ >,
37
+ )
38
+
39
+ return {
40
+ globalCommands,
41
+ guildCommands,
42
+ messageComponents,
43
+ modalSubmits,
44
+ autocompletes,
45
+ allCommands,
46
+ }
47
+ }
@@ -0,0 +1,59 @@
1
+ import Nacl from "tweetnacl"
2
+ import * as D from "./definitions.js"
3
+ import { handlers } from "./handlers.js"
4
+
5
+ export class BadWebhookSignature {
6
+ readonly _tag = "BadWebhookSignature"
7
+ }
8
+
9
+ const checkSignature = (
10
+ publicKey: string,
11
+ headers: Record<string, string>,
12
+ body: string,
13
+ ) =>
14
+ Maybe.struct({
15
+ signature: Maybe.fromNullable(headers["x-signature-ed25519"]),
16
+ timestamp: Maybe.fromNullable(headers["x-signature-timestamp"]),
17
+ })
18
+ .filter((a) =>
19
+ Nacl.sign.detached.verify(
20
+ Buffer.from(a.timestamp + body),
21
+ Buffer.from(a.signature, "hex"),
22
+ Buffer.from(publicKey, "hex"),
23
+ ),
24
+ )
25
+ .toEither(() => new BadWebhookSignature()).asUnit
26
+
27
+ export interface WebhookConfig {
28
+ applicationId: string
29
+ publicKey: string
30
+ }
31
+ export const WebhookConfig = Tag<WebhookConfig>()
32
+ export const makeConfig = (a: WebhookConfig) => Layer.succeed(WebhookConfig)(a)
33
+
34
+ export class WebhookParseError {
35
+ readonly _tag = "WebhookParseError"
36
+ constructor(readonly reason: unknown) {}
37
+ }
38
+
39
+ const fromHeadersAndBody = (headers: Record<string, string>, body: string) =>
40
+ Do(($) => {
41
+ const { publicKey } = $(Effect.service(WebhookConfig))
42
+ $(Effect.fromEither(checkSignature(publicKey, headers, body)))
43
+ return $(
44
+ Effect.tryCatch(
45
+ () => JSON.parse(body) as Discord.Interaction,
46
+ (reason) => new WebhookParseError(reason),
47
+ ),
48
+ )
49
+ })
50
+
51
+ export const run = <R, E>(
52
+ definitions: D.InteractionDefinition<R, E>[],
53
+ headers: Record<string, string>,
54
+ body: string,
55
+ ) =>
56
+ Do(($) => {
57
+ const interaction = $(fromHeadersAndBody(headers, body))
58
+ return $(handlers(definitions)[interaction.type](interaction))
59
+ })
@@ -0,0 +1,23 @@
1
+ const make = (debug = false) => ({
2
+ info: (...args: any[]) =>
3
+ Effect.sync(() => {
4
+ console.error("INFO", ...args)
5
+ }),
6
+ debug: (...args: any[]) =>
7
+ debug
8
+ ? Effect.sync(() => {
9
+ console.error("DEBUG", ...args)
10
+ })
11
+ : Effect.unit(),
12
+ })
13
+
14
+ export interface Log extends ReturnType<typeof make> {}
15
+ export const Log = Tag<Log>()
16
+ export const LiveLog = Layer.succeed(Log)(make(false))
17
+ export const LiveLogDebug = Layer.succeed(Log)(make(true))
18
+
19
+ export const info = (...args: any[]) =>
20
+ Effect.serviceWithEffect(Log)(({ info: log }) => log(...args))
21
+
22
+ export const debug = (...args: any[]) =>
23
+ Effect.serviceWithEffect(Log)(({ debug }) => debug(...args))
@@ -0,0 +1,65 @@
1
+ import { delayFrom } from "./utils.js"
2
+ import * as Memory from "./memory.js"
3
+
4
+ export type BucketDetails = {
5
+ key: "global" | string
6
+ resetAfter: number
7
+ limit: number
8
+ }
9
+
10
+ export interface RateLimitStore {
11
+ hasBucket: (bucketKey: string) => Effect<never, never, boolean>
12
+
13
+ putBucket: (bucket: BucketDetails) => Effect<never, never, void>
14
+
15
+ getBucketForRoute: (
16
+ route: string,
17
+ ) => Effect<never, never, Maybe<BucketDetails>>
18
+
19
+ putBucketRoute: (
20
+ route: string,
21
+ bucketKey: string,
22
+ ) => Effect<never, never, void>
23
+
24
+ incrementCounter: (
25
+ key: string,
26
+ window: number,
27
+ limit: number,
28
+ ) => Effect<never, never, readonly [count: number, ttl: number]>
29
+ }
30
+
31
+ export const RateLimitStore = Tag<RateLimitStore>()
32
+ export const LiveMemoryRateLimitStore = Layer.sync(RateLimitStore)(Memory.make)
33
+
34
+ const makeLimiter = Do(($) => {
35
+ const store = $(Effect.service(RateLimitStore))
36
+ const log = $(Effect.service(Log.Log))
37
+
38
+ const maybeWait = (
39
+ key: string,
40
+ window: Duration,
41
+ limit: number,
42
+ multiplier = 1.05,
43
+ ) => {
44
+ const windowMs = window.millis * multiplier
45
+ return store
46
+ .incrementCounter(key, windowMs, limit)
47
+ .map(([count, ttl]) => delayFrom(windowMs, limit, count, ttl))
48
+ .tap((d) =>
49
+ log.debug("RateLimitStore maybeWait", {
50
+ key,
51
+ window: window.millis,
52
+ windowMs,
53
+ limit,
54
+ delay: d.millis,
55
+ }),
56
+ )
57
+ .tap(Effect.sleep).asUnit
58
+ }
59
+
60
+ return { maybeWait }
61
+ })
62
+
63
+ export interface RateLimiter extends Success<typeof makeLimiter> {}
64
+ export const RateLimiter = Tag<RateLimiter>()
65
+ export const LiveRateLimiter = Layer.fromEffect(RateLimiter)(makeLimiter)
@@ -0,0 +1,48 @@
1
+ interface Counter {
2
+ count: number
3
+ expires: number
4
+ }
5
+
6
+ export const make = (): RateLimitStore.RateLimitStore => {
7
+ const buckets = new Map<string, RateLimitStore.BucketDetails>()
8
+ const routes = new Map<string, string>()
9
+ const counters = new Map<string, Counter>()
10
+
11
+ const getCounter = (key: string) =>
12
+ Maybe.fromNullable(counters.get(key)).filter((c) => c.expires > Date.now())
13
+
14
+ return {
15
+ hasBucket: (key) => Effect.sync(() => buckets.has(key)),
16
+
17
+ putBucket: (bucket) =>
18
+ Effect.sync(() => {
19
+ buckets.set(bucket.key, bucket)
20
+ }),
21
+
22
+ getBucketForRoute: (route) =>
23
+ Effect.sync(() => Maybe.fromNullable(buckets.get(routes.get(route)!))),
24
+
25
+ putBucketRoute: (route, bucket) =>
26
+ Effect.sync(() => {
27
+ routes.set(route, bucket)
28
+ }),
29
+
30
+ incrementCounter: (key, window, limit) =>
31
+ Effect.sync(() => {
32
+ const now = Date.now()
33
+ const perRequest = Math.ceil(window / limit)
34
+ const counter = getCounter(key).getOrElse(
35
+ (): Counter => ({
36
+ expires: now,
37
+ count: 0,
38
+ }),
39
+ )
40
+
41
+ const count = counter.count + 1
42
+ const expires = counter.expires + perRequest
43
+ counters.set(key, { ...counter, count, expires })
44
+
45
+ return [count, expires - now]
46
+ }),
47
+ }
48
+ }
@@ -0,0 +1,27 @@
1
+ import { millis, zero } from "@fp-ts/data/Duration"
2
+
3
+ export const delayFrom = (
4
+ window: number,
5
+ limit: number,
6
+ count: number,
7
+ ttl: number,
8
+ ): Duration => {
9
+ const perRequest = Math.ceil(window / limit)
10
+
11
+ const totalTime = count * perRequest
12
+ const elapsedTime = totalTime - ttl
13
+ const elapsedWindows = Math.floor(elapsedTime / window)
14
+ const completedRequests = elapsedWindows * limit
15
+ const remainingRequests = count - completedRequests
16
+ const remainingWindows = Math.floor((remainingRequests - 1) / limit)
17
+ const delayRemainder = elapsedTime % window
18
+
19
+ const requestRemainder = count % limit
20
+ const staggerDelay = requestRemainder * 50
21
+
22
+ if (remainingWindows === 0) {
23
+ return zero
24
+ }
25
+
26
+ return millis(remainingWindows * window - delayRemainder + staggerDelay)
27
+ }
package/src/common.ts ADDED
@@ -0,0 +1,35 @@
1
+ export { Effect, EffectTypeId } from "@effect/io/Effect"
2
+ export type { Layer } from "@effect/io/Layer"
3
+ export type { Schedule } from "@effect/io/Schedule"
4
+ export type { Cause } from "@effect/io/Cause"
5
+ export type { Chunk } from "@fp-ts/data/Chunk"
6
+ export { Context, Tag } from "@fp-ts/data/Context"
7
+ export type { Duration } from "@fp-ts/data/Duration"
8
+ export type { Equal } from "@fp-ts/data/Equal"
9
+ export type { Option as Maybe } from "@fp-ts/data/Option"
10
+ export type { Either } from "@fp-ts/data/Either"
11
+ export type { Exit } from "@effect/io/Exit"
12
+ export type { EffectSource } from "callbag-effect-ts/Source"
13
+ export type { EffectSink } from "callbag-effect-ts/Sink"
14
+ export type { HashMap } from "@fp-ts/data/HashMap"
15
+ export type { Ref } from "@effect/io/Ref"
16
+
17
+ export * as Config from "dfx/DiscordConfig/index"
18
+ export * as Discord from "dfx/types"
19
+ export * as Http from "dfx/Http/index"
20
+ export * as Log from "dfx/Log/index"
21
+ export * as RateLimitStore from "dfx/RateLimitStore/index"
22
+ export * as Rest from "dfx/DiscordREST/index"
23
+ export * as Gateway from "dfx/DiscordGateway/index"
24
+ export * as WS from "dfx/DiscordGateway/WS/index"
25
+ export * as DWS from "dfx/DiscordGateway/DiscordWS/index"
26
+ export * as Shard from "dfx/DiscordGateway/Shard/index"
27
+ export * as ShardStore from "dfx/DiscordGateway/ShardStore/index"
28
+ export * as Ix from "dfx/Interactions/index"
29
+
30
+ export * as Flags from "./Helpers/flags.js"
31
+ export * as Intents from "./Helpers/intents.js"
32
+ export * as IxHelpers from "./Helpers/interactions.js"
33
+ export * as Members from "./Helpers/members.js"
34
+ export * as Perms from "./Helpers/permissions.js"
35
+ export * as UI from "./Helpers/ui.js"
package/src/example.ts ADDED
@@ -0,0 +1,52 @@
1
+ import { Ix, makeLayer } from "dfx"
2
+ import Dotenv from "dotenv"
3
+
4
+ Dotenv.config()
5
+
6
+ const LiveEnv = makeLayer({
7
+ token: process.env.DISCORD_BOT_TOKEN!,
8
+ })
9
+
10
+ const hello = Ix.guild(
11
+ {
12
+ name: "hello",
13
+ description: "Eh yo",
14
+ options: [
15
+ {
16
+ type: Discord.ApplicationCommandOptionType.SUB_COMMAND,
17
+ name: "one",
18
+ description: "The first sub command",
19
+ },
20
+ {
21
+ type: Discord.ApplicationCommandOptionType.SUB_COMMAND,
22
+ name: "two",
23
+ description: "The second sub command",
24
+ },
25
+ ],
26
+ },
27
+ Ix.handleSubCommands({
28
+ one: Effect.succeed({
29
+ type: 4,
30
+ data: {
31
+ content: "One",
32
+ },
33
+ }),
34
+
35
+ two: Ix.getSubCommand.map((a) => ({
36
+ type: 4,
37
+ data: {
38
+ content: a.name,
39
+ },
40
+ })),
41
+ }),
42
+ )
43
+
44
+ Ix.builder
45
+ .add(hello)
46
+ .runGateway()
47
+ .provideLayer(LiveEnv)
48
+ .unsafeRunPromiseExit.then((exit) => {
49
+ if (exit.isFailure) {
50
+ console.error(exit.cause.unsafeRunSync.pretty())
51
+ }
52
+ })
package/src/global.ts ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @tsplus global
3
+ */
4
+ import type {
5
+ Effect,
6
+ EffectTypeId,
7
+ Layer,
8
+ Either,
9
+ Maybe,
10
+ Tag,
11
+ Context,
12
+ Cause,
13
+ Chunk,
14
+ Duration,
15
+ Equal,
16
+ Exit,
17
+ HashMap,
18
+ Schedule,
19
+ EffectSource,
20
+ EffectSink,
21
+ Ref,
22
+ Config,
23
+ Discord,
24
+ Http,
25
+ Log,
26
+ RateLimitStore,
27
+ Rest,
28
+ Gateway,
29
+ WS,
30
+ DWS,
31
+ Shard,
32
+ ShardStore,
33
+ Ix,
34
+ Flags,
35
+ Intents,
36
+ IxHelpers,
37
+ Members,
38
+ Perms,
39
+ UI,
40
+ } from "dfx/common"
41
+
42
+ /**
43
+ * @tsplus global
44
+ */
45
+ import type { Success } from "dfx/utils/effect"
46
+
47
+ /**
48
+ * @tsplus global
49
+ */
50
+ import { pipe, flow, identity } from "@fp-ts/data/Function"
package/src/index.ts ADDED
@@ -0,0 +1,45 @@
1
+ export * as Config from "./DiscordConfig/index.js"
2
+ export * as DiscordWS from "./DiscordGateway/DiscordWS/index.js"
3
+ export * as Gateway from "./DiscordGateway/index.js"
4
+ export { DiscordREST, LiveDiscordREST, rest } from "./DiscordREST/index.js"
5
+ export * as Ix from "./Interactions/index.js"
6
+ export * as Log from "./Log/index.js"
7
+ export * as RateLimitStore from "./RateLimitStore/index.js"
8
+
9
+ export * as Flags from "./Helpers/flags.js"
10
+ export * as Intents from "./Helpers/intents.js"
11
+ export * as IxHelpers from "./Helpers/interactions.js"
12
+ export * as Members from "./Helpers/members.js"
13
+ export * as Perms from "./Helpers/permissions.js"
14
+ export * as UI from "./Helpers/ui.js"
15
+
16
+ export const LiveRateLimit =
17
+ RateLimitStore.LiveMemoryRateLimitStore > RateLimitStore.LiveRateLimiter
18
+
19
+ export const LiveREST = LiveRateLimit > Rest.LiveDiscordREST
20
+
21
+ export const LiveGateway =
22
+ ShardStore.LiveMemoryShardStore + DWS.LiveJsonDiscordWSCodec >
23
+ Gateway.LiveDiscordGateway
24
+
25
+ export const LiveBot = LiveREST > LiveGateway
26
+
27
+ export const makeLayer = (config: Config.MakeOpts, debug = false) => {
28
+ const LiveLog = debug ? Log.LiveLogDebug : Log.LiveLog
29
+ const LiveConfig = Config.makeLayer(config)
30
+ const LiveEnv = LiveLog + LiveConfig > LiveBot
31
+
32
+ return LiveEnv
33
+ }
34
+
35
+ export const makeWebhookLayer = (
36
+ config: Config.MakeOpts & Ix.WebhookConfig,
37
+ debug = false,
38
+ ) => {
39
+ const LiveWebhook = Ix.makeWebhookConfig(config)
40
+ const LiveLog = debug ? Log.LiveLogDebug : Log.LiveLog
41
+ const LiveConfig = Config.makeLayer(config)
42
+ const LiveEnv = LiveLog + LiveConfig + LiveWebhook > LiveREST
43
+
44
+ return LiveEnv
45
+ }
package/src/json.d.ts ADDED
@@ -0,0 +1 @@
1
+ declare module "*.json"