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.
- package/Cache/prelude.d.ts +3 -3
- package/DiscordConfig.d.ts +5 -7
- package/DiscordConfig.d.ts.map +1 -1
- package/DiscordConfig.js +1 -3
- package/DiscordConfig.js.map +1 -1
- package/DiscordGateway/DiscordWS.d.ts +12 -11
- package/DiscordGateway/DiscordWS.d.ts.map +1 -1
- package/DiscordGateway/DiscordWS.js +8 -5
- package/DiscordGateway/DiscordWS.js.map +1 -1
- package/DiscordGateway/Messaging.d.ts +28 -0
- package/DiscordGateway/Messaging.d.ts.map +1 -0
- package/DiscordGateway/Messaging.js +41 -0
- package/DiscordGateway/Messaging.js.map +1 -0
- package/DiscordGateway/Shard.d.ts +14 -11
- package/DiscordGateway/Shard.d.ts.map +1 -1
- package/DiscordGateway/Shard.js +20 -17
- package/DiscordGateway/Shard.js.map +1 -1
- package/DiscordGateway/ShardStore.d.ts +5 -2
- package/DiscordGateway/ShardStore.d.ts.map +1 -1
- package/DiscordGateway/ShardStore.js +1 -1
- package/DiscordGateway/ShardStore.js.map +1 -1
- package/DiscordGateway/Sharder.d.ts +9 -18
- package/DiscordGateway/Sharder.d.ts.map +1 -1
- package/DiscordGateway/Sharder.js +36 -45
- package/DiscordGateway/Sharder.js.map +1 -1
- package/DiscordGateway/WS.d.ts +14 -10
- package/DiscordGateway/WS.d.ts.map +1 -1
- package/DiscordGateway/WS.js +31 -21
- package/DiscordGateway/WS.js.map +1 -1
- package/DiscordGateway.d.ts +10 -7
- package/DiscordGateway.d.ts.map +1 -1
- package/DiscordGateway.js +13 -31
- package/DiscordGateway.js.map +1 -1
- package/DiscordREST.d.ts +6 -4
- package/DiscordREST.d.ts.map +1 -1
- package/DiscordREST.js +7 -6
- package/DiscordREST.js.map +1 -1
- package/Interactions/context.d.ts +35 -17
- package/Interactions/context.d.ts.map +1 -1
- package/Interactions/context.js +6 -6
- package/Interactions/context.js.map +1 -1
- package/Interactions/definitions.d.ts +11 -11
- package/Interactions/definitions.d.ts.map +1 -1
- package/Interactions/definitions.js.map +1 -1
- package/Interactions/gateway.d.ts +7 -6
- package/Interactions/gateway.d.ts.map +1 -1
- package/Interactions/gateway.js +1 -1
- package/Interactions/gateway.js.map +1 -1
- package/Interactions/handlers.d.ts +2 -1
- package/Interactions/handlers.d.ts.map +1 -1
- package/Interactions/webhook.d.ts +5 -6
- package/Interactions/webhook.d.ts.map +1 -1
- package/Interactions/webhook.js +1 -1
- package/Interactions/webhook.js.map +1 -1
- package/RateLimit/memory.d.ts +2 -2
- package/RateLimit/memory.d.ts.map +1 -1
- package/RateLimit/memory.js.map +1 -1
- package/RateLimit.d.ts +10 -9
- package/RateLimit.d.ts.map +1 -1
- package/RateLimit.js +4 -5
- package/RateLimit.js.map +1 -1
- package/gateway.d.ts +2 -2
- package/gateway.d.ts.map +1 -1
- package/gateway.js +1 -2
- package/gateway.js.map +1 -1
- package/index.d.ts +1 -2
- package/index.d.ts.map +1 -1
- package/index.js +1 -3
- package/index.js.map +1 -1
- package/mjs/DiscordConfig.mjs +1 -3
- package/mjs/DiscordConfig.mjs.map +1 -1
- package/mjs/DiscordGateway/DiscordWS.mjs +8 -5
- package/mjs/DiscordGateway/DiscordWS.mjs.map +1 -1
- package/mjs/DiscordGateway/Messaging.mjs +33 -0
- package/mjs/DiscordGateway/Messaging.mjs.map +1 -0
- package/mjs/DiscordGateway/Shard.mjs +20 -17
- package/mjs/DiscordGateway/Shard.mjs.map +1 -1
- package/mjs/DiscordGateway/ShardStore.mjs +1 -1
- package/mjs/DiscordGateway/ShardStore.mjs.map +1 -1
- package/mjs/DiscordGateway/Sharder.mjs +35 -44
- package/mjs/DiscordGateway/Sharder.mjs.map +1 -1
- package/mjs/DiscordGateway/WS.mjs +32 -22
- package/mjs/DiscordGateway/WS.mjs.map +1 -1
- package/mjs/DiscordGateway.mjs +12 -30
- package/mjs/DiscordGateway.mjs.map +1 -1
- package/mjs/DiscordREST.mjs +7 -6
- package/mjs/DiscordREST.mjs.map +1 -1
- package/mjs/Interactions/context.mjs +6 -6
- package/mjs/Interactions/context.mjs.map +1 -1
- package/mjs/Interactions/definitions.mjs.map +1 -1
- package/mjs/Interactions/gateway.mjs +1 -1
- package/mjs/Interactions/gateway.mjs.map +1 -1
- package/mjs/Interactions/webhook.mjs +1 -1
- package/mjs/Interactions/webhook.mjs.map +1 -1
- package/mjs/RateLimit/memory.mjs.map +1 -1
- package/mjs/RateLimit.mjs +4 -5
- package/mjs/RateLimit.mjs.map +1 -1
- package/mjs/gateway.mjs +1 -2
- package/mjs/gateway.mjs.map +1 -1
- package/mjs/index.mjs +1 -2
- package/mjs/index.mjs.map +1 -1
- package/mjs/version.mjs +1 -1
- package/mjs/webhooks.mjs +1 -2
- package/mjs/webhooks.mjs.map +1 -1
- package/package.json +2 -2
- package/src/DiscordConfig.ts +7 -9
- package/src/DiscordGateway/DiscordWS.ts +23 -13
- package/src/DiscordGateway/Messaging.ts +72 -0
- package/src/DiscordGateway/Shard.ts +51 -33
- package/src/DiscordGateway/ShardStore.ts +8 -3
- package/src/DiscordGateway/Sharder.ts +72 -97
- package/src/DiscordGateway/WS.ts +64 -32
- package/src/DiscordGateway.ts +22 -71
- package/src/DiscordREST.ts +40 -27
- package/src/Interactions/context.ts +47 -10
- package/src/Interactions/definitions.ts +22 -20
- package/src/Interactions/gateway.ts +14 -6
- package/src/Interactions/handlers.ts +1 -1
- package/src/Interactions/webhook.ts +18 -4
- package/src/RateLimit/memory.ts +2 -2
- package/src/RateLimit.ts +17 -8
- package/src/gateway.ts +0 -2
- package/src/index.ts +0 -2
- package/src/version.ts +1 -1
- package/src/webhooks.ts +1 -2
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/webhooks.d.ts +1 -2
- package/webhooks.d.ts.map +1 -1
- package/webhooks.js +1 -2
- package/webhooks.js.map +1 -1
- package/src/Log.ts +0 -24
package/src/DiscordGateway/WS.ts
CHANGED
|
@@ -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
|
-
|
|
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 = (
|
|
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 =>
|
|
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
|
|
116
|
-
|
|
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 =
|
|
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
|
|
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(
|
|
146
|
+
Effect.zipRight(socket(urlRef)),
|
|
130
147
|
Effect.flatMap(ws =>
|
|
131
148
|
Effect.all(
|
|
132
149
|
[
|
|
133
|
-
offer(ws, queue
|
|
150
|
+
offer(ws, queue),
|
|
134
151
|
Effect.zipRight(
|
|
135
152
|
waitForOpen(ws, openTimeout),
|
|
136
|
-
send(ws, takeOutbound
|
|
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
|
-
|
|
147
|
-
})
|
|
171
|
+
yield* _(run)
|
|
148
172
|
|
|
149
|
-
|
|
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
|
|
153
|
-
|
|
154
|
-
|
|
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)
|
package/src/DiscordGateway.ts
CHANGED
|
@@ -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
|
|
7
|
+
import type * as HashSet from "effect/HashSet"
|
|
5
8
|
import * as Layer from "effect/Layer"
|
|
6
|
-
import * as
|
|
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
|
|
27
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
})
|
|
94
|
-
Effect.annotateLogs({
|
|
95
|
-
package: "dfx",
|
|
96
|
-
service: "DiscordGateway",
|
|
97
|
-
}),
|
|
98
|
-
)
|
|
49
|
+
})
|
|
99
50
|
|
|
100
|
-
export const DiscordGatewayLive = Layer.
|
|
101
|
-
Layer.
|
|
102
|
-
|
|
51
|
+
export const DiscordGatewayLive = Layer.effect(DiscordGateway, make).pipe(
|
|
52
|
+
Layer.provide(MesssagingLive),
|
|
53
|
+
Layer.provide(SharderLive),
|
|
103
54
|
)
|
package/src/DiscordREST.ts
CHANGED
|
@@ -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
|
-
|
|
51
|
-
.
|
|
52
|
-
.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
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
|
|
195
|
-
.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
-
|
|
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
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export const
|
|
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<
|
|
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<
|
|
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<
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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<
|
|
145
|
+
) => Effect.Effect<DiscordInteraction, ResolvedDataNotFound, T>
|
|
144
146
|
|
|
145
147
|
option: (
|
|
146
148
|
name: AllCommandOptions<A>["name"],
|
|
147
149
|
) => Effect.Effect<
|
|
148
|
-
|
|
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<
|
|
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
|
-
|
|
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
|
-
|
|
|
184
|
-
|
|
|
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
|
-
|
|
212
|
-
|
|
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 {
|
|
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 |
|
|
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,
|
|
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
|
|
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<
|
|
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,
|