dfx 0.77.2 → 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 +7 -6
  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 +10 -8
  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
package/mjs/index.mjs CHANGED
@@ -7,9 +7,8 @@ import * as Members from "dfx/Helpers/members";
7
7
  import * as Perms from "dfx/Helpers/permissions";
8
8
  import * as UI from "dfx/Helpers/ui";
9
9
  import * as Ix from "dfx/Interactions/index";
10
- import * as Log from "dfx/Log";
11
10
  import * as Discord from "dfx/types";
12
11
  export { DiscordREST, DiscordRESTLive } from "dfx/DiscordREST";
13
12
  export { MemoryRateLimitStoreLive, RateLimiterLive, RateLimiter, RateLimitStore } from "dfx/RateLimit";
14
- export { Cache, Discord, DiscordConfig, Flags, Intents, Ix, IxHelpers, Log, Members, Perms, UI };
13
+ export { Cache, Discord, DiscordConfig, Flags, Intents, Ix, IxHelpers, Members, Perms, UI };
15
14
  //# sourceMappingURL=index.mjs.map
package/mjs/index.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["Cache","DiscordConfig","Flags","Intents","IxHelpers","Members","Perms","UI","Ix","Log","Discord","DiscordREST","DiscordRESTLive","MemoryRateLimitStoreLive","RateLimiterLive","RateLimiter","RateLimitStore"],"sources":["../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA,OAAO,KAAKA,KAAK,MAAM,WAAW;AAClC,OAAO,KAAKC,aAAa,MAAM,mBAAmB;AAClD,OAAO,KAAKC,KAAK,MAAM,mBAAmB;AAC1C,OAAO,KAAKC,OAAO,MAAM,qBAAqB;AAC9C,OAAO,KAAKC,SAAS,MAAM,0BAA0B;AACrD,OAAO,KAAKC,OAAO,MAAM,qBAAqB;AAC9C,OAAO,KAAKC,KAAK,MAAM,yBAAyB;AAChD,OAAO,KAAKC,EAAE,MAAM,gBAAgB;AACpC,OAAO,KAAKC,EAAE,MAAM,wBAAwB;AAC5C,OAAO,KAAKC,GAAG,MAAM,SAAS;AAC9B,OAAO,KAAKC,OAAO,MAAM,WAAW;AAEpC,SAASC,WAAW,EAAEC,eAAe,QAAQ,iBAAiB;AAE9D,SAEEC,wBAAwB,EACxBC,eAAe,EACfC,WAAW,EACXC,cAAc,QACT,eAAe;AAEtB,SACEhB,KAAK,EACLU,OAAO,EACPT,aAAa,EACbC,KAAK,EACLC,OAAO,EACPK,EAAE,EACFJ,SAAS,EACTK,GAAG,EACHJ,OAAO,EACPC,KAAK,EACLC,EAAE"}
1
+ {"version":3,"file":"index.mjs","names":["Cache","DiscordConfig","Flags","Intents","IxHelpers","Members","Perms","UI","Ix","Discord","DiscordREST","DiscordRESTLive","MemoryRateLimitStoreLive","RateLimiterLive","RateLimiter","RateLimitStore"],"sources":["../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA,OAAO,KAAKA,KAAK,MAAM,WAAW;AAClC,OAAO,KAAKC,aAAa,MAAM,mBAAmB;AAClD,OAAO,KAAKC,KAAK,MAAM,mBAAmB;AAC1C,OAAO,KAAKC,OAAO,MAAM,qBAAqB;AAC9C,OAAO,KAAKC,SAAS,MAAM,0BAA0B;AACrD,OAAO,KAAKC,OAAO,MAAM,qBAAqB;AAC9C,OAAO,KAAKC,KAAK,MAAM,yBAAyB;AAChD,OAAO,KAAKC,EAAE,MAAM,gBAAgB;AACpC,OAAO,KAAKC,EAAE,MAAM,wBAAwB;AAC5C,OAAO,KAAKC,OAAO,MAAM,WAAW;AAEpC,SAASC,WAAW,EAAEC,eAAe,QAAQ,iBAAiB;AAE9D,SAEEC,wBAAwB,EACxBC,eAAe,EACfC,WAAW,EACXC,cAAc,QACT,eAAe;AAEtB,SACEf,KAAK,EACLS,OAAO,EACPR,aAAa,EACbC,KAAK,EACLC,OAAO,EACPK,EAAE,EACFJ,SAAS,EACTC,OAAO,EACPC,KAAK,EACLC,EAAE"}
package/mjs/version.mjs CHANGED
@@ -1,2 +1,2 @@
1
- export const LIB_VERSION = "0.77.2";
1
+ export const LIB_VERSION = "0.78.0";
2
2
  //# sourceMappingURL=version.mjs.map
package/mjs/webhooks.mjs CHANGED
@@ -1,7 +1,6 @@
1
1
  import { DiscordRESTLive } from "dfx/DiscordREST";
2
- import * as Log from "dfx/Log";
3
2
  import { MemoryRateLimitStoreLive, RateLimiterLive } from "dfx/RateLimit";
4
3
  import * as Layer from "effect/Layer";
5
4
  export { BadWebhookSignature, WebhookConfig, WebhookParseError, makeHandler, makeSimpleHandler, layer as webhookLayer, layerConfig as webhookLayerConfig } from "dfx/Interactions/webhook";
6
- export const DiscordLive = /*#__PURE__*/Layer.mergeAll(DiscordRESTLive, RateLimiterLive).pipe( /*#__PURE__*/Layer.provide(MemoryRateLimitStoreLive), /*#__PURE__*/Layer.provideMerge(Log.LogLive));
5
+ export const DiscordLive = /*#__PURE__*/Layer.mergeAll(DiscordRESTLive, RateLimiterLive).pipe( /*#__PURE__*/Layer.provide(MemoryRateLimitStoreLive));
7
6
  //# sourceMappingURL=webhooks.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.mjs","names":["DiscordRESTLive","Log","MemoryRateLimitStoreLive","RateLimiterLive","Layer","BadWebhookSignature","WebhookConfig","WebhookParseError","makeHandler","makeSimpleHandler","layer","webhookLayer","layerConfig","webhookLayerConfig","DiscordLive","mergeAll","pipe","provide","provideMerge","LogLive"],"sources":["../src/webhooks.ts"],"sourcesContent":[null],"mappings":"AAAA,SAASA,eAAe,QAAQ,iBAAiB;AACjD,OAAO,KAAKC,GAAG,MAAM,SAAS;AAC9B,SACEC,wBAAoD,EACpDC,eAAkC,QAC7B,eAAe;AACtB,OAAO,KAAKC,KAAK,MAAM,cAAc;AAErC,SACEC,mBAAmB,EACnBC,aAAa,EACbC,iBAAiB,EACjBC,WAAW,EACXC,iBAAiB,EACjBC,KAAK,IAAIC,YAAY,EACrBC,WAAW,IAAIC,kBAAkB,QAC5B,0BAA0B;AAEjC,OAAO,MAAMC,WAAW,gBAAGV,KAAK,CAACW,QAAQ,CACvCf,eAAe,EACfG,eAAe,CAChB,CAACa,IAAI,eAACZ,KAAK,CAACa,OAAO,CAACf,wBAAwB,CAAC,eAAEE,KAAK,CAACc,YAAY,CAACjB,GAAG,CAACkB,OAAO,CAAC,CAAC"}
1
+ {"version":3,"file":"webhooks.mjs","names":["DiscordRESTLive","MemoryRateLimitStoreLive","RateLimiterLive","Layer","BadWebhookSignature","WebhookConfig","WebhookParseError","makeHandler","makeSimpleHandler","layer","webhookLayer","layerConfig","webhookLayerConfig","DiscordLive","mergeAll","pipe","provide"],"sources":["../src/webhooks.ts"],"sourcesContent":[null],"mappings":"AAAA,SAASA,eAAe,QAAQ,iBAAiB;AACjD,SACEC,wBAAoD,EACpDC,eAAkC,QAC7B,eAAe;AACtB,OAAO,KAAKC,KAAK,MAAM,cAAc;AAErC,SACEC,mBAAmB,EACnBC,aAAa,EACbC,iBAAiB,EACjBC,WAAW,EACXC,iBAAiB,EACjBC,KAAK,IAAIC,YAAY,EACrBC,WAAW,IAAIC,kBAAkB,QAC5B,0BAA0B;AAEjC,OAAO,MAAMC,WAAW,gBAAGV,KAAK,CAACW,QAAQ,CACvCd,eAAe,EACfE,eAAe,CAChB,CAACa,IAAI,eAACZ,KAAK,CAACa,OAAO,CAACf,wBAAwB,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dfx",
3
- "version": "0.77.2",
3
+ "version": "0.78.0",
4
4
  "description": "Effect-TS discord library",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -48,6 +48,6 @@
48
48
  "utf-8-validate": "^6.0.3",
49
49
  "zlib-sync": "^0.1.9"
50
50
  },
51
- "gitHead": "100a9e2e0e2882c679f520fe645c6e8c28c3181e",
51
+ "gitHead": "efc2997291e09256e66f3654d4bc1ae3422291c8",
52
52
  "main": "./index.js"
53
53
  }
@@ -10,8 +10,11 @@ import * as Discord from "dfx/types"
10
10
  const VERSION = 10
11
11
 
12
12
  export interface DiscordConfig {
13
+ readonly _: unique symbol
14
+ }
15
+
16
+ export interface DiscordConfigService {
13
17
  readonly token: ConfigSecret.ConfigSecret
14
- readonly debug: boolean
15
18
  readonly rest: {
16
19
  readonly baseUrl: string
17
20
  readonly globalRateLimit: {
@@ -27,23 +30,22 @@ export interface DiscordConfig {
27
30
  readonly identifyRateLimit: readonly [window: number, limit: number]
28
31
  }
29
32
  }
30
- export const DiscordConfig = Tag<DiscordConfig>()
33
+ export const DiscordConfig = Tag<DiscordConfig, DiscordConfigService>(
34
+ "dfx/DiscordConfig",
35
+ )
31
36
 
32
37
  export interface MakeOpts {
33
38
  readonly token: ConfigSecret.ConfigSecret
34
- readonly debug?: boolean
35
- readonly rest?: Partial<DiscordConfig["rest"]>
36
- readonly gateway?: Partial<DiscordConfig["gateway"]>
39
+ readonly rest?: Partial<DiscordConfigService["rest"]>
40
+ readonly gateway?: Partial<DiscordConfigService["gateway"]>
37
41
  }
38
42
 
39
43
  export const make = ({
40
- debug = false,
41
44
  gateway,
42
45
  rest,
43
46
  token,
44
- }: MakeOpts): DiscordConfig => ({
47
+ }: MakeOpts): DiscordConfigService => ({
45
48
  token,
46
- debug,
47
49
  rest: {
48
50
  baseUrl: `https://discord.com/api/v${VERSION}`,
49
51
  ...(rest ?? {}),
@@ -16,12 +16,17 @@ export interface OpenOpts {
16
16
  onConnecting?: Effect.Effect<never, never, void>
17
17
  }
18
18
 
19
- export interface DiscordWSCodec {
19
+ export interface DiscordWSCodecService {
20
20
  type: "json" | "etf"
21
21
  encode: (p: Discord.GatewayPayload) => string
22
22
  decode: (p: WebSocket.Data) => Discord.GatewayPayload
23
23
  }
24
- export const DiscordWSCodec = Tag<DiscordWSCodec>()
24
+ export interface DiscordWSCodec {
25
+ readonly _: unique symbol
26
+ }
27
+ export const DiscordWSCodec = Tag<DiscordWSCodec, DiscordWSCodecService>(
28
+ "dfx/DiscordGateway/DiscordWS/Codec",
29
+ )
25
30
  export const JsonDiscordWSCodecLive = Layer.succeed(DiscordWSCodec, {
26
31
  type: "json",
27
32
  encode: p => JSON.stringify(p),
@@ -47,18 +52,19 @@ const make = Effect.gen(function* (_) {
47
52
  const takeOutbound = Effect.map(outbound, msg =>
48
53
  msg === Reconnect ? msg : encoding.encode(msg),
49
54
  )
50
- const socket = yield* _(ws.connect(urlRef, takeOutbound, onConnecting))
51
- const take = Effect.map(socket.take, encoding.decode)
52
-
53
- const run = Effect.retryWhile(
54
- socket.run,
55
- e =>
56
- (e._tag === "WebSocketCloseError" && e.code < 2000) ||
57
- (e._tag === "WebSocketError" && e.reason === "open-timeout"),
55
+ const socket = yield* _(
56
+ ws.connect({
57
+ urlRef,
58
+ takeOutbound,
59
+ onConnecting,
60
+ reconnectWhen: e =>
61
+ (e._tag === "WebSocketCloseError" && e.code < 2000) ||
62
+ (e._tag === "WebSocketError" && e.reason === "open-timeout"),
63
+ }),
58
64
  )
65
+ const take = Effect.map(socket.take, encoding.decode)
59
66
 
60
67
  return {
61
- run,
62
68
  take,
63
69
  setUrl,
64
70
  } as const
@@ -67,8 +73,12 @@ const make = Effect.gen(function* (_) {
67
73
  return { connect } as const
68
74
  })
69
75
 
70
- export interface DiscordWS extends Effect.Effect.Success<typeof make> {}
71
- export const DiscordWS = Tag<DiscordWS>()
76
+ export interface DiscordWS {
77
+ readonly _: unique symbol
78
+ }
79
+ export const DiscordWS = Tag<DiscordWS, Effect.Effect.Success<typeof make>>(
80
+ "dfx/DiscordGateway/DiscordWS",
81
+ )
72
82
  export const DiscordWSLive = Layer.provide(
73
83
  Layer.effect(DiscordWS, make),
74
84
  WSLive,
@@ -0,0 +1,72 @@
1
+ import { Tag } from "effect/Context"
2
+ import * as Effect from "effect/Effect"
3
+ import * as PubSub from "effect/PubSub"
4
+ import * as Layer from "effect/Layer"
5
+ import * as Queue from "effect/Queue"
6
+ import * as Stream from "effect/Stream"
7
+ import type * as Discord from "dfx/types"
8
+ import * as EffectUtils from "dfx/utils/Effect"
9
+
10
+ const fromDispatchFactory =
11
+ <R, E>(
12
+ source: Stream.Stream<R, E, Discord.GatewayPayload<Discord.ReceiveEvent>>,
13
+ ) =>
14
+ <K extends keyof Discord.ReceiveEvents>(
15
+ event: K,
16
+ ): Stream.Stream<R, E, Discord.ReceiveEvents[K]> =>
17
+ Stream.map(
18
+ Stream.filter(source, p => p.t === event),
19
+ p => p.d! as any,
20
+ )
21
+
22
+ const handleDispatchFactory =
23
+ (hub: PubSub.PubSub<Discord.GatewayPayload<Discord.ReceiveEvent>>) =>
24
+ <K extends keyof Discord.ReceiveEvents, R, E, A>(
25
+ event: K,
26
+ handle: (event: Discord.ReceiveEvents[K]) => Effect.Effect<R, E, A>,
27
+ ): Effect.Effect<R, E, never> =>
28
+ EffectUtils.subscribeForEachPar(hub, _ => {
29
+ if (_.t === event) {
30
+ return handle(_.d as any)
31
+ }
32
+ return Effect.unit as any
33
+ })
34
+
35
+ export const make = Effect.gen(function* (_) {
36
+ const hub = yield* _(
37
+ Effect.acquireRelease(
38
+ PubSub.unbounded<Discord.GatewayPayload<Discord.ReceiveEvent>>(),
39
+ PubSub.shutdown,
40
+ ),
41
+ )
42
+
43
+ const sendQueue = yield* _(
44
+ Effect.acquireRelease(
45
+ Queue.unbounded<Discord.GatewayPayload<Discord.SendEvent>>(),
46
+ Queue.shutdown,
47
+ ),
48
+ )
49
+ const send = (payload: Discord.GatewayPayload<Discord.SendEvent>) =>
50
+ sendQueue.offer(payload)
51
+
52
+ const dispatch = Stream.fromPubSub(hub)
53
+ const fromDispatch = fromDispatchFactory(dispatch)
54
+ const handleDispatch = handleDispatchFactory(hub)
55
+
56
+ return {
57
+ hub,
58
+ sendQueue,
59
+ dispatch,
60
+ fromDispatch,
61
+ handleDispatch,
62
+ send,
63
+ } as const
64
+ })
65
+
66
+ export interface Messsaging {
67
+ readonly _: unique symbol
68
+ }
69
+ export const Messaging = Tag<Messsaging, Effect.Effect.Success<typeof make>>(
70
+ "dfx/DiscordGateway/Messaging",
71
+ )
72
+ export const MesssagingLive = Layer.scoped(Messaging, make)
@@ -17,9 +17,9 @@ import * as Identify from "dfx/DiscordGateway/Shard/identify"
17
17
  import * as InvalidSession from "dfx/DiscordGateway/Shard/invalidSession"
18
18
  import * as Utils from "dfx/DiscordGateway/Shard/utils"
19
19
  import { Reconnect } from "dfx/DiscordGateway/WS"
20
- import { Log } from "dfx/Log"
21
20
  import { RateLimiterLive, RateLimiter } from "dfx/RateLimit"
22
21
  import * as Discord from "dfx/types"
22
+ import { Messaging, MesssagingLive } from "dfx/DiscordGateway/Messaging"
23
23
 
24
24
  const enum Phase {
25
25
  Connecting,
@@ -31,19 +31,18 @@ export const make = Effect.gen(function* (_) {
31
31
  const { gateway, token } = yield* _(DiscordConfig)
32
32
  const limiter = yield* _(RateLimiter)
33
33
  const dws = yield* _(DiscordWS)
34
- const log = yield* _(Log)
34
+ const { hub, sendQueue } = yield* _(Messaging)
35
35
 
36
- const connect = (
37
- shard: [id: number, count: number],
38
- hub: PubSub.PubSub<Discord.GatewayPayload<Discord.ReceiveEvent>>,
39
- sendQueue: Queue.Dequeue<Discord.GatewayPayload<Discord.SendEvent>>,
40
- ) =>
36
+ const connect = (shard: [id: number, count: number]) =>
41
37
  Effect.gen(function* (_) {
42
38
  const outboundQueue = yield* _(Queue.unbounded<Message>())
43
39
  const pendingQueue = yield* _(Queue.unbounded<Message>())
44
40
  const phase = yield* _(Ref.make(Phase.Connecting))
45
41
  const setPhase = (p: Phase) =>
46
- Effect.zipLeft(Ref.set(phase, p), log.debug("Shard", shard, "phase", p))
42
+ Effect.zipLeft(
43
+ Ref.set(phase, p),
44
+ Effect.annotateLogs(Effect.logTrace("phase transition"), "phase", p),
45
+ )
47
46
  const outbound = Effect.zipLeft(
48
47
  Queue.take(outboundQueue),
49
48
  limiter.maybeWait("dfx.shard.send", Duration.minutes(1), 120),
@@ -115,15 +114,23 @@ export const make = Effect.gen(function* (_) {
115
114
  },
116
115
  )
117
116
 
118
- const hellos = yield* _(Queue.unbounded<Discord.GatewayPayload>())
119
- const acks = yield* _(Queue.unbounded<Discord.GatewayPayload>())
117
+ const hellos = yield* _(
118
+ Effect.acquireRelease(
119
+ Queue.unbounded<Discord.GatewayPayload>(),
120
+ Queue.shutdown,
121
+ ),
122
+ )
123
+ const acks = yield* _(
124
+ Effect.acquireRelease(
125
+ Queue.unbounded<Discord.GatewayPayload>(),
126
+ Queue.shutdown,
127
+ ),
128
+ )
120
129
 
121
130
  // heartbeats
122
- const heartbeats = Heartbeats.send(
123
- hellos,
124
- acks,
125
- latestSequence,
126
- heartbeatSend,
131
+ yield* _(
132
+ Heartbeats.send(hellos, acks, latestSequence, heartbeatSend),
133
+ Effect.forkScoped,
127
134
  )
128
135
 
129
136
  // identify
@@ -169,32 +176,43 @@ export const make = Effect.gen(function* (_) {
169
176
  }),
170
177
  )
171
178
 
172
- const drainSendQueue = Effect.forever(
173
- Effect.tap(Queue.take(sendQueue), send),
179
+ yield* _(
180
+ Queue.take(sendQueue),
181
+ Effect.tap(send),
182
+ Effect.forever,
183
+ Effect.forkScoped,
174
184
  )
175
185
 
176
- const run = Effect.all(
177
- [
178
- Effect.forever(Effect.flatMap(socket.take, onPayload)),
179
- heartbeats,
180
- drainSendQueue,
181
- socket.run,
182
- ],
183
- { discard: true, concurrency: "unbounded" },
186
+ yield* _(
187
+ socket.take,
188
+ Effect.flatMap(onPayload),
189
+ Effect.forever,
190
+ Effect.forkScoped,
184
191
  )
185
192
 
186
- return { id: shard, send, run } as const
187
- })
193
+ return { id: shard, send } as const
194
+ }).pipe(
195
+ Effect.annotateLogs({
196
+ package: "dfx",
197
+ module: "DiscordGateway/Shard",
198
+ shard,
199
+ }),
200
+ )
188
201
 
189
202
  return { connect } as const
190
203
  })
191
204
 
192
- export interface Shard extends Effect.Effect.Success<typeof make> {}
193
- export const Shard = Tag<Shard>()
194
- export const ShardLive = Layer.provide(
195
- Layer.effect(Shard, make),
196
- Layer.merge(DiscordWSLive, RateLimiterLive),
205
+ type ShardService = Effect.Effect.Success<typeof make>
206
+
207
+ export interface Shard {
208
+ readonly _: unique symbol
209
+ }
210
+ export const Shard = Tag<Shard, ShardService>("dfx/DiscordGateway/Shard")
211
+ export const ShardLive = Layer.effect(Shard, make).pipe(
212
+ Layer.provide(DiscordWSLive),
213
+ Layer.provide(MesssagingLive),
214
+ Layer.provide(RateLimiterLive),
197
215
  )
198
216
 
199
217
  export interface RunningShard
200
- extends Effect.Effect.Success<ReturnType<Shard["connect"]>> {}
218
+ extends Effect.Effect.Success<ReturnType<ShardService["connect"]>> {}
@@ -8,17 +8,22 @@ export interface ClaimIdContext {
8
8
  totalCount: number
9
9
  }
10
10
 
11
- export interface ShardStore {
11
+ export interface ShardStoreService {
12
12
  claimId: (
13
13
  ctx: ClaimIdContext,
14
14
  ) => Effect.Effect<never, never, Option.Option<number>>
15
15
  allClaimed: (totalCount: number) => Effect.Effect<never, never, boolean>
16
16
  heartbeat?: (shardId: number) => Effect.Effect<never, never, void>
17
17
  }
18
- export const ShardStore = Tag<ShardStore>()
18
+ export interface ShardStore {
19
+ readonly _: unique symbol
20
+ }
21
+ export const ShardStore = Tag<ShardStore, ShardStoreService>(
22
+ "dfx/DiscordGateway/ShardStore",
23
+ )
19
24
 
20
25
  // Very basic shard id store, that does no health checks
21
- const memoryStore = (): ShardStore => {
26
+ const memoryStore = (): ShardStoreService => {
22
27
  let currentId = 0
23
28
 
24
29
  return {
@@ -1,24 +1,19 @@
1
- import * as Chunk from "effect/Chunk"
1
+ import { DiscordConfig } from "dfx/DiscordConfig"
2
+ import type { RunningShard } from "dfx/DiscordGateway/Shard"
3
+ import { Shard, ShardLive } from "dfx/DiscordGateway/Shard"
4
+ import { ShardStore } from "dfx/DiscordGateway/ShardStore"
5
+ import { DiscordREST, DiscordRESTLive } from "dfx/DiscordREST"
6
+ import { RateLimiter, RateLimiterLive } from "dfx/RateLimit"
7
+ import type * as Discord from "dfx/types"
2
8
  import { Tag } from "effect/Context"
3
9
  import * as Duration from "effect/Duration"
10
+ import * as Effect from "effect/Effect"
4
11
  import { pipe } from "effect/Function"
5
12
  import * as HashSet from "effect/HashSet"
6
- import type * as Option from "effect/Option"
7
- import * as Deferred from "effect/Deferred"
8
- import * as Effect from "effect/Effect"
9
- import type * as PubSub from "effect/PubSub"
10
13
  import * as Layer from "effect/Layer"
11
- import type * as Queue from "effect/Queue"
14
+ import type * as Option from "effect/Option"
12
15
  import * as Ref from "effect/Ref"
13
16
  import * as Schedule from "effect/Schedule"
14
- import { DiscordConfig } from "dfx/DiscordConfig"
15
- import type { RunningShard } from "dfx/DiscordGateway/Shard"
16
- import { ShardLive, Shard } from "dfx/DiscordGateway/Shard"
17
- import { ShardStore } from "dfx/DiscordGateway/ShardStore"
18
- import type { WebSocketCloseError, WebSocketError } from "dfx/DiscordGateway/WS"
19
- import { DiscordREST } from "dfx/DiscordREST"
20
- import { RateLimiterLive, RateLimiter } from "dfx/RateLimit"
21
- import type * as Discord from "dfx/types"
22
17
 
23
18
  const claimRepeatPolicy = Schedule.spaced("3 minutes").pipe(
24
19
  Schedule.whileInput((_: Option.Option<number>) => _._tag === "None"),
@@ -33,29 +28,6 @@ const make = Effect.gen(function* (_) {
33
28
  const shard = yield* _(Shard)
34
29
  const currentShards = yield* _(Ref.make(HashSet.empty<RunningShard>()))
35
30
 
36
- const takeConfig = (totalCount: number) =>
37
- Effect.gen(function* (_) {
38
- const currentCount = yield* _(Ref.make(0))
39
-
40
- const claimId = (
41
- sharderCount: number,
42
- ): Effect.Effect<never, never, number> =>
43
- pipe(
44
- store.claimId({
45
- totalCount,
46
- sharderCount,
47
- }),
48
- Effect.repeat(claimRepeatPolicy),
49
- Effect.map(_ => _.value),
50
- )
51
-
52
- return pipe(
53
- Ref.getAndUpdate(currentCount, _ => _ + 1),
54
- Effect.flatMap(claimId),
55
- Effect.map(id => ({ id, totalCount }) as const),
56
- )
57
- })
58
-
59
31
  const gateway = yield* _(
60
32
  rest.getGatewayBot(),
61
33
  Effect.flatMap(r => r.json),
@@ -73,68 +45,71 @@ const make = Effect.gen(function* (_) {
73
45
  ),
74
46
  )
75
47
 
76
- const run = (
77
- hub: PubSub.PubSub<Discord.GatewayPayload<Discord.ReceiveEvent>>,
78
- sendQueue: Queue.Dequeue<Discord.GatewayPayload<Discord.SendEvent>>,
79
- ) =>
80
- Effect.gen(function* (_) {
81
- const deferred = yield* _(
82
- Deferred.make<WebSocketError | WebSocketCloseError, never>(),
83
- )
84
- const take = yield* _(takeConfig(config.shardCount ?? gateway.shards))
85
-
86
- const spawner = pipe(
87
- take,
88
- Effect.map(config => ({
89
- ...config,
90
- url: gateway.url,
91
- concurrency: gateway.session_start_limit.max_concurrency,
92
- })),
93
- Effect.tap(({ concurrency, id }) =>
94
- limiter.maybeWait(
95
- `dfx.sharder.${id % concurrency}`,
96
- Duration.millis(config.identifyRateLimit[0]),
97
- config.identifyRateLimit[1],
98
- ),
99
- ),
100
- Effect.flatMap(c =>
101
- shard.connect([c.id, c.totalCount], hub, sendQueue),
102
- ),
103
- Effect.flatMap(shard =>
104
- Effect.acquireUseRelease(
105
- Ref.update(currentShards, HashSet.add(shard)),
106
- () => shard.run,
107
- () => Ref.update(currentShards, HashSet.remove(shard)),
108
- ).pipe(
109
- Effect.catchAllCause(_ => Deferred.failCause(deferred, _)),
110
- Effect.fork,
111
- ),
112
- ),
113
- Effect.forever,
114
- )
48
+ const totalCount = config.shardCount ?? gateway.shards
49
+ const currentCount = yield* _(Ref.make(0))
50
+ const claimId = (sharderCount: number): Effect.Effect<never, never, number> =>
51
+ pipe(
52
+ store.claimId({
53
+ totalCount,
54
+ sharderCount,
55
+ }),
56
+ Effect.repeat(claimRepeatPolicy),
57
+ Effect.map(_ => _.value),
58
+ )
59
+ const takeConfig = pipe(
60
+ Ref.getAndUpdate(currentCount, _ => _ + 1),
61
+ Effect.flatMap(claimId),
62
+ Effect.map(id => ({ id, totalCount }) as const),
63
+ )
115
64
 
116
- const spawners = Chunk.map(
117
- Chunk.range(1, gateway.session_start_limit.max_concurrency),
118
- () => spawner,
119
- )
65
+ const spawner = pipe(
66
+ takeConfig,
67
+ Effect.map(config => ({
68
+ ...config,
69
+ url: gateway.url,
70
+ concurrency: gateway.session_start_limit.max_concurrency,
71
+ })),
72
+ Effect.tap(({ concurrency, id }) =>
73
+ limiter.maybeWait(
74
+ `dfx.sharder.${id % concurrency}`,
75
+ Duration.millis(config.identifyRateLimit[0]),
76
+ config.identifyRateLimit[1],
77
+ ),
78
+ ),
79
+ Effect.flatMap(c => shard.connect([c.id, c.totalCount])),
80
+ Effect.flatMap(shard => Ref.update(currentShards, HashSet.add(shard))),
81
+ Effect.forever,
82
+ )
120
83
 
121
- return yield* _(
122
- Effect.all(
123
- [
124
- Effect.all(spawners, { concurrency: "unbounded", discard: true }),
125
- Deferred.await(deferred),
126
- ],
127
- { concurrency: "unbounded", discard: true },
128
- ) as Effect.Effect<never, WebSocketError | WebSocketCloseError, never>,
129
- )
130
- })
84
+ yield* _(
85
+ Effect.replicateEffect(
86
+ spawner,
87
+ gateway.session_start_limit.max_concurrency,
88
+ { concurrency: "unbounded", discard: true },
89
+ ),
90
+ Effect.scoped,
91
+ Effect.catchAllCause(Effect.logError),
92
+ Effect.ensuring(Ref.set(currentShards, HashSet.empty())),
93
+ Effect.forever,
94
+ Effect.forkScoped,
95
+ )
131
96
 
132
- return { shards: Ref.get(currentShards), run } as const
133
- })
97
+ return { shards: Ref.get(currentShards) } as const
98
+ }).pipe(
99
+ Effect.annotateLogs({
100
+ package: "dfx",
101
+ module: "DiscordGateway/Sharder",
102
+ }),
103
+ )
134
104
 
135
- export interface Sharder extends Effect.Effect.Success<typeof make> {}
136
- export const Sharder = Tag<Sharder>()
137
- export const SharedLive = Layer.provide(
138
- Layer.effect(Sharder, make),
139
- Layer.merge(RateLimiterLive, ShardLive),
105
+ export interface Sharder {
106
+ readonly _: unique symbol
107
+ }
108
+ export const Sharder = Tag<Sharder, Effect.Effect.Success<typeof make>>(
109
+ "dfx/DiscordGateway/Sharder",
110
+ )
111
+ export const SharderLive = Layer.scoped(Sharder, make).pipe(
112
+ Layer.provide(DiscordRESTLive),
113
+ Layer.provide(RateLimiterLive),
114
+ Layer.provide(ShardLive),
140
115
  )