dfx 0.42.2 → 0.42.4

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 (97) hide show
  1. package/Cache/driver.js.map +1 -1
  2. package/Cache/memory.js.map +1 -1
  3. package/Cache/memoryTTL.js.map +1 -1
  4. package/Cache/prelude.js.map +1 -1
  5. package/Cache.js.map +1 -1
  6. package/DiscordConfig.js.map +1 -1
  7. package/DiscordGateway/DiscordWS.js.map +1 -1
  8. package/DiscordGateway/Shard/heartbeats.js.map +1 -1
  9. package/DiscordGateway/Shard/identify.js.map +1 -1
  10. package/DiscordGateway/Shard/invalidSession.js.map +1 -1
  11. package/DiscordGateway/Shard/sendEvents.js.map +1 -1
  12. package/DiscordGateway/Shard/utils.js.map +1 -1
  13. package/DiscordGateway/Shard.js.map +1 -1
  14. package/DiscordGateway/ShardStore.js.map +1 -1
  15. package/DiscordGateway/Sharder.js.map +1 -1
  16. package/DiscordGateway/WS.js +11 -14
  17. package/DiscordGateway/WS.js.map +1 -1
  18. package/DiscordGateway.js.map +1 -1
  19. package/DiscordREST/types.js.map +1 -1
  20. package/DiscordREST/utils.js.map +1 -1
  21. package/DiscordREST.js.map +1 -1
  22. package/Helpers/flags.js.map +1 -1
  23. package/Helpers/intents.js.map +1 -1
  24. package/Helpers/interactions.js.map +1 -1
  25. package/Helpers/members.js.map +1 -1
  26. package/Helpers/permissions.js.map +1 -1
  27. package/Helpers/ui.js.map +1 -1
  28. package/Interactions/context.js.map +1 -1
  29. package/Interactions/definitions.js.map +1 -1
  30. package/Interactions/gateway.js.map +1 -1
  31. package/Interactions/handlers.js.map +1 -1
  32. package/Interactions/index.js.map +1 -1
  33. package/Interactions/utils.js.map +1 -1
  34. package/Interactions/webhook.js.map +1 -1
  35. package/Log.js.map +1 -1
  36. package/RateLimit/memory.js.map +1 -1
  37. package/RateLimit/utils.js.map +1 -1
  38. package/RateLimit.js.map +1 -1
  39. package/_common.js.map +1 -1
  40. package/gateway.js.map +1 -1
  41. package/global.js.map +1 -1
  42. package/index.js.map +1 -1
  43. package/package.json +50 -52
  44. package/src/Cache/driver.ts +31 -0
  45. package/src/Cache/memory.ts +76 -0
  46. package/src/Cache/memoryTTL.ts +201 -0
  47. package/src/Cache/prelude.ts +215 -0
  48. package/src/Cache.ts +140 -0
  49. package/src/DiscordConfig.ts +48 -0
  50. package/src/DiscordGateway/DiscordWS.ts +74 -0
  51. package/src/DiscordGateway/Shard/heartbeats.ts +42 -0
  52. package/src/DiscordGateway/Shard/identify.ts +52 -0
  53. package/src/DiscordGateway/Shard/invalidSession.ts +10 -0
  54. package/src/DiscordGateway/Shard/sendEvents.ts +37 -0
  55. package/src/DiscordGateway/Shard/utils.ts +14 -0
  56. package/src/DiscordGateway/Shard.ts +152 -0
  57. package/src/DiscordGateway/ShardStore.ts +33 -0
  58. package/src/DiscordGateway/Sharder.ts +102 -0
  59. package/src/DiscordGateway/WS.ts +118 -0
  60. package/src/DiscordGateway.ts +43 -0
  61. package/src/DiscordREST/types.ts +13 -0
  62. package/src/DiscordREST/utils.ts +33 -0
  63. package/src/DiscordREST.ts +203 -0
  64. package/src/Helpers/flags.ts +68 -0
  65. package/src/Helpers/intents.ts +34 -0
  66. package/src/Helpers/interactions.ts +229 -0
  67. package/src/Helpers/members.ts +14 -0
  68. package/src/Helpers/permissions.ts +140 -0
  69. package/src/Helpers/ui.ts +103 -0
  70. package/src/Interactions/context.ts +132 -0
  71. package/src/Interactions/definitions.ts +309 -0
  72. package/src/Interactions/gateway.ts +71 -0
  73. package/src/Interactions/handlers.ts +130 -0
  74. package/src/Interactions/index.ts +108 -0
  75. package/src/Interactions/utils.ts +81 -0
  76. package/src/Interactions/webhook.ts +110 -0
  77. package/src/Log.ts +17 -0
  78. package/src/RateLimit/memory.ts +57 -0
  79. package/src/RateLimit/utils.ts +27 -0
  80. package/src/RateLimit.ts +69 -0
  81. package/src/_common.ts +43 -0
  82. package/src/gateway.ts +38 -0
  83. package/src/global.ts +45 -0
  84. package/src/index.ts +20 -0
  85. package/src/types.ts +6368 -0
  86. package/src/utils/effect.ts +0 -0
  87. package/src/utils/hub.ts +47 -0
  88. package/src/utils/json.d.ts +1 -0
  89. package/src/utils/tsplus.ts +10 -0
  90. package/src/webhooks.ts +41 -0
  91. package/tsconfig.json +23 -0
  92. package/tsplus.config.json +8 -0
  93. package/types.js.map +1 -1
  94. package/utils/effect.js.map +1 -1
  95. package/utils/hub.js.map +1 -1
  96. package/utils/tsplus.js.map +1 -1
  97. package/webhooks.js.map +1 -1
package/package.json CHANGED
@@ -1,54 +1,52 @@
1
1
  {
2
- "name": "dfx",
3
- "version": "0.42.2",
4
- "type": "module",
5
- "publishConfig": {
6
- "access": "public",
7
- "directory": "dist"
8
- },
9
- "description": "Effect-TS discord library",
10
- "author": "Tim Smart <hello@timsmart.co>",
11
- "repository": {
12
- "type": "git",
13
- "url": "https://github.com/tim-smart/dfx.git"
14
- },
15
- "license": "MIT",
16
- "scripts": {
17
- "prepublishOnly": "pnpm run clean && pnpm run build:tsc && cp package.json README.md dist/",
18
- "build:tsc": "tsc -p tsconfig.json",
19
- "types": "discord-api-codegen ./discord-api-docs -l typescript -o 'imports=RestResponse|dfx/DiscordREST/types' 'endpointReturnType=RestResponse' > src/types.ts && prettier -w src/types.ts",
20
- "clean": "rm -rf dist/ *.tsbuildinfo"
21
- },
22
- "exports": {
23
- ".": "./index.js",
24
- "./gateway": "./gateway.js",
25
- "./webhooks": "./webhooks.js",
26
- "./*": "./*.js"
27
- },
28
- "devDependencies": {
29
- "@tim-smart/discord-api-docs-parser": "^0.5.2",
30
- "@tsplus-types/effect__data": "0.12.2-3b576ba",
31
- "@tsplus-types/effect__io": "0.25.8-3b576ba",
32
- "@tsplus-types/effect__stream": "0.21.0-3b576ba",
33
- "@types/ws": "^8.5.4",
34
- "dotenv": "^16.0.3",
35
- "lerna": "^6.6.1",
36
- "madge": "^6.0.0",
37
- "typescript": "https://cdn.jsdelivr.net/npm/@tsplus/installer@0.0.171/compiler/typescript.tgz"
38
- },
39
- "dependencies": {
40
- "@effect-http/client": "^0.24.2",
41
- "@effect/data": "^0.12.2",
42
- "@effect/io": "~0.25.8",
43
- "@effect/stream": "~0.21.0",
44
- "tweetnacl": "^1.0.3"
45
- },
46
- "optionalDependencies": {
47
- "bufferutil": "^4.0.7",
48
- "isomorphic-ws": "^5.0.0",
49
- "utf-8-validate": "^6.0.3",
50
- "ws": "^8.13.0"
51
- },
52
- "sideEffects": false,
53
- "gitHead": "3885d0874380e6814794f3b287e0b706cd3ff0af"
2
+ "name": "dfx",
3
+ "version": "0.42.4",
4
+ "type": "module",
5
+ "publishConfig": {
6
+ "access": "public",
7
+ "directory": "dist"
8
+ },
9
+ "description": "Effect-TS discord library",
10
+ "author": "Tim Smart <hello@timsmart.co>",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/tim-smart/dfx.git"
14
+ },
15
+ "license": "MIT",
16
+ "scripts": {
17
+ "prepublishOnly": "make build",
18
+ "types": "discord-api-codegen ./discord-api-docs -l typescript -o 'imports=RestResponse|dfx/DiscordREST/types' 'endpointReturnType=RestResponse' > src/types.ts && prettier -w src/types.ts"
19
+ },
20
+ "exports": {
21
+ ".": "./index.js",
22
+ "./gateway": "./gateway.js",
23
+ "./webhooks": "./webhooks.js",
24
+ "./*": "./*.js"
25
+ },
26
+ "devDependencies": {
27
+ "@tim-smart/discord-api-docs-parser": "^0.5.2",
28
+ "@tsplus-types/effect__data": "0.12.2-3b576ba",
29
+ "@tsplus-types/effect__io": "0.25.8-3b576ba",
30
+ "@tsplus-types/effect__stream": "0.21.1-3b576ba",
31
+ "@types/ws": "^8.5.4",
32
+ "dotenv": "^16.0.3",
33
+ "lerna": "^6.6.1",
34
+ "madge": "^6.0.0",
35
+ "typescript": "https://cdn.jsdelivr.net/npm/@tsplus/installer@0.0.171/compiler/typescript.tgz"
36
+ },
37
+ "dependencies": {
38
+ "@effect-http/client": "^0.24.2",
39
+ "@effect/data": "^0.12.2",
40
+ "@effect/io": "~0.25.8",
41
+ "@effect/stream": "~0.21.1",
42
+ "tweetnacl": "^1.0.3"
43
+ },
44
+ "optionalDependencies": {
45
+ "bufferutil": "^4.0.7",
46
+ "isomorphic-ws": "^5.0.0",
47
+ "utf-8-validate": "^6.0.3",
48
+ "ws": "^8.13.0"
49
+ },
50
+ "sideEffects": false,
51
+ "gitHead": "b126c63501e8a26a235c2eec43c8332c6dde5f5c"
54
52
  }
@@ -0,0 +1,31 @@
1
+ export interface ParentCacheDriver<E, T> {
2
+ readonly size: Effect<never, E, number>
3
+ sizeForParent: (parentId: string) => Effect<never, E, number>
4
+ get: (parentId: string, resourceId: string) => Effect<never, E, Maybe<T>>
5
+ getForParent: (
6
+ parentId: string,
7
+ ) => Effect<never, E, Maybe<ReadonlyMap<string, T>>>
8
+ set: (
9
+ parentId: string,
10
+ resourceId: string,
11
+ resource: T,
12
+ ) => Effect<never, E, void>
13
+ delete: (parentId: string, resourceId: string) => Effect<never, E, void>
14
+ parentDelete: (parentId: string) => Effect<never, E, void>
15
+ refreshTTL: (parentId: string, resourceId: string) => Effect<never, E, void>
16
+ readonly run: Effect<never, E, never>
17
+ }
18
+
19
+ export const createParentDriver = <E, T>(driver: ParentCacheDriver<E, T>) =>
20
+ driver
21
+
22
+ export interface CacheDriver<E, T> {
23
+ readonly size: Effect<never, E, number>
24
+ get: (resourceId: string) => Effect<never, E, Maybe<T>>
25
+ set: (resourceId: string, resource: T) => Effect<never, E, void>
26
+ delete: (resourceId: string) => Effect<never, E, void>
27
+ refreshTTL: (resourceId: string) => Effect<never, E, void>
28
+ readonly run: Effect<never, E, never>
29
+ }
30
+
31
+ export const createDriver = <E, T>(driver: CacheDriver<E, T>) => driver
@@ -0,0 +1,76 @@
1
+ import { createDriver, createParentDriver } from "./driver.js"
2
+
3
+ export const createWithParent = <T>() =>
4
+ Effect.sync(() => {
5
+ const map = new Map<string, Map<string, T>>()
6
+
7
+ return createParentDriver({
8
+ size: Effect.sync(() => {
9
+ let count = 0
10
+ for (const a of map.values()) {
11
+ count += a.size
12
+ }
13
+ return count
14
+ }),
15
+
16
+ sizeForParent: parentId =>
17
+ Effect.sync(() => map.get(parentId)?.size ?? 0),
18
+
19
+ get: (parentId, resourceId) =>
20
+ Effect.sync(
21
+ (): Maybe<T> =>
22
+ Maybe.fromNullable(map.get(parentId)?.get(resourceId)),
23
+ ),
24
+
25
+ getForParent: parentId =>
26
+ Effect.sync(() => Maybe.fromNullable(map.get(parentId))),
27
+
28
+ set: (parentId, resourceId, resource) =>
29
+ Effect.sync(() => {
30
+ if (!map.has(parentId)) {
31
+ map.set(parentId, new Map())
32
+ }
33
+ map.get(parentId)!.set(resourceId, resource)
34
+ }),
35
+
36
+ delete: (parentId, resourceId) =>
37
+ Effect.sync(() => {
38
+ map.get(parentId)?.delete(resourceId)
39
+ }),
40
+
41
+ parentDelete: parentId =>
42
+ Effect.sync(() => {
43
+ map.delete(parentId)
44
+ }),
45
+
46
+ refreshTTL: () => Effect.unit(),
47
+
48
+ run: Effect.never(),
49
+ })
50
+ })
51
+
52
+ export const create = <T>() =>
53
+ Effect.sync(() => {
54
+ const map = new Map<string, T>()
55
+
56
+ return createDriver({
57
+ size: Effect.sync(() => map.size),
58
+
59
+ get: resourceId =>
60
+ Effect.sync((): Maybe<T> => Maybe.fromNullable(map.get(resourceId))),
61
+
62
+ set: (resourceId, resource) =>
63
+ Effect.sync(() => {
64
+ map.set(resourceId, resource)
65
+ }),
66
+
67
+ delete: resourceId =>
68
+ Effect.sync(() => {
69
+ map.delete(resourceId)
70
+ }),
71
+
72
+ refreshTTL: () => Effect.unit(),
73
+
74
+ run: Effect.never(),
75
+ })
76
+ })
@@ -0,0 +1,201 @@
1
+ import { createDriver, createParentDriver } from "./driver.js"
2
+
3
+ export interface MemoryTTLOpts {
4
+ /** The approx. number of milliseconds to keep items */
5
+ ttl: Duration
6
+
7
+ /**
8
+ * How often items should be cleared.
9
+ */
10
+ resolution?: Duration
11
+
12
+ /**
13
+ * What sweep strategy to use.
14
+ *
15
+ * "activity" means the TTL is reset for every `set` OR `get` operation
16
+ * "usage" means the TTL is only reset for the `get` operation
17
+ *
18
+ * Defaults to "usage"
19
+ */
20
+ strategy?: "activity" | "usage" | "expiry"
21
+ }
22
+
23
+ interface CacheItem<T> {
24
+ resource: T
25
+ }
26
+
27
+ interface TTLBucket<T> {
28
+ expires: number
29
+ items: CacheItem<T>[]
30
+ }
31
+
32
+ const make = <T>({
33
+ ttl,
34
+ resolution = Duration.minutes(1),
35
+ strategy = "usage",
36
+ }: MemoryTTLOpts) => {
37
+ const additionalMilliseconds =
38
+ (Math.floor(ttl.millis / resolution.millis) + 1) * resolution.millis
39
+
40
+ const items = new Map<string, WeakRef<CacheItem<T>>>()
41
+ const buckets: TTLBucket<T>[] = []
42
+
43
+ const refreshTTL = (item: CacheItem<T>) => {
44
+ const now = Date.now()
45
+ const remainder = now % resolution.millis
46
+ const expires = now - remainder + additionalMilliseconds
47
+ let currentBucket = buckets[buckets.length - 1]
48
+
49
+ if ((currentBucket?.expires || 0) < expires) {
50
+ currentBucket = {
51
+ expires,
52
+ items: [],
53
+ }
54
+ buckets.push(currentBucket)
55
+ }
56
+
57
+ currentBucket.items.push(item)
58
+ }
59
+
60
+ const sweep = () => {
61
+ const now = Date.now()
62
+ const remainder = now % resolution.millis
63
+ const currentExpires = now - remainder
64
+
65
+ while (buckets.length && buckets[0].expires <= currentExpires) {
66
+ buckets.shift()!
67
+ }
68
+
69
+ if (global.gc) {
70
+ global.gc()
71
+ }
72
+ }
73
+
74
+ const getSync = (resourceId: string) => {
75
+ const ref = items.get(resourceId)
76
+ if (!ref) return undefined
77
+
78
+ const item = ref.deref()
79
+ if (!item) {
80
+ items.delete(resourceId)
81
+ return undefined
82
+ }
83
+
84
+ if (strategy !== "expiry") {
85
+ refreshTTL(item)
86
+ }
87
+
88
+ return item.resource
89
+ }
90
+
91
+ return createDriver({
92
+ size: Effect.sync(() => items.size),
93
+
94
+ get: resourceId =>
95
+ Effect.sync((): Maybe<T> => Maybe.fromNullable(getSync(resourceId))),
96
+
97
+ refreshTTL: id =>
98
+ Effect.sync(() => {
99
+ getSync(id)
100
+ }),
101
+
102
+ set: (resourceId, resource) =>
103
+ Effect.sync(() => {
104
+ const item = items.get(resourceId)?.deref()
105
+
106
+ if (item && strategy !== "activity") {
107
+ item.resource = resource
108
+ } else {
109
+ const newItem = { resource }
110
+ refreshTTL(newItem)
111
+ items.set(resourceId, new WeakRef(newItem))
112
+ }
113
+ }),
114
+
115
+ delete: resourceId =>
116
+ Effect.sync(() => {
117
+ items.delete(resourceId)
118
+ }),
119
+
120
+ run: Effect.sync(sweep).delay(resolution * 0.5).forever,
121
+ })
122
+ }
123
+
124
+ export const create = <T>(opts: MemoryTTLOpts) =>
125
+ Effect.sync(() => make<T>(opts))
126
+
127
+ export const createWithParent = <T>(opts: MemoryTTLOpts) =>
128
+ Effect.sync(() => {
129
+ const store = make<T>(opts)
130
+ const parentIds = new Map<string, Set<string>>()
131
+
132
+ return createParentDriver({
133
+ size: store.size,
134
+ sizeForParent: parentId =>
135
+ Effect.sync(() => parentIds.get(parentId)?.size ?? 0),
136
+
137
+ refreshTTL: (_, id) => store.refreshTTL(id),
138
+
139
+ get: (_, id) => store.get(id),
140
+
141
+ getForParent: parentId =>
142
+ Do($ => {
143
+ const ids = parentIds.get(parentId)
144
+ if (!ids) return Maybe.none()
145
+
146
+ const toGet: Effect<never, never, readonly [string, Maybe<T>]>[] = []
147
+ ids.forEach(id => {
148
+ toGet.push(
149
+ Do($ => {
150
+ const item = $(store.get(id))
151
+ if (item._tag === "None") {
152
+ parentIds.delete(id)
153
+ }
154
+ return [id, item] as const
155
+ }),
156
+ )
157
+ })
158
+
159
+ const results = $(Effect.allPar(toGet))
160
+ const map = results.reduce(
161
+ (map, [id, a]) => (a._tag === "Some" ? map.set(id, a.value) : map),
162
+ new Map<string, T>(),
163
+ )
164
+
165
+ return Maybe.some(map)
166
+ }),
167
+
168
+ set: (parentId, resourceId, resource) =>
169
+ Do($ => {
170
+ $(store.set(resourceId, resource))
171
+
172
+ if (!parentIds.has(parentId)) {
173
+ parentIds.set(parentId, new Set())
174
+ }
175
+ parentIds.get(parentId)!.add(resourceId)
176
+ }),
177
+
178
+ delete: (parentId, resourceId) =>
179
+ Do($ => {
180
+ $(store.delete(resourceId))
181
+ parentIds.get(parentId)?.delete(resourceId)
182
+ }),
183
+
184
+ parentDelete: parentId =>
185
+ Do($ => {
186
+ const ids = parentIds.get(parentId)
187
+ parentIds.delete(parentId)
188
+
189
+ const effects: Effect<never, never, void>[] = []
190
+ if (ids) {
191
+ ids.forEach(id => {
192
+ effects.push(store.delete(id))
193
+ })
194
+ }
195
+
196
+ $(Effect.allParDiscard(effects))
197
+ }),
198
+
199
+ run: store.run,
200
+ })
201
+ })
@@ -0,0 +1,215 @@
1
+ import { DiscordREST } from "dfx"
2
+ import { Discord, Effect, Stream } from "dfx/_common"
3
+ import { DiscordGateway } from "dfx/gateway"
4
+ import {
5
+ CacheDriver,
6
+ CacheMissError,
7
+ CacheOp,
8
+ ParentCacheDriver,
9
+ ParentCacheOp,
10
+ make,
11
+ makeWithParent,
12
+ } from "../Cache.js"
13
+
14
+ export interface OptsWithParentOptions<E, A> {
15
+ id: (a: A) => string
16
+ fromParent: Stream<never, E, [parentId: string, resources: A[]]>
17
+ create: Stream<never, E, [parentId: string, resource: A]>
18
+ update: Stream<never, E, [parentId: string, resource: A]>
19
+ remove: Stream<never, E, [parentId: string, id: string]>
20
+ parentRemove: Stream<never, E, string>
21
+ }
22
+
23
+ export const opsWithParent = <E, T>({
24
+ id,
25
+ fromParent,
26
+ create,
27
+ update,
28
+ remove,
29
+ parentRemove,
30
+ }: OptsWithParentOptions<E, T>) => {
31
+ const fromParentOps = fromParent.flatMap(([parentId, a]) =>
32
+ Stream.fromIterable(
33
+ a.map(
34
+ (resource): ParentCacheOp<T> => ({
35
+ op: "create",
36
+ parentId,
37
+ resourceId: id(resource),
38
+ resource,
39
+ }),
40
+ ),
41
+ ),
42
+ )
43
+
44
+ const createOps = create.map(
45
+ ([parentId, resource]): ParentCacheOp<T> => ({
46
+ op: "create",
47
+ parentId,
48
+ resourceId: id(resource),
49
+ resource,
50
+ }),
51
+ )
52
+
53
+ const updateOps = update.map(
54
+ ([parentId, resource]): ParentCacheOp<T> => ({
55
+ op: "update",
56
+ parentId,
57
+ resourceId: id(resource),
58
+ resource,
59
+ }),
60
+ )
61
+
62
+ const removeOps = remove.map(
63
+ ([parentId, resourceId]): ParentCacheOp<T> => ({
64
+ op: "delete",
65
+ parentId,
66
+ resourceId,
67
+ }),
68
+ )
69
+
70
+ const parentRemoveOps = parentRemove.map(
71
+ (parentId): ParentCacheOp<T> => ({
72
+ op: "parentDelete",
73
+ parentId,
74
+ }),
75
+ )
76
+
77
+ return fromParentOps
78
+ .merge(createOps)
79
+ .merge(updateOps)
80
+ .merge(removeOps)
81
+ .merge(parentRemoveOps)
82
+ }
83
+
84
+ export interface OpsOptions<E, A> {
85
+ id: (a: A) => string
86
+ create: Stream<never, E, A>
87
+ update: Stream<never, E, A>
88
+ remove: Stream<never, E, string>
89
+ }
90
+
91
+ export const ops = <E, T>({ id, create, update, remove }: OpsOptions<E, T>) => {
92
+ const createOps = create.map(
93
+ (resource): CacheOp<T> => ({
94
+ op: "create",
95
+ resourceId: id(resource),
96
+ resource,
97
+ }),
98
+ )
99
+
100
+ const updateOps = update.map(
101
+ (resource): CacheOp<T> => ({
102
+ op: "update",
103
+ resourceId: id(resource),
104
+ resource,
105
+ }),
106
+ )
107
+
108
+ const removeOps = remove.map(
109
+ (resourceId): CacheOp<T> => ({
110
+ op: "delete",
111
+ resourceId,
112
+ }),
113
+ )
114
+
115
+ return createOps.merge(updateOps).merge(removeOps)
116
+ }
117
+
118
+ export const guilds = <RM, EM, E>(
119
+ makeDriver: Effect<RM, EM, CacheDriver<E, Discord.Guild>>,
120
+ ) =>
121
+ Do($ => {
122
+ const driver = $(makeDriver)
123
+ const gateway = $(DiscordGateway)
124
+ const rest = $(DiscordREST)
125
+
126
+ return make({
127
+ driver,
128
+ id: _ => _.id,
129
+ ops: ops({
130
+ id: (g: Discord.Guild) => g.id,
131
+ create: gateway.fromDispatch("GUILD_CREATE").map(g => ({
132
+ ...g,
133
+ channels: [],
134
+ roles: [],
135
+ emojis: [],
136
+ members: [],
137
+ })),
138
+ update: gateway.fromDispatch("GUILD_UPDATE"),
139
+ remove: gateway.fromDispatch("GUILD_DELETE").map(a => a.id),
140
+ }),
141
+ onMiss: id => rest.getGuild(id).flatMap(r => r.json),
142
+ })
143
+ })
144
+
145
+ export const channels = <RM, EM, E>(
146
+ makeDriver: Effect<RM, EM, ParentCacheDriver<E, Discord.Channel>>,
147
+ ) =>
148
+ Do($ => {
149
+ const driver = $(makeDriver)
150
+ const gateway = $(DiscordGateway)
151
+ const rest = $(DiscordREST)
152
+
153
+ return makeWithParent({
154
+ driver,
155
+ id: _ => Effect.succeed([_.guild_id!, _.id]),
156
+ ops: opsWithParent({
157
+ id: (a: Discord.Channel) => a.id,
158
+ fromParent: gateway
159
+ .fromDispatch("GUILD_CREATE")
160
+ .map(g => [g.id, g.channels]),
161
+ create: gateway
162
+ .fromDispatch("CHANNEL_CREATE")
163
+ .map(c => [c.guild_id!, c]),
164
+ update: gateway
165
+ .fromDispatch("CHANNEL_UPDATE")
166
+ .map(c => [c.guild_id!, c]),
167
+ remove: gateway
168
+ .fromDispatch("CHANNEL_DELETE")
169
+ .map(a => [a.guild_id!, a.id]),
170
+ parentRemove: gateway.fromDispatch("GUILD_DELETE").map(g => g.id),
171
+ }),
172
+ onMiss: (_, id) => rest.getChannel(id).flatMap(r => r.json),
173
+ onParentMiss: guildId =>
174
+ rest
175
+ .getGuildChannels(guildId)
176
+ .flatMap(r => r.json)
177
+ .map(a => a.map(a => [a.id, a])),
178
+ })
179
+ })
180
+
181
+ export const roles = <RM, EM, E>(
182
+ makeDriver: Effect<RM, EM, ParentCacheDriver<E, Discord.Role>>,
183
+ ) =>
184
+ Do($ => {
185
+ const driver = $(makeDriver)
186
+ const gateway = $(DiscordGateway)
187
+ const rest = $(DiscordREST)
188
+
189
+ return makeWithParent({
190
+ driver,
191
+ id: _ => Effect.fail(new CacheMissError("RolesCache/id", _.id)),
192
+ ops: opsWithParent({
193
+ id: (a: Discord.Role) => a.id,
194
+ fromParent: gateway
195
+ .fromDispatch("GUILD_CREATE")
196
+ .map(g => [g.id, g.roles]),
197
+ create: gateway
198
+ .fromDispatch("GUILD_ROLE_CREATE")
199
+ .map(r => [r.guild_id, r.role]),
200
+ update: gateway
201
+ .fromDispatch("GUILD_ROLE_UPDATE")
202
+ .map(r => [r.guild_id, r.role]),
203
+ remove: gateway
204
+ .fromDispatch("GUILD_ROLE_DELETE")
205
+ .map(r => [r.guild_id, r.role_id]),
206
+ parentRemove: gateway.fromDispatch("GUILD_DELETE").map(g => g.id),
207
+ }),
208
+ onMiss: (_, id) => Effect.fail(new CacheMissError("RolesCache", id)),
209
+ onParentMiss: guildId =>
210
+ rest
211
+ .getGuildRoles(guildId)
212
+ .flatMap(r => r.json)
213
+ .map(_ => _.map(role => [role.id, role])),
214
+ })
215
+ })