dfx 0.77.3 → 0.78.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 (132) hide show
  1. package/Cache/prelude.d.ts +3 -3
  2. package/DiscordConfig.d.ts +5 -7
  3. package/DiscordConfig.d.ts.map +1 -1
  4. package/DiscordConfig.js +1 -3
  5. package/DiscordConfig.js.map +1 -1
  6. package/DiscordGateway/DiscordWS.d.ts +12 -11
  7. package/DiscordGateway/DiscordWS.d.ts.map +1 -1
  8. package/DiscordGateway/DiscordWS.js +8 -5
  9. package/DiscordGateway/DiscordWS.js.map +1 -1
  10. package/DiscordGateway/Messaging.d.ts +28 -0
  11. package/DiscordGateway/Messaging.d.ts.map +1 -0
  12. package/DiscordGateway/Messaging.js +41 -0
  13. package/DiscordGateway/Messaging.js.map +1 -0
  14. package/DiscordGateway/Shard.d.ts +14 -11
  15. package/DiscordGateway/Shard.d.ts.map +1 -1
  16. package/DiscordGateway/Shard.js +20 -17
  17. package/DiscordGateway/Shard.js.map +1 -1
  18. package/DiscordGateway/ShardStore.d.ts +5 -2
  19. package/DiscordGateway/ShardStore.d.ts.map +1 -1
  20. package/DiscordGateway/ShardStore.js +1 -1
  21. package/DiscordGateway/ShardStore.js.map +1 -1
  22. package/DiscordGateway/Sharder.d.ts +9 -18
  23. package/DiscordGateway/Sharder.d.ts.map +1 -1
  24. package/DiscordGateway/Sharder.js +36 -45
  25. package/DiscordGateway/Sharder.js.map +1 -1
  26. package/DiscordGateway/WS.d.ts +14 -10
  27. package/DiscordGateway/WS.d.ts.map +1 -1
  28. package/DiscordGateway/WS.js +31 -21
  29. package/DiscordGateway/WS.js.map +1 -1
  30. package/DiscordGateway.d.ts +10 -7
  31. package/DiscordGateway.d.ts.map +1 -1
  32. package/DiscordGateway.js +13 -31
  33. package/DiscordGateway.js.map +1 -1
  34. package/DiscordREST.d.ts +6 -4
  35. package/DiscordREST.d.ts.map +1 -1
  36. package/DiscordREST.js +7 -6
  37. package/DiscordREST.js.map +1 -1
  38. package/Interactions/context.d.ts +35 -17
  39. package/Interactions/context.d.ts.map +1 -1
  40. package/Interactions/context.js +6 -6
  41. package/Interactions/context.js.map +1 -1
  42. package/Interactions/definitions.d.ts +11 -11
  43. package/Interactions/definitions.d.ts.map +1 -1
  44. package/Interactions/definitions.js.map +1 -1
  45. package/Interactions/gateway.d.ts +7 -6
  46. package/Interactions/gateway.d.ts.map +1 -1
  47. package/Interactions/gateway.js +1 -1
  48. package/Interactions/gateway.js.map +1 -1
  49. package/Interactions/handlers.d.ts +2 -1
  50. package/Interactions/handlers.d.ts.map +1 -1
  51. package/Interactions/webhook.d.ts +5 -6
  52. package/Interactions/webhook.d.ts.map +1 -1
  53. package/Interactions/webhook.js +1 -1
  54. package/Interactions/webhook.js.map +1 -1
  55. package/RateLimit/memory.d.ts +2 -2
  56. package/RateLimit/memory.d.ts.map +1 -1
  57. package/RateLimit/memory.js.map +1 -1
  58. package/RateLimit.d.ts +10 -9
  59. package/RateLimit.d.ts.map +1 -1
  60. package/RateLimit.js +4 -5
  61. package/RateLimit.js.map +1 -1
  62. package/gateway.d.ts +2 -2
  63. package/gateway.d.ts.map +1 -1
  64. package/gateway.js +1 -2
  65. package/gateway.js.map +1 -1
  66. package/index.d.ts +1 -2
  67. package/index.d.ts.map +1 -1
  68. package/index.js +1 -3
  69. package/index.js.map +1 -1
  70. package/mjs/DiscordConfig.mjs +1 -3
  71. package/mjs/DiscordConfig.mjs.map +1 -1
  72. package/mjs/DiscordGateway/DiscordWS.mjs +8 -5
  73. package/mjs/DiscordGateway/DiscordWS.mjs.map +1 -1
  74. package/mjs/DiscordGateway/Messaging.mjs +33 -0
  75. package/mjs/DiscordGateway/Messaging.mjs.map +1 -0
  76. package/mjs/DiscordGateway/Shard.mjs +20 -17
  77. package/mjs/DiscordGateway/Shard.mjs.map +1 -1
  78. package/mjs/DiscordGateway/ShardStore.mjs +1 -1
  79. package/mjs/DiscordGateway/ShardStore.mjs.map +1 -1
  80. package/mjs/DiscordGateway/Sharder.mjs +35 -44
  81. package/mjs/DiscordGateway/Sharder.mjs.map +1 -1
  82. package/mjs/DiscordGateway/WS.mjs +32 -22
  83. package/mjs/DiscordGateway/WS.mjs.map +1 -1
  84. package/mjs/DiscordGateway.mjs +12 -30
  85. package/mjs/DiscordGateway.mjs.map +1 -1
  86. package/mjs/DiscordREST.mjs +7 -6
  87. package/mjs/DiscordREST.mjs.map +1 -1
  88. package/mjs/Interactions/context.mjs +6 -6
  89. package/mjs/Interactions/context.mjs.map +1 -1
  90. package/mjs/Interactions/definitions.mjs.map +1 -1
  91. package/mjs/Interactions/gateway.mjs +1 -1
  92. package/mjs/Interactions/gateway.mjs.map +1 -1
  93. package/mjs/Interactions/webhook.mjs +1 -1
  94. package/mjs/Interactions/webhook.mjs.map +1 -1
  95. package/mjs/RateLimit/memory.mjs.map +1 -1
  96. package/mjs/RateLimit.mjs +4 -5
  97. package/mjs/RateLimit.mjs.map +1 -1
  98. package/mjs/gateway.mjs +1 -2
  99. package/mjs/gateway.mjs.map +1 -1
  100. package/mjs/index.mjs +1 -2
  101. package/mjs/index.mjs.map +1 -1
  102. package/mjs/version.mjs +1 -1
  103. package/mjs/webhooks.mjs +1 -2
  104. package/mjs/webhooks.mjs.map +1 -1
  105. package/package.json +2 -2
  106. package/src/DiscordConfig.ts +7 -9
  107. package/src/DiscordGateway/DiscordWS.ts +23 -13
  108. package/src/DiscordGateway/Messaging.ts +72 -0
  109. package/src/DiscordGateway/Shard.ts +51 -33
  110. package/src/DiscordGateway/ShardStore.ts +8 -3
  111. package/src/DiscordGateway/Sharder.ts +72 -97
  112. package/src/DiscordGateway/WS.ts +64 -32
  113. package/src/DiscordGateway.ts +22 -71
  114. package/src/DiscordREST.ts +40 -27
  115. package/src/Interactions/context.ts +47 -10
  116. package/src/Interactions/definitions.ts +22 -20
  117. package/src/Interactions/gateway.ts +14 -6
  118. package/src/Interactions/handlers.ts +1 -1
  119. package/src/Interactions/webhook.ts +18 -4
  120. package/src/RateLimit/memory.ts +2 -2
  121. package/src/RateLimit.ts +17 -8
  122. package/src/gateway.ts +0 -2
  123. package/src/index.ts +0 -2
  124. package/src/version.ts +1 -1
  125. package/src/webhooks.ts +1 -2
  126. package/version.d.ts +1 -1
  127. package/version.js +1 -1
  128. package/webhooks.d.ts +1 -2
  129. package/webhooks.d.ts.map +1 -1
  130. package/webhooks.js +1 -2
  131. package/webhooks.js.map +1 -1
  132. package/src/Log.ts +0 -24
@@ -1,12 +1,13 @@
1
1
  import { Tag } from "effect/Context"
2
- import * as Duration from "effect/Duration"
3
- import { pipe } from "effect/Function"
2
+ import type * as Duration from "effect/Duration"
3
+ import { identity, pipe } from "effect/Function"
4
4
  import * as Effect from "effect/Effect"
5
5
  import * as Layer from "effect/Layer"
6
6
  import * as Queue from "effect/Queue"
7
7
  import * as Ref from "effect/Ref"
8
- import { Log } from "dfx/Log"
9
8
  import WebSocket from "isomorphic-ws"
9
+ import type { Predicate } from "effect/Predicate"
10
+ import * as Schedule from "effect/Schedule"
10
11
 
11
12
  export const Reconnect = Symbol()
12
13
  export type Reconnect = typeof Reconnect
@@ -49,16 +50,10 @@ const socket = (urlRef: Ref.Ref<string>) =>
49
50
  const offer = (
50
51
  ws: globalThis.WebSocket,
51
52
  queue: Queue.Enqueue<WebSocket.Data>,
52
- log: Log,
53
53
  ) =>
54
54
  Effect.async<never, WebSocketError | WebSocketCloseError, never>(resume => {
55
55
  ws.addEventListener("message", message => {
56
- Effect.runFork(
57
- Effect.zipRight(
58
- log.debug("WS", "receive", message.data),
59
- Queue.offer(queue, message.data),
60
- ),
61
- )
56
+ Queue.unsafeOffer(queue, message.data)
62
57
  })
63
58
 
64
59
  ws.addEventListener("error", cause => {
@@ -70,7 +65,10 @@ const offer = (
70
65
  })
71
66
  })
72
67
 
73
- const waitForOpen = (ws: globalThis.WebSocket, timeout: Duration.Duration) =>
68
+ const waitForOpen = (
69
+ ws: globalThis.WebSocket,
70
+ timeout: Duration.DurationInput,
71
+ ) =>
74
72
  Effect.timeoutFail(
75
73
  Effect.suspend(() => {
76
74
  if (ws.readyState === WebSocket.OPEN) {
@@ -92,11 +90,10 @@ const waitForOpen = (ws: globalThis.WebSocket, timeout: Duration.Duration) =>
92
90
  const send = (
93
91
  ws: globalThis.WebSocket,
94
92
  take: Effect.Effect<never, never, Message>,
95
- log: Log,
96
93
  ) =>
97
94
  pipe(
98
95
  take,
99
- Effect.tap(data => log.debug("WS", "send", data)),
96
+ Effect.tap(data => Effect.logTrace(data)),
100
97
  Effect.tap(data => {
101
98
  if (data === Reconnect) {
102
99
  return Effect.failSync(() => {
@@ -110,30 +107,50 @@ const send = (
110
107
  })
111
108
  }),
112
109
  Effect.forever,
110
+ Effect.annotateLogs("method", "send"),
113
111
  )
114
112
 
115
- const make = Effect.gen(function* (_) {
116
- const log = yield* _(Log)
117
-
118
- const connect = (
119
- url: Ref.Ref<string>,
120
- takeOutbound: Effect.Effect<never, never, Message>,
113
+ const wsImpl = {
114
+ connect: ({
121
115
  onConnecting = Effect.unit,
122
- openTimeout = Duration.seconds(3),
123
- ) =>
116
+ openTimeout = "3 seconds",
117
+ reconnectWhen,
118
+ takeOutbound,
119
+ urlRef,
120
+ }: {
121
+ readonly urlRef: Ref.Ref<string>
122
+ readonly takeOutbound: Effect.Effect<never, never, Message>
123
+ readonly onConnecting?: Effect.Effect<never, never, void>
124
+ readonly openTimeout?: Duration.DurationInput
125
+ readonly reconnectWhen?: Predicate<WebSocketError | WebSocketCloseError>
126
+ }) =>
124
127
  Effect.gen(function* (_) {
125
- const queue = yield* _(Queue.unbounded<WebSocket.Data>())
128
+ const scope = yield* _(Effect.scope)
129
+ const queue = yield* _(
130
+ Effect.acquireRelease(
131
+ Queue.unbounded<WebSocket.Data>(),
132
+ Queue.shutdown,
133
+ ),
134
+ )
135
+ const take = Effect.annotateLogs(
136
+ Effect.tap(Queue.take(queue), data => Effect.logTrace(data)),
137
+ {
138
+ package: "dfx",
139
+ module: "DiscordGateway/WS",
140
+ method: "take",
141
+ },
142
+ )
126
143
 
127
144
  const run = pipe(
128
145
  onConnecting,
129
- Effect.zipRight(socket(url)),
146
+ Effect.zipRight(socket(urlRef)),
130
147
  Effect.flatMap(ws =>
131
148
  Effect.all(
132
149
  [
133
- offer(ws, queue, log),
150
+ offer(ws, queue),
134
151
  Effect.zipRight(
135
152
  waitForOpen(ws, openTimeout),
136
- send(ws, takeOutbound, log),
153
+ send(ws, takeOutbound),
137
154
  ),
138
155
  ],
139
156
  { concurrency: "unbounded", discard: true },
@@ -141,14 +158,29 @@ const make = Effect.gen(function* (_) {
141
158
  ),
142
159
  Effect.scoped,
143
160
  Effect.retryWhile(isReconnect),
161
+ reconnectWhen ? Effect.retryWhile(reconnectWhen) : identity,
162
+ Effect.catchAllCause(Effect.logError),
163
+ Effect.repeat(
164
+ Schedule.exponential("500 millis").pipe(
165
+ Schedule.union(Schedule.spaced("30 seconds")),
166
+ ),
167
+ ),
168
+ Effect.forkIn(scope),
144
169
  )
145
170
 
146
- return { run, take: Queue.take(queue) } as const
147
- })
171
+ yield* _(run)
148
172
 
149
- return { connect } as const
150
- })
173
+ return { take } as const
174
+ }).pipe(
175
+ Effect.annotateLogs({
176
+ package: "dfx",
177
+ module: "DiscordGateway/WS",
178
+ }),
179
+ ),
180
+ } as const
151
181
 
152
- export interface WS extends Effect.Effect.Success<typeof make> {}
153
- export const WS = Tag<WS>()
154
- export const WSLive = Layer.effect(WS, make)
182
+ export interface WS {
183
+ readonly _: unique symbol
184
+ }
185
+ export const WS = Tag<WS, typeof wsImpl>("dfx/DiscordGateway/WS")
186
+ export const WSLive = Layer.succeed(WS, wsImpl)
@@ -1,42 +1,19 @@
1
+ import { Messaging, MesssagingLive } from "dfx/DiscordGateway/Messaging"
2
+ import type { RunningShard } from "dfx/DiscordGateway/Shard"
3
+ import { Sharder, SharderLive } from "dfx/DiscordGateway/Sharder"
4
+ import type * as Discord from "dfx/types"
1
5
  import { Tag } from "effect/Context"
2
- import type * as HashSet from "effect/HashSet"
3
6
  import * as Effect from "effect/Effect"
4
- import * as PubSub from "effect/PubSub"
7
+ import type * as HashSet from "effect/HashSet"
5
8
  import * as Layer from "effect/Layer"
6
- import * as Queue from "effect/Queue"
7
- import * as Stream from "effect/Stream"
8
- import type { RunningShard } from "dfx/DiscordGateway/Shard"
9
- import { SharedLive, Sharder } from "dfx/DiscordGateway/Sharder"
10
- import type * as Discord from "dfx/types"
11
- import * as EffectUtils from "dfx/utils/Effect"
12
- import * as Schedule from "effect/Schedule"
13
-
14
- const fromDispatchFactory =
15
- <R, E>(
16
- source: Stream.Stream<R, E, Discord.GatewayPayload<Discord.ReceiveEvent>>,
17
- ) =>
18
- <K extends keyof Discord.ReceiveEvents>(
19
- event: K,
20
- ): Stream.Stream<R, E, Discord.ReceiveEvents[K]> =>
21
- Stream.map(
22
- Stream.filter(source, p => p.t === event),
23
- p => p.d! as any,
24
- )
9
+ import type * as Stream from "effect/Stream"
25
10
 
26
- const handleDispatchFactory =
27
- (hub: PubSub.PubSub<Discord.GatewayPayload<Discord.ReceiveEvent>>) =>
28
- <K extends keyof Discord.ReceiveEvents, R, E, A>(
29
- event: K,
30
- handle: (event: Discord.ReceiveEvents[K]) => Effect.Effect<R, E, A>,
31
- ): Effect.Effect<R, E, never> =>
32
- EffectUtils.subscribeForEachPar(hub, _ => {
33
- if (_.t === event) {
34
- return handle(_.d as any)
35
- }
36
- return Effect.unit as any
37
- })
11
+ export const TypeId = Symbol.for("dfx/DiscordGateway")
12
+ export type TypeId = typeof TypeId
38
13
 
39
14
  export interface DiscordGateway {
15
+ readonly [TypeId]: TypeId
16
+
40
17
  readonly dispatch: Stream.Stream<
41
18
  never,
42
19
  never,
@@ -54,50 +31,24 @@ export interface DiscordGateway {
54
31
  ) => Effect.Effect<never, never, boolean>
55
32
  readonly shards: Effect.Effect<never, never, HashSet.HashSet<RunningShard>>
56
33
  }
57
- export const DiscordGateway = Tag<DiscordGateway>()
34
+
35
+ export const DiscordGateway = Tag<DiscordGateway>(TypeId)
58
36
 
59
37
  export const make = Effect.gen(function* (_) {
60
38
  const sharder = yield* _(Sharder)
61
- const hub = yield* _(
62
- PubSub.unbounded<Discord.GatewayPayload<Discord.ReceiveEvent>>(),
63
- )
64
-
65
- const sendQueue = yield* _(
66
- Queue.unbounded<Discord.GatewayPayload<Discord.SendEvent>>(),
67
- )
68
- const send = (payload: Discord.GatewayPayload<Discord.SendEvent>) =>
69
- sendQueue.offer(payload)
70
-
71
- const dispatch = Stream.fromPubSub(hub)
72
- const fromDispatch = fromDispatchFactory(dispatch)
73
- const handleDispatch = handleDispatchFactory(hub)
74
-
75
- yield* _(
76
- sharder.run(hub, sendQueue),
77
- Effect.tapErrorCause(_ => Effect.logError("fatal error, restarting", _)),
78
- Effect.retry(
79
- Schedule.exponential("1 seconds").pipe(
80
- Schedule.union(Schedule.spaced("30 seconds")),
81
- ),
82
- ),
83
- Effect.forkScoped,
84
- )
39
+ const messaging = yield* _(Messaging)
85
40
 
86
41
  return DiscordGateway.of({
87
- dispatch,
88
- fromDispatch,
89
- handleDispatch,
90
- send,
42
+ [TypeId]: TypeId,
43
+ dispatch: messaging.dispatch,
44
+ fromDispatch: messaging.fromDispatch,
45
+ handleDispatch: messaging.handleDispatch,
46
+ send: messaging.send,
91
47
  shards: sharder.shards,
92
48
  })
93
- }).pipe(
94
- Effect.annotateLogs({
95
- package: "dfx",
96
- service: "DiscordGateway",
97
- }),
98
- )
49
+ })
99
50
 
100
- export const DiscordGatewayLive = Layer.provide(
101
- Layer.scoped(DiscordGateway, make),
102
- SharedLive,
51
+ export const DiscordGatewayLive = Layer.effect(DiscordGateway, make).pipe(
52
+ Layer.provide(MesssagingLive),
53
+ Layer.provide(SharderLive),
103
54
  )
@@ -16,7 +16,6 @@ import {
16
16
  retryAfter,
17
17
  routeFromConfig,
18
18
  } from "dfx/DiscordREST/utils"
19
- import { Log } from "dfx/Log"
20
19
  import { RateLimiterLive, RateLimiter, RateLimitStore } from "dfx/RateLimit"
21
20
  import * as Discord from "dfx/types"
22
21
  import { LIB_VERSION } from "dfx/version"
@@ -33,7 +32,6 @@ const make = Effect.gen(function* (_) {
33
32
  const { rest, token } = yield* _(DiscordConfig)
34
33
 
35
34
  const http = yield* _(Http.client.Client)
36
- const log = yield* _(Log)
37
35
  const store = yield* _(RateLimitStore)
38
36
  const { maybeWait } = yield* _(RateLimiter)
39
37
 
@@ -47,14 +45,13 @@ const make = Effect.gen(function* (_) {
47
45
  const badRoutesRef = yield* _(Ref.make(HashSet.empty<string>()))
48
46
  const tenMinutes = Duration.toMillis(Duration.minutes(10))
49
47
  const addBadRoute = (route: string) =>
50
- log
51
- .info("DiscordREST", "addBadRoute", route)
52
- .pipe(
53
- Effect.zipRight(Ref.update(badRoutesRef, HashSet.add(route))),
54
- Effect.zipRight(
55
- store.incrementCounter("dfx.rest.invalid", tenMinutes, 10000),
56
- ),
57
- )
48
+ Effect.logDebug("bad route").pipe(
49
+ Effect.zipRight(Ref.update(badRoutesRef, HashSet.add(route))),
50
+ Effect.zipRight(
51
+ store.incrementCounter("dfx.rest.invalid", tenMinutes, 10000),
52
+ ),
53
+ Effect.annotateLogs("route", route),
54
+ )
58
55
  const isBadRoute = (route: string) =>
59
56
  Effect.map(Ref.get(badRoutesRef), HashSet.has(route))
60
57
  const removeBadRoute = (route: string) =>
@@ -181,7 +178,11 @@ const make = Effect.gen(function* (_) {
181
178
  return Effect.zipRight(
182
179
  Effect.all(
183
180
  [
184
- log.info("DiscordREST", "403", request.url),
181
+ Effect.annotateLogs(
182
+ Effect.logDebug("403"),
183
+ "url",
184
+ request.url,
185
+ ),
185
186
  addBadRoute(routeFromConfig(request.url, request.method)),
186
187
  updateBuckets(request, response),
187
188
  ],
@@ -191,26 +192,32 @@ const make = Effect.gen(function* (_) {
191
192
  )
192
193
 
193
194
  case 429:
194
- return log
195
- .info("DiscordREST", "429", request.url)
196
- .pipe(
197
- Effect.zipRight(
198
- addBadRoute(routeFromConfig(request.url, request.method)),
199
- ),
200
- Effect.zipRight(updateBuckets(request, response)),
201
- Effect.zipRight(
202
- Effect.sleep(
203
- Option.getOrElse(retryAfter(response.headers), () =>
204
- Duration.seconds(5),
205
- ),
195
+ return Effect.annotateLogs(
196
+ Effect.logDebug("429"),
197
+ "url",
198
+ request.url,
199
+ ).pipe(
200
+ Effect.zipRight(
201
+ addBadRoute(routeFromConfig(request.url, request.method)),
202
+ ),
203
+ Effect.zipRight(updateBuckets(request, response)),
204
+ Effect.zipRight(
205
+ Effect.sleep(
206
+ Option.getOrElse(retryAfter(response.headers), () =>
207
+ Duration.seconds(5),
206
208
  ),
207
209
  ),
208
- Effect.zipRight(executor<A>(request)),
209
- )
210
+ ),
211
+ Effect.zipRight(executor<A>(request)),
212
+ )
210
213
  }
211
214
 
212
215
  return Effect.fail(e)
213
216
  }),
217
+ Effect.annotateLogs({
218
+ package: "dfx",
219
+ module: "DiscordREST",
220
+ }),
214
221
  )
215
222
 
216
223
  const routes = Discord.createRoutes<Partial<Http.request.Options.NoUrl>>(
@@ -246,14 +253,20 @@ const make = Effect.gen(function* (_) {
246
253
  }
247
254
  })
248
255
 
249
- export interface DiscordREST
256
+ export interface DiscordREST {
257
+ readonly _: unique symbol
258
+ }
259
+
260
+ export interface DiscordRESTService
250
261
  extends Discord.Endpoints<Partial<Http.request.Options.NoUrl>> {
251
262
  readonly executor: <A = unknown>(
252
263
  request: Http.request.ClientRequest,
253
264
  ) => Effect.Effect<never, DiscordRESTError, ResponseWithData<A>>
254
265
  }
255
266
 
256
- export const DiscordREST = Tag<DiscordREST>()
267
+ export const DiscordREST = Tag<DiscordREST, DiscordRESTService>(
268
+ "dfx/DiscordREST",
269
+ )
257
270
  export const DiscordRESTLive = Layer.effect(DiscordREST, make).pipe(
258
271
  Layer.provide(RateLimiterLive),
259
272
  Layer.provide(Http.client.layer),
@@ -6,20 +6,57 @@ import * as Effect from "effect/Effect"
6
6
  import * as IxHelpers from "dfx/Helpers/interactions"
7
7
  import type * as Discord from "dfx/types"
8
8
 
9
- export const Interaction = Tag<Discord.Interaction>()
10
- export const ApplicationCommand = Tag<Discord.ApplicationCommandDatum>()
11
- export const MessageComponentData = Tag<Discord.MessageComponentDatum>()
12
- export const ModalSubmitData = Tag<Discord.ModalSubmitDatum>()
9
+ export interface DiscordInteraction {
10
+ readonly _: unique symbol
11
+ }
12
+ export const Interaction = Tag<DiscordInteraction, Discord.Interaction>(
13
+ "dfx/Interactions/Interaction",
14
+ )
15
+
16
+ export interface DiscordApplicationCommand {
17
+ readonly _: unique symbol
18
+ }
19
+ export const ApplicationCommand = Tag<
20
+ DiscordApplicationCommand,
21
+ Discord.ApplicationCommandDatum
22
+ >("dfx/Interactions/ApplicationCommand")
23
+
24
+ export interface DiscordMessageComponent {
25
+ readonly _: unique symbol
26
+ }
27
+ export const MessageComponentData = Tag<
28
+ DiscordMessageComponent,
29
+ Discord.MessageComponentDatum
30
+ >("dfx/Interactions/MessageComponentData")
13
31
 
32
+ export interface DiscordModalSubmit {
33
+ readonly _: unique symbol
34
+ }
35
+ export const ModalSubmitData = Tag<
36
+ DiscordModalSubmit,
37
+ Discord.ModalSubmitDatum
38
+ >("dfx/Interactions/ModalSubmitData")
39
+
40
+ export interface DiscordFocusedOption {
41
+ readonly _: unique symbol
42
+ }
14
43
  export interface FocusedOptionContext {
15
44
  readonly focusedOption: Discord.ApplicationCommandInteractionDataOption
16
45
  }
17
- export const FocusedOptionContext = Tag<FocusedOptionContext>()
46
+ export const FocusedOptionContext = Tag<
47
+ DiscordFocusedOption,
48
+ FocusedOptionContext
49
+ >("dfx/Interactions/FocusedOptionContext")
18
50
 
51
+ export interface DiscordSubCommand {
52
+ readonly _: unique symbol
53
+ }
19
54
  export interface SubCommandContext {
20
55
  readonly command: Discord.ApplicationCommandInteractionDataOption
21
56
  }
22
- export const SubCommandContext = Tag<SubCommandContext>()
57
+ export const SubCommandContext = Tag<DiscordSubCommand, SubCommandContext>(
58
+ "dfx/Interactions/SubCommandContext",
59
+ )
23
60
 
24
61
  export class ResolvedDataNotFound {
25
62
  readonly _tag = "ResolvedDataNotFound"
@@ -31,7 +68,7 @@ export class ResolvedDataNotFound {
31
68
 
32
69
  export const resolvedValues = <A>(
33
70
  f: (id: Discord.Snowflake, data: Discord.ResolvedDatum) => A | undefined,
34
- ): Effect.Effect<Discord.Interaction, ResolvedDataNotFound, ReadonlyArray<A>> =>
71
+ ): Effect.Effect<DiscordInteraction, ResolvedDataNotFound, ReadonlyArray<A>> =>
35
72
  Effect.flatMap(Interaction, ix =>
36
73
  Effect.mapError(
37
74
  IxHelpers.resolveValues(f)(ix),
@@ -42,7 +79,7 @@ export const resolvedValues = <A>(
42
79
  export const resolved = <A>(
43
80
  name: string,
44
81
  f: (id: Discord.Snowflake, data: Discord.ResolvedDatum) => A | undefined,
45
- ): Effect.Effect<Discord.Interaction, ResolvedDataNotFound, A> =>
82
+ ): Effect.Effect<DiscordInteraction, ResolvedDataNotFound, A> =>
46
83
  Effect.flatMap(Interaction, ix =>
47
84
  Effect.mapError(
48
85
  IxHelpers.resolveOptionValue(name, f)(ix),
@@ -101,13 +138,13 @@ export const handleSubCommands = <
101
138
  )
102
139
 
103
140
  export const currentSubCommand: Effect.Effect<
104
- SubCommandContext,
141
+ DiscordSubCommand,
105
142
  never,
106
143
  Discord.ApplicationCommandInteractionDataOption
107
144
  > = Effect.map(SubCommandContext, _ => _.command)
108
145
 
109
146
  export const optionsMap: Effect.Effect<
110
- Discord.ApplicationCommandDatum,
147
+ DiscordApplicationCommand,
111
148
  never,
112
149
  HashMap.HashMap<string, string | undefined>
113
150
  > = Effect.map(ApplicationCommand, IxHelpers.optionsMap)
@@ -1,7 +1,11 @@
1
1
  import type * as Option from "effect/Option"
2
2
  import type * as Effect from "effect/Effect"
3
3
  import type {
4
- FocusedOptionContext,
4
+ DiscordApplicationCommand,
5
+ DiscordFocusedOption,
6
+ DiscordInteraction,
7
+ DiscordMessageComponent,
8
+ DiscordModalSubmit,
5
9
  ResolvedDataNotFound,
6
10
  SubCommandContext,
7
11
  } from "dfx/Interactions/context"
@@ -32,7 +36,7 @@ export const global = <
32
36
  handle: CommandHandler<R, E, A>,
33
37
  ) =>
34
38
  new GlobalApplicationCommand<
35
- Exclude<R, Discord.Interaction | Discord.ApplicationCommandDatum>,
39
+ Exclude<R, DiscordInteraction | DiscordApplicationCommand>,
36
40
  E
37
41
  >(command as any, handle as any)
38
42
 
@@ -54,7 +58,7 @@ export const guild = <
54
58
  handle: CommandHandler<R, E, A>,
55
59
  ) =>
56
60
  new GuildApplicationCommand<
57
- Exclude<R, Discord.Interaction | Discord.ApplicationCommandDatum>,
61
+ Exclude<R, DiscordInteraction | DiscordApplicationCommand>,
58
62
  E
59
63
  >(command as any, handle as any)
60
64
 
@@ -71,7 +75,7 @@ export const messageComponent = <R1, R2, E1, E2>(
71
75
  handle: CommandHandler<R2, E2, Discord.InteractionResponse>,
72
76
  ) =>
73
77
  new MessageComponent<
74
- Exclude<R1 | R2, Discord.Interaction | Discord.MessageComponentDatum>,
78
+ Exclude<R1 | R2, DiscordInteraction | DiscordMessageComponent>,
75
79
  E1 | E2
76
80
  >(pred as any, handle as any)
77
81
 
@@ -88,7 +92,7 @@ export const modalSubmit = <R1, R2, E1, E2>(
88
92
  handle: Effect.Effect<R2, E2, Discord.InteractionResponse>,
89
93
  ) =>
90
94
  new ModalSubmit<
91
- Exclude<R1 | R2, Discord.Interaction | Discord.ModalSubmitDatum>,
95
+ Exclude<R1 | R2, DiscordInteraction | DiscordModalSubmit>,
92
96
  E1 | E2
93
97
  >(pred as any, handle as any)
94
98
 
@@ -113,9 +117,7 @@ export const autocomplete = <R1, R2, E1, E2>(
113
117
  new Autocomplete<
114
118
  Exclude<
115
119
  R1 | R2,
116
- | Discord.Interaction
117
- | Discord.ApplicationCommandDatum
118
- | FocusedOptionContext
120
+ DiscordInteraction | DiscordApplicationCommand | DiscordFocusedOption
119
121
  >,
120
122
  E1 | E2
121
123
  >(pred as any, handle as any)
@@ -124,10 +126,10 @@ export const autocomplete = <R1, R2, E1, E2>(
124
126
  type DeepReadonly<T> = T extends Array<infer R>
125
127
  ? ReadonlyArray<DeepReadonly<R>>
126
128
  : T extends Function
127
- ? T
128
- : T extends object
129
- ? DeepReadonlyObject<T>
130
- : T
129
+ ? T
130
+ : T extends object
131
+ ? DeepReadonlyObject<T>
132
+ : T
131
133
  type DeepReadonlyObject<T> = {
132
134
  readonly [P in keyof T]: DeepReadonly<T[P]>
133
135
  }
@@ -140,24 +142,24 @@ export interface CommandHelper<A> {
140
142
  resolve: <T>(
141
143
  name: AllResolvables<A>["name"],
142
144
  f: (id: Discord.Snowflake, data: Discord.ResolvedDatum) => T | undefined,
143
- ) => Effect.Effect<Discord.Interaction, ResolvedDataNotFound, T>
145
+ ) => Effect.Effect<DiscordInteraction, ResolvedDataNotFound, T>
144
146
 
145
147
  option: (
146
148
  name: AllCommandOptions<A>["name"],
147
149
  ) => Effect.Effect<
148
- Discord.ApplicationCommandDatum,
150
+ DiscordApplicationCommand,
149
151
  never,
150
152
  Option.Option<Discord.ApplicationCommandInteractionDataOption>
151
153
  >
152
154
 
153
155
  optionValue: <N extends AllRequiredCommandOptions<A>["name"]>(
154
156
  name: N,
155
- ) => Effect.Effect<Discord.ApplicationCommandDatum, never, CommandValue<A, N>>
157
+ ) => Effect.Effect<DiscordApplicationCommand, never, CommandValue<A, N>>
156
158
 
157
159
  optionValueOptional: <N extends AllCommandOptions<A>["name"]>(
158
160
  name: N,
159
161
  ) => Effect.Effect<
160
- Discord.ApplicationCommandDatum,
162
+ DiscordApplicationCommand,
161
163
  never,
162
164
  Option.Option<CommandValue<A, N>>
163
165
  >
@@ -180,8 +182,8 @@ export interface CommandHelper<A> {
180
182
  : never,
181
183
  SubCommandContext
182
184
  >
183
- | Discord.Interaction
184
- | Discord.ApplicationCommandDatum,
185
+ | DiscordInteraction
186
+ | DiscordApplicationCommand,
185
187
  [NER[keyof NER]] extends [
186
188
  { [Effect.EffectTypeId]: { _E: (_: never) => infer E } },
187
189
  ]
@@ -208,8 +210,8 @@ type SubCommands<A> = A extends {
208
210
  }
209
211
  ? A
210
212
  : A extends { readonly options: ReadonlyArray<CommandOption> }
211
- ? SubCommands<A["options"][number]>
212
- : never
213
+ ? SubCommands<A["options"][number]>
214
+ : never
213
215
 
214
216
  type SubCommandNames<A> = Option<SubCommands<A>>["name"]
215
217
 
@@ -16,9 +16,11 @@ import type {
16
16
  } from "dfx/Interactions/definitions"
17
17
  import type { DefinitionNotFound } from "dfx/Interactions/handlers"
18
18
  import { handlers } from "dfx/Interactions/handlers"
19
- import type { InteractionBuilder } from "dfx/Interactions/index"
19
+ import type {
20
+ DiscordInteraction,
21
+ InteractionBuilder,
22
+ } from "dfx/Interactions/index"
20
23
  import { builder, Interaction } from "dfx/Interactions/index"
21
- import type * as Discord from "dfx/types"
22
24
  import * as EffectUtils from "dfx/utils/Effect"
23
25
  import * as Schedule from "effect/Schedule"
24
26
  import { globalValue } from "effect/GlobalValue"
@@ -36,7 +38,7 @@ export const run =
36
38
  <R, R2, E, TE, E2>(
37
39
  postHandler: (
38
40
  effect: Effect.Effect<
39
- R | DiscordREST | Discord.Interaction,
41
+ R | DiscordREST | DiscordInteraction,
40
42
  TE | DiscordRESTError | DefinitionNotFound,
41
43
  void
42
44
  >,
@@ -45,7 +47,7 @@ export const run =
45
47
  (
46
48
  ix: InteractionBuilder<R, E, TE>,
47
49
  ): Effect.Effect<
48
- DiscordREST | DiscordGateway | Exclude<R2, Discord.Interaction>,
50
+ DiscordREST | DiscordGateway | Exclude<R2, DiscordInteraction>,
49
51
  E2 | DiscordRESTError | Http.error.ResponseError,
50
52
  never
51
53
  > =>
@@ -155,13 +157,19 @@ const makeRegistry = Effect.gen(function* (_) {
155
157
  }),
156
158
  )
157
159
 
158
- export interface InteractionsRegistry {
160
+ export interface InteractionsRegistryService {
159
161
  readonly register: <E>(
160
162
  ix: InteractionBuilder<never, E, never>,
161
163
  ) => Effect.Effect<never, never, void>
162
164
  }
165
+ export interface InteractionsRegistry {
166
+ readonly _: unique symbol
167
+ }
163
168
 
164
- export const InteractionsRegistry = Tag<InteractionsRegistry>()
169
+ export const InteractionsRegistry = Tag<
170
+ InteractionsRegistry,
171
+ InteractionsRegistryService
172
+ >("dfx/Interactions/InteractionsRegistry")
165
173
  export const InteractionsRegistryLive = Layer.scoped(
166
174
  InteractionsRegistry,
167
175
  makeRegistry,
@@ -13,7 +13,7 @@ export class DefinitionNotFound {
13
13
  }
14
14
 
15
15
  type Handler<R, E, A> = Effect.Effect<
16
- R | Discord.Interaction,
16
+ R | Ctx.DiscordInteraction,
17
17
  E | DefinitionNotFound,
18
18
  A
19
19
  >