dfx 0.9.7 → 0.9.8
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/package.json +7 -6
- package/README.md +0 -41
- package/dist/DiscordConfig/index.d.ts +0 -40
- package/dist/DiscordConfig/index.d.ts.map +0 -1
- package/dist/DiscordConfig/index.js +0 -29
- package/dist/DiscordConfig/index.js.map +0 -1
- package/dist/DiscordGateway/DiscordWS/index.d.ts +0 -24
- package/dist/DiscordGateway/DiscordWS/index.d.ts.map +0 -1
- package/dist/DiscordGateway/DiscordWS/index.js +0 -26
- package/dist/DiscordGateway/DiscordWS/index.js.map +0 -1
- package/dist/DiscordGateway/Shard/heartbeats.d.ts +0 -4
- package/dist/DiscordGateway/Shard/heartbeats.d.ts.map +0 -1
- package/dist/DiscordGateway/Shard/heartbeats.js +0 -24
- package/dist/DiscordGateway/Shard/heartbeats.js.map +0 -1
- package/dist/DiscordGateway/Shard/identify.d.ts +0 -13
- package/dist/DiscordGateway/Shard/identify.d.ts.map +0 -1
- package/dist/DiscordGateway/Shard/identify.js +0 -30
- package/dist/DiscordGateway/Shard/identify.js.map +0 -1
- package/dist/DiscordGateway/Shard/index.d.ts +0 -10
- package/dist/DiscordGateway/Shard/index.d.ts.map +0 -1
- package/dist/DiscordGateway/Shard/index.js +0 -52
- package/dist/DiscordGateway/Shard/index.js.map +0 -1
- package/dist/DiscordGateway/Shard/invalidSession.d.ts +0 -4
- package/dist/DiscordGateway/Shard/invalidSession.d.ts.map +0 -1
- package/dist/DiscordGateway/Shard/invalidSession.js +0 -10
- package/dist/DiscordGateway/Shard/invalidSession.js.map +0 -1
- package/dist/DiscordGateway/Shard/sendEvents.d.ts +0 -8
- package/dist/DiscordGateway/Shard/sendEvents.d.ts.map +0 -1
- package/dist/DiscordGateway/Shard/sendEvents.js +0 -26
- package/dist/DiscordGateway/Shard/sendEvents.js.map +0 -1
- package/dist/DiscordGateway/Shard/utils.d.ts +0 -4
- package/dist/DiscordGateway/Shard/utils.d.ts.map +0 -1
- package/dist/DiscordGateway/Shard/utils.js +0 -9
- package/dist/DiscordGateway/Shard/utils.js.map +0 -1
- package/dist/DiscordGateway/ShardStore/index.d.ts +0 -13
- package/dist/DiscordGateway/ShardStore/index.d.ts.map +0 -1
- package/dist/DiscordGateway/ShardStore/index.js +0 -22
- package/dist/DiscordGateway/ShardStore/index.js.map +0 -1
- package/dist/DiscordGateway/Sharder/index.d.ts +0 -10
- package/dist/DiscordGateway/Sharder/index.d.ts.map +0 -1
- package/dist/DiscordGateway/Sharder/index.js +0 -61
- package/dist/DiscordGateway/Sharder/index.js.map +0 -1
- package/dist/DiscordGateway/WS/index.d.ts +0 -28
- package/dist/DiscordGateway/WS/index.d.ts.map +0 -1
- package/dist/DiscordGateway/WS/index.js +0 -82
- package/dist/DiscordGateway/WS/index.js.map +0 -1
- package/dist/DiscordGateway/index.d.ts +0 -21
- package/dist/DiscordGateway/index.d.ts.map +0 -1
- package/dist/DiscordGateway/index.js +0 -27
- package/dist/DiscordGateway/index.js.map +0 -1
- package/dist/DiscordREST/index.d.ts +0 -13
- package/dist/DiscordREST/index.d.ts.map +0 -1
- package/dist/DiscordREST/index.js +0 -85
- package/dist/DiscordREST/index.js.map +0 -1
- package/dist/DiscordREST/types.d.ts +0 -10
- package/dist/DiscordREST/types.d.ts.map +0 -1
- package/dist/DiscordREST/types.js +0 -2
- package/dist/DiscordREST/types.js.map +0 -1
- package/dist/DiscordREST/utils.d.ts +0 -11
- package/dist/DiscordREST/utils.d.ts.map +0 -1
- package/dist/DiscordREST/utils.js +0 -22
- package/dist/DiscordREST/utils.js.map +0 -1
- package/dist/Helpers/flags.d.ts +0 -28
- package/dist/Helpers/flags.d.ts.map +0 -1
- package/dist/Helpers/flags.js +0 -36
- package/dist/Helpers/flags.js.map +0 -1
- package/dist/Helpers/intents.d.ts +0 -25
- package/dist/Helpers/intents.d.ts.map +0 -1
- package/dist/Helpers/intents.js +0 -28
- package/dist/Helpers/intents.js.map +0 -1
- package/dist/Helpers/interactions.d.ts +0 -74
- package/dist/Helpers/interactions.d.ts.map +0 -1
- package/dist/Helpers/interactions.js +0 -93
- package/dist/Helpers/interactions.js.map +0 -1
- package/dist/Helpers/members.d.ts +0 -10
- package/dist/Helpers/members.d.ts.map +0 -1
- package/dist/Helpers/members.js +0 -10
- package/dist/Helpers/members.js.map +0 -1
- package/dist/Helpers/permissions.d.ts +0 -35
- package/dist/Helpers/permissions.d.ts.map +0 -1
- package/dist/Helpers/permissions.js +0 -69
- package/dist/Helpers/permissions.js.map +0 -1
- package/dist/Helpers/ui.d.ts +0 -48
- package/dist/Helpers/ui.d.ts.map +0 -1
- package/dist/Helpers/ui.js +0 -67
- package/dist/Helpers/ui.js.map +0 -1
- package/dist/Http/index.d.ts +0 -31
- package/dist/Http/index.d.ts.map +0 -1
- package/dist/Http/index.js +0 -53
- package/dist/Http/index.js.map +0 -1
- package/dist/Interactions/context.d.ts +0 -37
- package/dist/Interactions/context.d.ts.map +0 -1
- package/dist/Interactions/context.js +0 -34
- package/dist/Interactions/context.js.map +0 -1
- package/dist/Interactions/definitions.d.ts +0 -61
- package/dist/Interactions/definitions.d.ts.map +0 -1
- package/dist/Interactions/definitions.js +0 -52
- package/dist/Interactions/definitions.js.map +0 -1
- package/dist/Interactions/gateway.d.ts +0 -7
- package/dist/Interactions/gateway.d.ts.map +0 -1
- package/dist/Interactions/gateway.js +0 -21
- package/dist/Interactions/gateway.js.map +0 -1
- package/dist/Interactions/handlers.d.ts +0 -9
- package/dist/Interactions/handlers.d.ts.map +0 -1
- package/dist/Interactions/handlers.js +0 -49
- package/dist/Interactions/handlers.js.map +0 -1
- package/dist/Interactions/index.d.ts +0 -18
- package/dist/Interactions/index.d.ts.map +0 -1
- package/dist/Interactions/index.js +0 -39
- package/dist/Interactions/index.js.map +0 -1
- package/dist/Interactions/utils.d.ts +0 -11
- package/dist/Interactions/utils.d.ts.map +0 -1
- package/dist/Interactions/utils.js +0 -61
- package/dist/Interactions/utils.js.map +0 -1
- package/dist/Interactions/webhook.d.ts +0 -33
- package/dist/Interactions/webhook.d.ts.map +0 -1
- package/dist/Interactions/webhook.js +0 -42
- package/dist/Interactions/webhook.js.map +0 -1
- package/dist/Log/index.d.ts +0 -13
- package/dist/Log/index.d.ts.map +0 -1
- package/dist/Log/index.js +0 -19
- package/dist/Log/index.js.map +0 -1
- package/dist/RateLimitStore/index.d.ts +0 -25
- package/dist/RateLimitStore/index.d.ts.map +0 -1
- package/dist/RateLimitStore/index.js +0 -24
- package/dist/RateLimitStore/index.js.map +0 -1
- package/dist/RateLimitStore/memory.d.ts +0 -3
- package/dist/RateLimitStore/memory.d.ts.map +0 -1
- package/dist/RateLimitStore/memory.js +0 -31
- package/dist/RateLimitStore/memory.js.map +0 -1
- package/dist/RateLimitStore/utils.d.ts +0 -3
- package/dist/RateLimitStore/utils.d.ts.map +0 -1
- package/dist/RateLimitStore/utils.js +0 -18
- package/dist/RateLimitStore/utils.js.map +0 -1
- package/dist/common-gateway.d.ts +0 -6
- package/dist/common-gateway.d.ts.map +0 -1
- package/dist/common-gateway.js +0 -6
- package/dist/common-gateway.js.map +0 -1
- package/dist/common.d.ts +0 -29
- package/dist/common.d.ts.map +0 -1
- package/dist/common.js +0 -16
- package/dist/common.js.map +0 -1
- package/dist/global.d.ts +0 -18
- package/dist/global.d.ts.map +0 -1
- package/dist/global.js +0 -2
- package/dist/global.js.map +0 -1
- package/dist/index.d.ts +0 -22
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -29
- package/dist/index.js.map +0 -1
- package/dist/types.d.ts +0 -4229
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -1796
- package/dist/types.js.map +0 -1
- package/dist/utils/effect.d.ts +0 -3
- package/dist/utils/effect.d.ts.map +0 -1
- package/dist/utils/effect.js +0 -2
- package/dist/utils/effect.js.map +0 -1
- package/dist/utils/tsplus.d.ts +0 -14
- package/dist/utils/tsplus.d.ts.map +0 -1
- package/dist/utils/tsplus.js +0 -2
- package/dist/utils/tsplus.js.map +0 -1
- package/dist/webhooks.d.ts +0 -16
- package/dist/webhooks.d.ts.map +0 -1
- package/dist/webhooks.js +0 -23
- package/dist/webhooks.js.map +0 -1
- package/src/DiscordConfig/index.ts +0 -52
- package/src/DiscordGateway/DiscordWS/index.ts +0 -50
- package/src/DiscordGateway/Shard/heartbeats.ts +0 -39
- package/src/DiscordGateway/Shard/identify.ts +0 -61
- package/src/DiscordGateway/Shard/index.ts +0 -90
- package/src/DiscordGateway/Shard/invalidSession.ts +0 -11
- package/src/DiscordGateway/Shard/sendEvents.ts +0 -35
- package/src/DiscordGateway/Shard/utils.ts +0 -14
- package/src/DiscordGateway/ShardStore/index.ts +0 -33
- package/src/DiscordGateway/Sharder/index.ts +0 -95
- package/src/DiscordGateway/WS/index.ts +0 -99
- package/src/DiscordGateway/index.ts +0 -55
- package/src/DiscordREST/index.ts +0 -132
- package/src/DiscordREST/types.ts +0 -14
- package/src/DiscordREST/utils.ts +0 -35
- package/src/Helpers/flags.ts +0 -68
- package/src/Helpers/intents.ts +0 -32
- package/src/Helpers/interactions.ts +0 -180
- package/src/Helpers/members.ts +0 -14
- package/src/Helpers/permissions.ts +0 -102
- package/src/Helpers/ui.ts +0 -103
- package/src/Http/index.ts +0 -65
- package/src/Interactions/context.ts +0 -100
- package/src/Interactions/definitions.ts +0 -144
- package/src/Interactions/gateway.ts +0 -55
- package/src/Interactions/handlers.ts +0 -139
- package/src/Interactions/index.ts +0 -83
- package/src/Interactions/utils.ts +0 -81
- package/src/Interactions/webhook.ts +0 -96
- package/src/Log/index.ts +0 -23
- package/src/RateLimitStore/index.ts +0 -65
- package/src/RateLimitStore/memory.ts +0 -48
- package/src/RateLimitStore/utils.ts +0 -27
- package/src/common-gateway.ts +0 -5
- package/src/common.ts +0 -30
- package/src/global.ts +0 -50
- package/src/index.ts +0 -36
- package/src/json.d.ts +0 -1
- package/src/types.ts +0 -6095
- package/src/utils/effect.ts +0 -7
- package/src/utils/tsplus.ts +0 -11
- package/src/webhooks.ts +0 -30
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { millis } from "@fp-ts/data/Duration"
|
|
2
|
-
import { overridePull } from "callbag-effect-ts/Source"
|
|
3
|
-
import { ShardStore } from "../ShardStore/index.js"
|
|
4
|
-
|
|
5
|
-
const configs = (totalCount: number) =>
|
|
6
|
-
Do(($) => {
|
|
7
|
-
const store = $(Effect.service(ShardStore))
|
|
8
|
-
const claimId = (sharderCount: number) =>
|
|
9
|
-
store
|
|
10
|
-
.claimId({
|
|
11
|
-
totalCount,
|
|
12
|
-
sharderCount,
|
|
13
|
-
})
|
|
14
|
-
.flatMap(
|
|
15
|
-
(
|
|
16
|
-
a,
|
|
17
|
-
): Effect<
|
|
18
|
-
never,
|
|
19
|
-
never,
|
|
20
|
-
readonly [Maybe<number>, EffectSource<never, never, number>]
|
|
21
|
-
> =>
|
|
22
|
-
a.match(
|
|
23
|
-
() =>
|
|
24
|
-
Effect.succeed([
|
|
25
|
-
Maybe.some(sharderCount),
|
|
26
|
-
EffectSource.empty,
|
|
27
|
-
] as const).delay(Duration.minutes(3)),
|
|
28
|
-
(id) =>
|
|
29
|
-
Effect.succeed([
|
|
30
|
-
Maybe.some(sharderCount + 1),
|
|
31
|
-
EffectSource.of(id),
|
|
32
|
-
]),
|
|
33
|
-
),
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
return EffectSource.resource(0, (sharderCount) =>
|
|
37
|
-
EffectSource.fromEffect(claimId(sharderCount)),
|
|
38
|
-
).map((id) => ({
|
|
39
|
-
id,
|
|
40
|
-
totalCount,
|
|
41
|
-
}))
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
const spawnEffect = Effect.structPar({
|
|
45
|
-
gateway: Rest.rest
|
|
46
|
-
.getGatewayBot()
|
|
47
|
-
.flatMap((r) => r.json)
|
|
48
|
-
.catchAll(() =>
|
|
49
|
-
Effect.succeed<Discord.GetGatewayBotResponse>({
|
|
50
|
-
url: "wss://gateway.discord.gg/",
|
|
51
|
-
shards: 1,
|
|
52
|
-
session_start_limit: {
|
|
53
|
-
total: 0,
|
|
54
|
-
remaining: 0,
|
|
55
|
-
reset_after: 0,
|
|
56
|
-
max_concurrency: 1,
|
|
57
|
-
},
|
|
58
|
-
}),
|
|
59
|
-
),
|
|
60
|
-
config: Config.gateway,
|
|
61
|
-
limiter: Effect.service(RateLimitStore.RateLimiter),
|
|
62
|
-
})
|
|
63
|
-
.bind("configs", ({ gateway, config }) =>
|
|
64
|
-
configs(config.shardCount ?? gateway.shards),
|
|
65
|
-
)
|
|
66
|
-
.map(({ gateway, config, configs, limiter }) => {
|
|
67
|
-
const [source, pull] = overridePull(
|
|
68
|
-
configs,
|
|
69
|
-
gateway.session_start_limit.max_concurrency,
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
return source
|
|
73
|
-
.map((config) => ({
|
|
74
|
-
...config,
|
|
75
|
-
url: gateway.url,
|
|
76
|
-
concurrency: gateway.session_start_limit.max_concurrency,
|
|
77
|
-
}))
|
|
78
|
-
.groupBy((c) => c.id % c.concurrency)
|
|
79
|
-
.chainPar(([shardConfig, key]) =>
|
|
80
|
-
shardConfig
|
|
81
|
-
.tap(() =>
|
|
82
|
-
limiter.maybeWait(
|
|
83
|
-
`gateway.sharder.${key}`,
|
|
84
|
-
millis(config.identifyRateLimit[0]),
|
|
85
|
-
config.identifyRateLimit[1],
|
|
86
|
-
),
|
|
87
|
-
)
|
|
88
|
-
.mapEffect((c) => Shard.make([c.id, c.totalCount])),
|
|
89
|
-
)
|
|
90
|
-
.tap(() => Effect.sync(pull))
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
export const spawn = spawnEffect.unwrap.chainPar((shard) =>
|
|
94
|
-
EffectSource.of(shard).merge(EffectSource.fromEffect(shard.run).drain),
|
|
95
|
-
)
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import WebSocket from "isomorphic-ws"
|
|
2
|
-
|
|
3
|
-
export const Reconnect = Symbol()
|
|
4
|
-
export type Reconnect = typeof Reconnect
|
|
5
|
-
export type Message = string | Buffer | ArrayBuffer | Reconnect
|
|
6
|
-
|
|
7
|
-
const socket = (urlRef: Ref<string>, options?: WebSocket.ClientOptions) =>
|
|
8
|
-
Do(($) => {
|
|
9
|
-
const url = $(urlRef.get)
|
|
10
|
-
return new WebSocket(url, options)
|
|
11
|
-
}).acquireRelease((ws) =>
|
|
12
|
-
Effect.sync(() => {
|
|
13
|
-
ws.close()
|
|
14
|
-
ws.removeAllListeners()
|
|
15
|
-
}),
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
export class WebSocketError {
|
|
19
|
-
readonly _tag = "WebSocketError"
|
|
20
|
-
constructor(readonly reason: unknown) {}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export class WebSocketCloseError {
|
|
24
|
-
readonly _tag = "WebSocketCloseError"
|
|
25
|
-
constructor(readonly code: number, readonly reason: string) {}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const recv = (ws: WebSocket) =>
|
|
29
|
-
EffectSource.async<WebSocketError | WebSocketCloseError, WebSocket.RawData>(
|
|
30
|
-
(emit) => {
|
|
31
|
-
ws.on("message", (message) => {
|
|
32
|
-
emit.data(message)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
ws.on("error", (cause) => {
|
|
36
|
-
emit.fail(new WebSocketError(cause))
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
ws.on("close", (code, reason) => {
|
|
40
|
-
emit.fail(new WebSocketCloseError(code, reason.toString("utf8")))
|
|
41
|
-
})
|
|
42
|
-
},
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
export class WebSocketWriteError {
|
|
46
|
-
readonly _tag = "WebSocketWriteError"
|
|
47
|
-
constructor(readonly reason: Error) {}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const send = (ws: WebSocket, out: EffectSource<never, never, Message>) =>
|
|
51
|
-
Do(($) => {
|
|
52
|
-
const log = $(Effect.service(Log.Log))
|
|
53
|
-
return Effect.async<never, never, void>((resume) => {
|
|
54
|
-
if (ws.readyState & ws.OPEN) {
|
|
55
|
-
resume(Effect.unit())
|
|
56
|
-
} else {
|
|
57
|
-
ws.once("open", () => {
|
|
58
|
-
resume(Effect.unit())
|
|
59
|
-
})
|
|
60
|
-
}
|
|
61
|
-
})
|
|
62
|
-
.map(() => out)
|
|
63
|
-
.unwrap.tap((p) => log.debug("WS", "send", p))
|
|
64
|
-
.tap((data) =>
|
|
65
|
-
Effect.async<never, WebSocketWriteError, void>((resume) => {
|
|
66
|
-
if (data === Reconnect) {
|
|
67
|
-
ws.close(1012, "reconnecting")
|
|
68
|
-
resume(Effect.unit())
|
|
69
|
-
} else {
|
|
70
|
-
ws.send(data, (err) => {
|
|
71
|
-
resume(
|
|
72
|
-
err
|
|
73
|
-
? Effect.fail(new WebSocketWriteError(err!))
|
|
74
|
-
: Effect.unit(),
|
|
75
|
-
)
|
|
76
|
-
})
|
|
77
|
-
}
|
|
78
|
-
}),
|
|
79
|
-
).drain
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
export const make = (url: Ref<string>, options?: WebSocket.ClientOptions) =>
|
|
83
|
-
Do(($) => {
|
|
84
|
-
const [sink, outbound] = EffectSource.asyncSink<never, Message>()
|
|
85
|
-
const log = $(Effect.service(Log.Log))
|
|
86
|
-
const withLog = Effect.provideService(Log.Log)(log)
|
|
87
|
-
|
|
88
|
-
const source = Do(($) => {
|
|
89
|
-
const ws = $(socket(url, options))
|
|
90
|
-
const sendEffect = $(withLog(send(ws, outbound)))
|
|
91
|
-
return recv(ws).merge(sendEffect)
|
|
92
|
-
}).unwrapScope.retry(
|
|
93
|
-
Schedule.recurWhile(
|
|
94
|
-
(e) => e._tag === "WebSocketCloseError" && e.code === 1012,
|
|
95
|
-
),
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
return { source, sink }
|
|
99
|
-
})
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { spawn } from "./Sharder/index.js"
|
|
2
|
-
|
|
3
|
-
const fromDispatchFactory =
|
|
4
|
-
<R, E>(
|
|
5
|
-
source: EffectSource<R, E, Discord.GatewayPayload<Discord.ReceiveEvent>>,
|
|
6
|
-
) =>
|
|
7
|
-
<K extends keyof Discord.ReceiveEvents>(
|
|
8
|
-
event: K,
|
|
9
|
-
): EffectSource<R, E, Discord.ReceiveEvents[K]> =>
|
|
10
|
-
source.filter((p) => p.t === event).map((p) => p.d! as any)
|
|
11
|
-
|
|
12
|
-
const handleDispatchFactory =
|
|
13
|
-
<R, E>(
|
|
14
|
-
source: EffectSource<R, E, Discord.GatewayPayload<Discord.ReceiveEvent>>,
|
|
15
|
-
) =>
|
|
16
|
-
<K extends keyof Discord.ReceiveEvents, R1, E1, A>(
|
|
17
|
-
event: K,
|
|
18
|
-
handle: (event: Discord.ReceiveEvents[K]) => Effect<R1, E1, A>,
|
|
19
|
-
): Effect<R | R1, E | E1, void> =>
|
|
20
|
-
source
|
|
21
|
-
.filter((p) => p.t === event)
|
|
22
|
-
.chainPar((a) => EffectSource.fromEffect(handle(a.d as any))).runDrain
|
|
23
|
-
|
|
24
|
-
export const make = Do(($) => {
|
|
25
|
-
const shards = $(spawn.share)
|
|
26
|
-
const raw = $(shards.chainPar((s) => s.raw).share)
|
|
27
|
-
const dispatch = $(shards.chainPar((s) => s.dispatch).share)
|
|
28
|
-
const fromDispatch = fromDispatchFactory(dispatch)
|
|
29
|
-
const handleDispatch = handleDispatchFactory(dispatch)
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
shards,
|
|
33
|
-
raw,
|
|
34
|
-
dispatch,
|
|
35
|
-
fromDispatch,
|
|
36
|
-
handleDispatch,
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
export interface DiscordGateway extends Success<typeof make> {}
|
|
41
|
-
export const DiscordGateway = Tag<DiscordGateway>()
|
|
42
|
-
export const LiveDiscordGateway = Layer.fromEffect(DiscordGateway)(make)
|
|
43
|
-
|
|
44
|
-
export const handleDispatch = <
|
|
45
|
-
K extends keyof Discord.ReceiveEvents,
|
|
46
|
-
R1,
|
|
47
|
-
E1,
|
|
48
|
-
A,
|
|
49
|
-
>(
|
|
50
|
-
event: K,
|
|
51
|
-
handle: (event: Discord.ReceiveEvents[K]) => Effect<R1, E1, A>,
|
|
52
|
-
) =>
|
|
53
|
-
Effect.serviceWithEffect(DiscordGateway)((a) =>
|
|
54
|
-
a.handleDispatch(event, handle),
|
|
55
|
-
)
|
package/src/DiscordREST/index.ts
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { millis } from "@fp-ts/data/Duration"
|
|
2
|
-
import { BucketDetails } from "dfx/RateLimitStore/index"
|
|
3
|
-
import { ResponseWithData } from "./types.js"
|
|
4
|
-
import { rateLimitFromHeaders, routeFromConfig } from "./utils.js"
|
|
5
|
-
import Pkg from "../../package.json" assert { type: "json" }
|
|
6
|
-
|
|
7
|
-
const make = Do(($) => {
|
|
8
|
-
const { token, rest } = $(Effect.service(Config.DiscordConfig))
|
|
9
|
-
|
|
10
|
-
const log = $(Effect.service(Log.Log))
|
|
11
|
-
const store = $(Effect.service(RateLimitStore.RateLimitStore))
|
|
12
|
-
const { maybeWait } = $(Effect.service(RateLimitStore.RateLimiter))
|
|
13
|
-
|
|
14
|
-
const globalRateLimit = maybeWait(
|
|
15
|
-
"rest.global",
|
|
16
|
-
rest.globalRateLimit.window,
|
|
17
|
-
rest.globalRateLimit.limit,
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
const requestRateLimit = (path: string, init: RequestInit) =>
|
|
21
|
-
Do(($) => {
|
|
22
|
-
const route = routeFromConfig(path, init)
|
|
23
|
-
const maybeBucket = $(store.getBucketForRoute(route))
|
|
24
|
-
const bucket = maybeBucket.getOrElse(
|
|
25
|
-
(): BucketDetails => ({
|
|
26
|
-
key: `?.${Equal.hash(route)}`,
|
|
27
|
-
resetAfter: 5000,
|
|
28
|
-
limit: 1,
|
|
29
|
-
}),
|
|
30
|
-
)
|
|
31
|
-
const resetAfter = millis(bucket.resetAfter)
|
|
32
|
-
$(maybeWait(`rest.bucket.${bucket.key}`, resetAfter, bucket.limit))
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
const updateBuckets = (path: string, init: RequestInit, response: Response) =>
|
|
36
|
-
Do(($) => {
|
|
37
|
-
const route = routeFromConfig(path, init)
|
|
38
|
-
const { bucket, retryAfter, limit, remaining } = $(
|
|
39
|
-
Effect.fromOption(rateLimitFromHeaders(response.headers)),
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
const effectsToRun = [store.putBucketRoute(route, bucket)]
|
|
43
|
-
|
|
44
|
-
const hasBucket = $(store.hasBucket(bucket))
|
|
45
|
-
if (!hasBucket || limit - 1 === remaining) {
|
|
46
|
-
effectsToRun.push(
|
|
47
|
-
store.putBucket({
|
|
48
|
-
key: bucket,
|
|
49
|
-
resetAfter: retryAfter.millis,
|
|
50
|
-
limit: !hasBucket && remaining > 0 ? remaining : limit,
|
|
51
|
-
}),
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
$(effectsToRun.collectAllParDiscard)
|
|
56
|
-
}).ignore
|
|
57
|
-
|
|
58
|
-
const request = <A = unknown>(
|
|
59
|
-
path: string,
|
|
60
|
-
init: RequestInit = {},
|
|
61
|
-
): Effect<
|
|
62
|
-
never,
|
|
63
|
-
Http.FetchError | Http.StatusCodeError | Http.JsonParseError,
|
|
64
|
-
ResponseWithData<A>
|
|
65
|
-
> =>
|
|
66
|
-
requestRateLimit(path, init)
|
|
67
|
-
.tap(() => globalRateLimit)
|
|
68
|
-
.flatMap(() =>
|
|
69
|
-
Http.requestWithJson<A>(`${rest.baseUrl}${path}`, {
|
|
70
|
-
...init,
|
|
71
|
-
headers: {
|
|
72
|
-
...(init?.headers ?? {}),
|
|
73
|
-
Authorization: `Bot ${token}`,
|
|
74
|
-
"User-Agent": `DiscordBot (https://github.com/tim-smart/dfx, ${Pkg.version})`,
|
|
75
|
-
},
|
|
76
|
-
}),
|
|
77
|
-
)
|
|
78
|
-
.catchTag("StatusCodeError", (e) =>
|
|
79
|
-
e.code === 429
|
|
80
|
-
? Do(($) => {
|
|
81
|
-
$(log.debug("DiscordREST", "429", path))
|
|
82
|
-
$(updateBuckets(path, init, e.response))
|
|
83
|
-
return $(request<A>(path, init))
|
|
84
|
-
})
|
|
85
|
-
: Effect.fail(e),
|
|
86
|
-
)
|
|
87
|
-
.tap(({ response }) => updateBuckets(path, init, response))
|
|
88
|
-
|
|
89
|
-
return { request }
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
export interface DiscordREST extends Success<typeof make> {}
|
|
93
|
-
export const DiscordREST = Tag<DiscordREST>()
|
|
94
|
-
export const LiveDiscordREST = Layer.fromEffect(DiscordREST)(make)
|
|
95
|
-
|
|
96
|
-
export const rest = Discord.createRoutes<RequestInit>(
|
|
97
|
-
({ method, url, params, options = {} }) =>
|
|
98
|
-
Effect.serviceWithEffect(DiscordREST)(({ request }) => {
|
|
99
|
-
const hasBody = method !== "GET" && method !== "DELETE"
|
|
100
|
-
let hasFormData = typeof (options?.body as any)?.append === "function"
|
|
101
|
-
let body: BodyInit | undefined = undefined
|
|
102
|
-
|
|
103
|
-
const headers: Record<string, string> = {}
|
|
104
|
-
if (hasBody && !hasFormData) {
|
|
105
|
-
headers["content-type"] = "application/json"
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const qs = new URLSearchParams()
|
|
109
|
-
if (!hasBody) {
|
|
110
|
-
Object.entries((params ?? {}) as Record<string, string>).forEach(
|
|
111
|
-
([key, value]) => {
|
|
112
|
-
qs.append(key, value)
|
|
113
|
-
},
|
|
114
|
-
)
|
|
115
|
-
} else if (hasFormData) {
|
|
116
|
-
body = options.body!
|
|
117
|
-
if (params) {
|
|
118
|
-
;(body as FormData).append("payload_json", JSON.stringify(params))
|
|
119
|
-
}
|
|
120
|
-
} else if (params) {
|
|
121
|
-
body = JSON.stringify(params)
|
|
122
|
-
} else {
|
|
123
|
-
body = options.body!
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return request(`${url}?${qs.toString()}`, {
|
|
127
|
-
method,
|
|
128
|
-
headers,
|
|
129
|
-
body,
|
|
130
|
-
})
|
|
131
|
-
}),
|
|
132
|
-
)
|
package/src/DiscordREST/types.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { DiscordREST } from "./index.js"
|
|
2
|
-
|
|
3
|
-
export interface ResponseWithData<A> {
|
|
4
|
-
response: Response
|
|
5
|
-
json: Effect<never, Http.JsonParseError, A>
|
|
6
|
-
text: Effect<never, never, string>
|
|
7
|
-
blob: Effect<never, Http.BlobError, Blob>
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export type RestResponse<T> = Effect<
|
|
11
|
-
DiscordREST,
|
|
12
|
-
Http.FetchError | Http.StatusCodeError | Http.JsonParseError,
|
|
13
|
-
ResponseWithData<T>
|
|
14
|
-
>
|
package/src/DiscordREST/utils.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
const majorResources = ["channels", "guilds", "webhooks"] as const
|
|
2
|
-
|
|
3
|
-
export const routeFromConfig = (path: string, init: RequestInit) => {
|
|
4
|
-
const method = (init?.method ?? "get").toLowerCase()
|
|
5
|
-
|
|
6
|
-
// Only keep major ID's
|
|
7
|
-
const routeURL = path
|
|
8
|
-
.split("?")[0]
|
|
9
|
-
.replace(/\/([A-Za-z]+)\/(\d{16,21}|@me)/g, (match, resource) =>
|
|
10
|
-
majorResources.includes(resource) ? match : `/${resource}`,
|
|
11
|
-
)
|
|
12
|
-
// Strip reactions
|
|
13
|
-
.replace(/\/reactions\/(.*)/, "/reactions")
|
|
14
|
-
|
|
15
|
-
return `${method}-${routeURL}`
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const numberHeader = (headers: Headers) => (key: string) =>
|
|
19
|
-
Maybe.fromNullable(headers.get(key))
|
|
20
|
-
.map(parseFloat)
|
|
21
|
-
.filter((n) => !isNaN(n))
|
|
22
|
-
|
|
23
|
-
export const retryAfter = (headers: Headers) =>
|
|
24
|
-
numberHeader(headers)("x-ratelimit-reset-after")
|
|
25
|
-
.catchAll(() => numberHeader(headers)("retry-after"))
|
|
26
|
-
.map(Duration.seconds)
|
|
27
|
-
|
|
28
|
-
export const rateLimitFromHeaders = (headers: Headers) =>
|
|
29
|
-
Maybe.struct({
|
|
30
|
-
bucket: Maybe.fromNullable(headers.get("x-ratelimit-bucket")),
|
|
31
|
-
retryAfter: retryAfter(headers),
|
|
32
|
-
limit: numberHeader(headers)("x-ratelimit-limit"),
|
|
33
|
-
remaining: numberHeader(headers)("x-ratelimit-remaining"),
|
|
34
|
-
})
|
|
35
|
-
export type RateLimitDetails = ReturnType<typeof rateLimitFromHeaders>
|
package/src/Helpers/flags.ts
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
export type Flags<T extends number | bigint> = Record<string, T>
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Returns all the flags OR'ed together.
|
|
5
|
-
*/
|
|
6
|
-
export function all(flags: Flags<number>): number
|
|
7
|
-
export function all(flags: Flags<bigint>): bigint
|
|
8
|
-
export function all(flags: Flags<any>): any {
|
|
9
|
-
return Object.values(flags).reduce((acc, flag) => acc | flag)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Returns a function that converts a bitfield to a list of flag names.
|
|
14
|
-
*/
|
|
15
|
-
export function toList<T extends Flags<number>>(
|
|
16
|
-
flags: T,
|
|
17
|
-
): (bitfield: number) => (keyof T)[]
|
|
18
|
-
export function toList<T extends Flags<bigint>>(
|
|
19
|
-
flags: T,
|
|
20
|
-
): (bitfield: bigint) => (keyof T)[]
|
|
21
|
-
export function toList<T extends Flags<any>>(
|
|
22
|
-
flags: T,
|
|
23
|
-
): (bitfield: any) => (keyof T)[] {
|
|
24
|
-
const entries = Object.entries(flags)
|
|
25
|
-
return (val) =>
|
|
26
|
-
entries.reduce(
|
|
27
|
-
(acc, [key, flag]) => ((val & flag) === flag ? [...acc, key] : acc),
|
|
28
|
-
[] as (keyof T)[],
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Returns a function that converts a list of flags names to a bigint bitfield.
|
|
34
|
-
*/
|
|
35
|
-
export const fromListBigint =
|
|
36
|
-
<T extends Flags<bigint>>(flags: T) =>
|
|
37
|
-
(list: (keyof T)[]) =>
|
|
38
|
-
list.reduce((acc, key) => acc | flags[key], BigInt(0))
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Returns a function that converts a list of flags names to a bitfield.
|
|
42
|
-
*/
|
|
43
|
-
export const fromList =
|
|
44
|
-
<T extends Flags<number>>(flags: T) =>
|
|
45
|
-
(list: (keyof T)[]) =>
|
|
46
|
-
list.reduce((acc, key) => acc | flags[key], 0)
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Checks if a bigint bitfield contains and a flag value.
|
|
50
|
-
*/
|
|
51
|
-
export const hasBigInt = (flag: bigint | string) => {
|
|
52
|
-
const flagBigInt = BigInt(flag)
|
|
53
|
-
return (bits: bigint | string) => {
|
|
54
|
-
const bitsBigInt = BigInt(bits)
|
|
55
|
-
return (bitsBigInt & flagBigInt) === flagBigInt
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Checks if a bitfield contains and a flag value.
|
|
61
|
-
*/
|
|
62
|
-
export const has = (flag: number | string) => {
|
|
63
|
-
const flagNumber = +flag
|
|
64
|
-
return (bits: number | string) => {
|
|
65
|
-
const bitsNumber = +bits
|
|
66
|
-
return (bitsNumber & flagNumber) === flagNumber
|
|
67
|
-
}
|
|
68
|
-
}
|
package/src/Helpers/intents.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* All the intents
|
|
3
|
-
*/
|
|
4
|
-
export const ALL = Flags.all(Discord.GatewayIntents)
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Privileged intents
|
|
8
|
-
*/
|
|
9
|
-
export const PRIVILEGED =
|
|
10
|
-
Discord.GatewayIntents.GUILD_PRESENCES |
|
|
11
|
-
Discord.GatewayIntents.GUILD_MEMBERS |
|
|
12
|
-
Discord.GatewayIntents.MESSAGE_CONTENT
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Un-privileged intents
|
|
16
|
-
*/
|
|
17
|
-
export const UNPRIVILEGED = ALL ^ PRIVILEGED
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Function that converts a intents bitfield value to a list of intent names.
|
|
21
|
-
*/
|
|
22
|
-
export const toList = Flags.toList(Discord.GatewayIntents)
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Function that converts a list of intent names to a bitfield value.
|
|
26
|
-
*/
|
|
27
|
-
export const fromList = Flags.fromList(Discord.GatewayIntents)
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Check if an intent flag exists in the permissions.
|
|
31
|
-
*/
|
|
32
|
-
export const has = Flags.has
|