@wolfstar/plugin-cache 0.0.0 → 0.1.0-next-20260926145943
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/LICENSE +202 -202
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
package/LICENSE
CHANGED
|
@@ -1,202 +1,202 @@
|
|
|
1
|
-
|
|
2
|
-
Apache License
|
|
3
|
-
Version 2.0, January 2004
|
|
4
|
-
http://www.apache.org/licenses/
|
|
5
|
-
|
|
6
|
-
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
-
|
|
8
|
-
1. Definitions.
|
|
9
|
-
|
|
10
|
-
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
-
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
-
|
|
13
|
-
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
-
the copyright owner that is granting the License.
|
|
15
|
-
|
|
16
|
-
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
-
other entities that control, are controlled by, or are under common
|
|
18
|
-
control with that entity. For the purposes of this definition,
|
|
19
|
-
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
-
direction or management of such entity, whether by contract or
|
|
21
|
-
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
-
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
-
|
|
24
|
-
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
-
exercising permissions granted by this License.
|
|
26
|
-
|
|
27
|
-
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
-
including but not limited to software source code, documentation
|
|
29
|
-
source, and configuration files.
|
|
30
|
-
|
|
31
|
-
"Object" form shall mean any form resulting from mechanical
|
|
32
|
-
transformation or translation of a Source form, including but
|
|
33
|
-
not limited to compiled object code, generated documentation,
|
|
34
|
-
and conversions to other media types.
|
|
35
|
-
|
|
36
|
-
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
-
Object form, made available under the License, as indicated by a
|
|
38
|
-
copyright notice that is included in or attached to the work
|
|
39
|
-
(an example is provided in the Appendix below).
|
|
40
|
-
|
|
41
|
-
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
-
form, that is based on (or derived from) the Work and for which the
|
|
43
|
-
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
-
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
-
of this License, Derivative Works shall not include works that remain
|
|
46
|
-
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
-
the Work and Derivative Works thereof.
|
|
48
|
-
|
|
49
|
-
"Contribution" shall mean any work of authorship, including
|
|
50
|
-
the original version of the Work and any modifications or additions
|
|
51
|
-
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
-
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
-
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
-
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
-
means any form of electronic, verbal, or written communication sent
|
|
56
|
-
to the Licensor or its representatives, including but not limited to
|
|
57
|
-
communication on electronic mailing lists, source code control systems,
|
|
58
|
-
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
-
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
-
excluding communication that is conspicuously marked or otherwise
|
|
61
|
-
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
-
|
|
63
|
-
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
-
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
-
subsequently incorporated within the Work.
|
|
66
|
-
|
|
67
|
-
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
-
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
-
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
-
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
-
Work and such Derivative Works in Source or Object form.
|
|
73
|
-
|
|
74
|
-
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
-
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
-
(except as stated in this section) patent license to make, have made,
|
|
78
|
-
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
-
where such license applies only to those patent claims licensable
|
|
80
|
-
by such Contributor that are necessarily infringed by their
|
|
81
|
-
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
-
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
-
institute patent litigation against any entity (including a
|
|
84
|
-
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
-
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
-
or contributory patent infringement, then any patent licenses
|
|
87
|
-
granted to You under this License for that Work shall terminate
|
|
88
|
-
as of the date such litigation is filed.
|
|
89
|
-
|
|
90
|
-
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
-
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
-
modifications, and in Source or Object form, provided that You
|
|
93
|
-
meet the following conditions:
|
|
94
|
-
|
|
95
|
-
(a) You must give any other recipients of the Work or
|
|
96
|
-
Derivative Works a copy of this License; and
|
|
97
|
-
|
|
98
|
-
(b) You must cause any modified files to carry prominent notices
|
|
99
|
-
stating that You changed the files; and
|
|
100
|
-
|
|
101
|
-
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
-
that You distribute, all copyright, patent, trademark, and
|
|
103
|
-
attribution notices from the Source form of the Work,
|
|
104
|
-
excluding those notices that do not pertain to any part of
|
|
105
|
-
the Derivative Works; and
|
|
106
|
-
|
|
107
|
-
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
-
distribution, then any Derivative Works that You distribute must
|
|
109
|
-
include a readable copy of the attribution notices contained
|
|
110
|
-
within such NOTICE file, excluding those notices that do not
|
|
111
|
-
pertain to any part of the Derivative Works, in at least one
|
|
112
|
-
of the following places: within a NOTICE text file distributed
|
|
113
|
-
as part of the Derivative Works; within the Source form or
|
|
114
|
-
documentation, if provided along with the Derivative Works; or,
|
|
115
|
-
within a display generated by the Derivative Works, if and
|
|
116
|
-
wherever such third-party notices normally appear. The contents
|
|
117
|
-
of the NOTICE file are for informational purposes only and
|
|
118
|
-
do not modify the License. You may add Your own attribution
|
|
119
|
-
notices within Derivative Works that You distribute, alongside
|
|
120
|
-
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
-
that such additional attribution notices cannot be construed
|
|
122
|
-
as modifying the License.
|
|
123
|
-
|
|
124
|
-
You may add Your own copyright statement to Your modifications and
|
|
125
|
-
may provide additional or different license terms and conditions
|
|
126
|
-
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
-
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
-
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
-
the conditions stated in this License.
|
|
130
|
-
|
|
131
|
-
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
-
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
-
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
-
this License, without any additional terms or conditions.
|
|
135
|
-
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
-
the terms of any separate license agreement you may have executed
|
|
137
|
-
with Licensor regarding such Contributions.
|
|
138
|
-
|
|
139
|
-
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
-
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
-
except as required for reasonable and customary use in describing the
|
|
142
|
-
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
-
|
|
144
|
-
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
-
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
-
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
-
implied, including, without limitation, any warranties or conditions
|
|
149
|
-
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
-
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
-
appropriateness of using or redistributing the Work and assume any
|
|
152
|
-
risks associated with Your exercise of permissions under this License.
|
|
153
|
-
|
|
154
|
-
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
-
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
-
unless required by applicable law (such as deliberate and grossly
|
|
157
|
-
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
-
liable to You for damages, including any direct, indirect, special,
|
|
159
|
-
incidental, or consequential damages of any character arising as a
|
|
160
|
-
result of this License or out of the use or inability to use the
|
|
161
|
-
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
-
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
-
other commercial damages or losses), even if such Contributor
|
|
164
|
-
has been advised of the possibility of such damages.
|
|
165
|
-
|
|
166
|
-
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
-
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
-
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
-
or other liability obligations and/or rights consistent with this
|
|
170
|
-
License. However, in accepting such obligations, You may act only
|
|
171
|
-
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
-
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
-
defend, and hold each Contributor harmless for any liability
|
|
174
|
-
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
-
of your accepting any such warranty or additional liability.
|
|
176
|
-
|
|
177
|
-
END OF TERMS AND CONDITIONS
|
|
178
|
-
|
|
179
|
-
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
-
|
|
181
|
-
To apply the Apache License to your work, attach the following
|
|
182
|
-
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
-
replaced with your own identifying information. (Don't include
|
|
184
|
-
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
-
comment syntax for the file format. We also recommend that a
|
|
186
|
-
file or class name and description of purpose be included on the
|
|
187
|
-
same "printed page" as the copyright notice for easier
|
|
188
|
-
identification within third-party archives.
|
|
189
|
-
|
|
190
|
-
Copyright [yyyy] [name of copyright owner]
|
|
191
|
-
|
|
192
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
-
you may not use this file except in compliance with the License.
|
|
194
|
-
You may obtain a copy of the License at
|
|
195
|
-
|
|
196
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
-
|
|
198
|
-
Unless required by applicable law or agreed to in writing, software
|
|
199
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
-
See the License for the specific language governing permissions and
|
|
202
|
-
limitations under the License.
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/lib/keys.ts","../../src/lib/reactions.ts","../../src/lib/operations.ts","../../src/lib/gateway.ts","../../src/lib/memory.ts","../../src/lib/redis.ts"],"sourcesContent":["import type { Snowflake } from \"discord-api-types/v10\";\n\n/**\n * Creates a stable key for a guild-scoped entity.\n */\nexport function guildScopedKey(guildId: Snowflake, id: Snowflake): string {\n return `${guildId}:${id}`;\n}\n\n/**\n * Creates a stable key for a channel message.\n */\nexport function messageKey(channelId: Snowflake, messageId: Snowflake): string {\n return `${channelId}:${messageId}`;\n}\n\n/**\n * Creates a stable key for a guild member.\n */\nexport function memberKey(guildId: Snowflake, userId: Snowflake): string {\n return guildScopedKey(guildId, userId);\n}\n\n/**\n * Creates a stable key for a guild presence.\n */\nexport function presenceKey(guildId: Snowflake, userId: Snowflake): string {\n return guildScopedKey(guildId, userId);\n}\n\n/**\n * Creates a stable key for a guild voice state.\n */\nexport function voiceStateKey(guildId: Snowflake, userId: Snowflake): string {\n return guildScopedKey(guildId, userId);\n}\n\n/**\n * Creates a stable key for a guild role.\n */\nexport function roleKey(guildId: Snowflake, roleId: Snowflake): string {\n return guildScopedKey(guildId, roleId);\n}\n\n/**\n * Creates a stable key for a guild emoji.\n */\nexport function emojiKey(guildId: Snowflake, emojiId: Snowflake): string {\n return guildScopedKey(guildId, emojiId);\n}\n\n/**\n * Creates a stable key for a guild sticker.\n */\nexport function stickerKey(guildId: Snowflake, stickerId: Snowflake): string {\n return guildScopedKey(guildId, stickerId);\n}\n\n/**\n * Creates a stable key for a guild scheduled event.\n */\nexport function scheduledEventKey(guildId: Snowflake, scheduledEventId: Snowflake): string {\n return guildScopedKey(guildId, scheduledEventId);\n}\n\n/**\n * Creates a stable key for a stage instance.\n */\nexport function stageInstanceKey(guildId: Snowflake, channelId: Snowflake): string {\n return guildScopedKey(guildId, channelId);\n}\n\n/**\n * Creates a stable key for a guild soundboard sound.\n */\nexport function soundboardSoundKey(guildId: Snowflake, soundId: Snowflake): string {\n return guildScopedKey(guildId, soundId);\n}\n\n/**\n * Creates a stable key for a guild auto moderation rule.\n */\nexport function autoModerationRuleKey(guildId: Snowflake, ruleId: Snowflake): string {\n return guildScopedKey(guildId, ruleId);\n}\n\n/**\n * Creates a stable key for a guild ban.\n */\nexport function banKey(guildId: Snowflake, userId: Snowflake): string {\n return guildScopedKey(guildId, userId);\n}\n\n/**\n * Creates a stable key for a guild integration.\n */\nexport function integrationKey(guildId: Snowflake, integrationId: Snowflake): string {\n return guildScopedKey(guildId, integrationId);\n}\n\n/**\n * Creates a stable key for an invite, using `@global` for invites that do not belong to a guild.\n */\nexport function inviteKey(guildId: Snowflake | null | undefined, code: string): string {\n return `${guildId ?? \"@global\"}:${code}`;\n}\n\n/**\n * Creates a stable key for a thread member.\n */\nexport function threadMemberKey(threadId: Snowflake, userId: Snowflake): string {\n return `${threadId}:${userId}`;\n}\n\n/**\n * Creates a stable key for application command permissions.\n */\nexport function applicationCommandPermissionsKey(\n applicationId: Snowflake,\n guildId: Snowflake,\n commandId: Snowflake,\n): string {\n return `${applicationId}:${guildId}:${commandId}`;\n}\n","import type {\r\n APIMessage,\r\n APIPartialEmoji,\r\n APIReaction,\r\n GatewayMessagePollVoteDispatchData,\r\n GatewayMessageReactionAddDispatchData,\r\n GatewayMessageReactionRemoveDispatchData,\r\n} from \"discord-api-types/v10\";\r\n\r\n// Reactions and poll votes only carry the voter's ID, so whether the bot is the voter needs the bot's own ID.\r\n\r\n/**\r\n * Whether two reaction emojis are the same: custom emojis match by ID, Unicode emojis by name.\r\n */\r\nfunction isSameEmoji(a: APIPartialEmoji, b: APIPartialEmoji): boolean {\r\n return a.id ? a.id === b.id : !b.id && a.name === b.name;\r\n}\r\n\r\n/**\r\n * Adds a `MESSAGE_REACTION_ADD` to a cached message's reactions.\r\n *\r\n * @param message The cached message.\r\n * @param data The dispatch data.\r\n * @param clientUserId The bot's user ID, to set `me` when the bot reacted.\r\n */\r\nexport function addReaction(\r\n message: APIMessage,\r\n data: GatewayMessageReactionAddDispatchData,\r\n clientUserId?: string,\r\n): APIMessage {\r\n const me = data.user_id === clientUserId;\r\n const kind = data.burst ? \"burst\" : \"normal\";\r\n const reactions = message.reactions ?? [];\r\n const existing = reactions.find((reaction) => isSameEmoji(reaction.emoji, data.emoji));\r\n\r\n if (!existing) {\r\n const reaction: APIReaction = {\r\n emoji: data.emoji,\r\n count: 1,\r\n count_details: { normal: data.burst ? 0 : 1, burst: data.burst ? 1 : 0 },\r\n me: me && !data.burst,\r\n me_burst: me && data.burst,\r\n burst_colors: data.burst_colors ?? [],\r\n };\r\n return { ...message, reactions: [...reactions, reaction] };\r\n }\r\n\r\n return {\r\n ...message,\r\n reactions: reactions.map((reaction) =>\r\n reaction === existing\r\n ? {\r\n ...reaction,\r\n count: reaction.count + 1,\r\n count_details: {\r\n ...reaction.count_details,\r\n [kind]: reaction.count_details[kind] + 1,\r\n },\r\n me: reaction.me || (me && !data.burst),\r\n me_burst: reaction.me_burst || (me && data.burst),\r\n burst_colors: data.burst\r\n ? (data.burst_colors ?? reaction.burst_colors)\r\n : reaction.burst_colors,\r\n }\r\n : reaction,\r\n ),\r\n };\r\n}\r\n\r\n/**\r\n * Removes a `MESSAGE_REACTION_REMOVE` from a cached message's reactions, dropping the reaction when its count reaches\r\n * zero.\r\n *\r\n * @param message The cached message.\r\n * @param data The dispatch data.\r\n * @param clientUserId The bot's user ID, to clear `me` when the bot's reaction was removed.\r\n */\r\nexport function removeReaction(\r\n message: APIMessage,\r\n data: GatewayMessageReactionRemoveDispatchData,\r\n clientUserId?: string,\r\n): APIMessage {\r\n const me = data.user_id === clientUserId;\r\n const kind = data.burst ? \"burst\" : \"normal\";\r\n const reactions = (message.reactions ?? []).flatMap((reaction) => {\r\n if (!isSameEmoji(reaction.emoji, data.emoji)) return [reaction];\r\n if (reaction.count <= 1) return [];\r\n return [\r\n {\r\n ...reaction,\r\n count: reaction.count - 1,\r\n count_details: {\r\n ...reaction.count_details,\r\n [kind]: Math.max(0, reaction.count_details[kind] - 1),\r\n },\r\n me: reaction.me && !(me && !data.burst),\r\n me_burst: reaction.me_burst && !(me && data.burst),\r\n },\r\n ];\r\n });\r\n return { ...message, reactions };\r\n}\r\n\r\n/**\r\n * Removes every reaction with one emoji from a cached message.\r\n *\r\n * @param message The cached message.\r\n * @param emoji The emoji.\r\n */\r\nexport function removeReactionEmoji(message: APIMessage, emoji: APIPartialEmoji): APIMessage {\r\n return {\r\n ...message,\r\n reactions: (message.reactions ?? []).filter((reaction) => !isSameEmoji(reaction.emoji, emoji)),\r\n };\r\n}\r\n\r\n/**\r\n * Counts a `MESSAGE_POLL_VOTE_ADD` or `MESSAGE_POLL_VOTE_REMOVE` in a cached message's poll results.\r\n *\r\n * @param message The cached message.\r\n * @param data The dispatch data.\r\n * @param delta `1` for a vote, `-1` for a removed vote.\r\n * @param clientUserId The bot's user ID, to set `me_voted` when the bot voted.\r\n */\r\nexport function countPollVote(\r\n message: APIMessage,\r\n data: GatewayMessagePollVoteDispatchData,\r\n delta: 1 | -1,\r\n clientUserId?: string,\r\n): APIMessage {\r\n const { poll } = message;\r\n if (!poll) return message;\r\n\r\n const me = data.user_id === clientUserId;\r\n const results = poll.results ?? { is_finalized: false, answer_counts: [] };\r\n const counts = results.answer_counts.some((count) => count.id === data.answer_id)\r\n ? results.answer_counts\r\n : [...results.answer_counts, { id: data.answer_id, count: 0, me_voted: false }];\r\n\r\n return {\r\n ...message,\r\n poll: {\r\n ...poll,\r\n results: {\r\n ...results,\r\n answer_counts: counts.map((count) =>\r\n count.id === data.answer_id\r\n ? {\r\n ...count,\r\n count: Math.max(0, count.count + delta),\r\n me_voted: me ? delta === 1 : count.me_voted,\r\n }\r\n : count,\r\n ),\r\n },\r\n },\r\n };\r\n}\r\n","import { GatewayDispatchEvents } from \"discord-api-types/v10\";\r\nimport type {\r\n APIEmoji,\r\n APIMessage,\r\n APIGuildMember,\r\n APIRole,\r\n APISoundboardSound,\r\n APISticker,\r\n GatewayDispatchPayload,\r\n GatewayGuildCreateDispatchData,\r\n GatewayGuildMembersChunkDispatchData,\r\n GatewayGuildSoundboardSoundsUpdateDispatchData,\r\n GatewaySoundboardSoundsDispatchData,\r\n GatewayThreadListSync,\r\n GatewayThreadMembersUpdateDispatchData,\r\n Snowflake,\r\n} from \"discord-api-types/v10\";\r\nimport {\r\n applicationCommandPermissionsKey,\r\n autoModerationRuleKey,\r\n banKey,\r\n emojiKey,\r\n guildScopedKey,\r\n integrationKey,\r\n inviteKey,\r\n memberKey,\r\n messageKey,\r\n presenceKey,\r\n roleKey,\r\n scheduledEventKey,\r\n soundboardSoundKey,\r\n stageInstanceKey,\r\n stickerKey,\r\n threadMemberKey,\r\n voiceStateKey,\r\n} from \"./keys.js\";\r\nimport { addReaction, countPollVote, removeReaction, removeReactionEmoji } from \"./reactions.js\";\r\nimport type { Cache, CacheEntityName, EntityCache } from \"./types.js\";\r\n\r\n// A record rather than an array so the compiler enforces that every entity cache is listed.\r\nconst cacheEntityNameRecord: Record<CacheEntityName, true> = {\r\n applicationCommandPermissions: true,\r\n auditLogEntries: true,\r\n autoModerationRules: true,\r\n bans: true,\r\n channels: true,\r\n emojis: true,\r\n entitlements: true,\r\n guilds: true,\r\n integrations: true,\r\n invites: true,\r\n members: true,\r\n messages: true,\r\n presences: true,\r\n roles: true,\r\n scheduledEvents: true,\r\n soundboardSounds: true,\r\n stageInstances: true,\r\n stickers: true,\r\n subscriptions: true,\r\n threadMembers: true,\r\n threads: true,\r\n users: true,\r\n voiceStates: true,\r\n};\r\n\r\n/**\r\n * The name of every entity cache held by a {@link Cache}.\r\n */\r\nexport const CacheEntityNames = Object.keys(cacheEntityNameRecord) as readonly CacheEntityName[];\r\n\r\n/**\r\n * A single mutation a gateway dispatch produces on a {@link Cache}.\r\n */\r\nexport type CacheOperation =\r\n | {\r\n type: \"upsert\";\r\n store: CacheEntityName;\r\n key: string;\r\n raw: unknown;\r\n /** Whether to shallow-merge `raw` onto the existing value, used for partial updates. */\r\n merge?: boolean;\r\n }\r\n | {\r\n type: \"update\";\r\n store: CacheEntityName;\r\n key: string;\r\n /** Computes the new value from the cached one. Nothing is written when the key is not cached. */\r\n update: (value: unknown) => unknown;\r\n }\r\n | { type: \"delete\"; store: CacheEntityName; key: string }\r\n | { type: \"deletePrefix\"; store: CacheEntityName; prefix: string }\r\n | { type: \"deleteWhere\"; store: CacheEntityName; predicate: (value: unknown) => boolean };\r\n\r\n/**\r\n * What {@link createCacheOperations} needs to know besides the dispatch.\r\n */\r\nexport interface CacheOperationContext {\r\n /**\r\n * The bot's user ID. Reactions and poll votes only carry the voter's ID, so without it the cached `me` and\r\n * `me_voted` flags are never set.\r\n */\r\n clientUserId?: string;\r\n}\r\n\r\n/**\r\n * Translates a gateway dispatch into the list of {@link CacheOperation}s it implies, including the cascades (e.g.\r\n * `CHANNEL_DELETE` also drops that channel's messages).\r\n *\r\n * @remarks\r\n * This is a pure function, it does not touch any cache. Use {@link applyGatewayDispatch} to apply them.\r\n * `INTERACTION_CREATE` is intentionally ignored: interactions are short-lived and never cached.\r\n *\r\n * @param payload The gateway dispatch payload.\r\n * @param context The bot's user ID, for the `me` flags of reactions and poll votes.\r\n */\r\nexport function createCacheOperations(\r\n payload: GatewayDispatchPayload,\r\n context: CacheOperationContext = {},\r\n): CacheOperation[] {\r\n const { clientUserId } = context;\r\n const operations: CacheOperation[] = [];\r\n\r\n switch (payload.t) {\r\n case GatewayDispatchEvents.ApplicationCommandPermissionsUpdate: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"applicationCommandPermissions\",\r\n key: applicationCommandPermissionsKey(data.application_id, data.guild_id, data.id),\r\n raw: data,\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.AutoModerationRuleCreate:\r\n case GatewayDispatchEvents.AutoModerationRuleUpdate: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"autoModerationRules\",\r\n key: autoModerationRuleKey(data.guild_id, data.id),\r\n raw: data,\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.AutoModerationRuleDelete: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"delete\",\r\n store: \"autoModerationRules\",\r\n key: autoModerationRuleKey(data.guild_id, data.id),\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.ChannelCreate:\r\n case GatewayDispatchEvents.ChannelUpdate: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"channels\",\r\n key: data.id,\r\n raw: data,\r\n merge: payload.t === GatewayDispatchEvents.ChannelUpdate,\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.ChannelDelete: {\r\n const data = payload.d;\r\n operations.push({ type: \"delete\", store: \"channels\", key: data.id });\r\n operations.push({ type: \"deletePrefix\", store: \"messages\", prefix: `${data.id}:` });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.EntitlementCreate:\r\n case GatewayDispatchEvents.EntitlementUpdate: {\r\n const data = payload.d;\r\n operations.push({ type: \"upsert\", store: \"entitlements\", key: data.id, raw: data });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.EntitlementDelete: {\r\n operations.push({ type: \"delete\", store: \"entitlements\", key: payload.d.id });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildAuditLogEntryCreate: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"auditLogEntries\",\r\n key: guildScopedKey(data.guild_id, data.id),\r\n raw: data,\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildBanAdd: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"bans\",\r\n key: banKey(data.guild_id, data.user.id),\r\n raw: data,\r\n });\r\n operations.push({ type: \"upsert\", store: \"users\", key: data.user.id, raw: data.user });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildBanRemove: {\r\n const data = payload.d;\r\n operations.push({ type: \"delete\", store: \"bans\", key: banKey(data.guild_id, data.user.id) });\r\n operations.push({ type: \"upsert\", store: \"users\", key: data.user.id, raw: data.user });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildCreate: {\r\n hydrateGuildCreate(operations, payload.d);\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildUpdate: {\r\n // Like `GUILD_CREATE`, the roles and emojis go to their own entity caches rather than the guild entry.\r\n const { roles, emojis, stickers, ...data } = payload.d;\r\n operations.push({ type: \"upsert\", store: \"guilds\", key: data.id, raw: data, merge: true });\r\n for (const role of roles ?? []) hydrateRole(operations, data.id, role);\r\n for (const emoji of emojis ?? []) hydrateEmoji(operations, data.id, emoji);\r\n for (const sticker of stickers ?? []) hydrateSticker(operations, data.id, sticker);\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildDelete: {\r\n const data = payload.d;\r\n // An `unavailable` guild is an outage, not a removal: keep its data around until it comes back.\r\n if (data.unavailable) {\r\n operations.push({ type: \"upsert\", store: \"guilds\", key: data.id, raw: data, merge: true });\r\n break;\r\n }\r\n\r\n operations.push({ type: \"delete\", store: \"guilds\", key: data.id });\r\n deleteGuildScopedResources(operations, data.id);\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildEmojisUpdate: {\r\n const data = payload.d;\r\n operations.push({ type: \"deletePrefix\", store: \"emojis\", prefix: `${data.guild_id}:` });\r\n for (const emoji of data.emojis) {\r\n if (!emoji.id) continue;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"emojis\",\r\n key: emojiKey(data.guild_id, emoji.id),\r\n raw: withGuildId(emoji, data.guild_id),\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildStickersUpdate: {\r\n const data = payload.d;\r\n operations.push({ type: \"deletePrefix\", store: \"stickers\", prefix: `${data.guild_id}:` });\r\n for (const sticker of data.stickers) {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"stickers\",\r\n key: stickerKey(data.guild_id, sticker.id),\r\n raw: withGuildId(sticker, data.guild_id),\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildMemberAdd:\r\n case GatewayDispatchEvents.GuildMemberUpdate: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"members\",\r\n key: memberKey(data.guild_id, data.user.id),\r\n raw: data,\r\n merge: true,\r\n });\r\n operations.push({ type: \"upsert\", store: \"users\", key: data.user.id, raw: data.user });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildMemberRemove: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"delete\",\r\n store: \"members\",\r\n key: memberKey(data.guild_id, data.user.id),\r\n });\r\n operations.push({ type: \"upsert\", store: \"users\", key: data.user.id, raw: data.user });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildMembersChunk: {\r\n hydrateGuildMembersChunk(operations, payload.d);\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildRoleCreate:\r\n case GatewayDispatchEvents.GuildRoleUpdate: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"roles\",\r\n key: roleKey(data.guild_id, data.role.id),\r\n raw: withGuildId(data.role, data.guild_id),\r\n merge: payload.t === GatewayDispatchEvents.GuildRoleUpdate,\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildRoleDelete: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"delete\",\r\n store: \"roles\",\r\n key: roleKey(data.guild_id, data.role_id),\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildScheduledEventCreate:\r\n case GatewayDispatchEvents.GuildScheduledEventUpdate: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"scheduledEvents\",\r\n key: scheduledEventKey(data.guild_id, data.id),\r\n raw: data,\r\n merge: true,\r\n });\r\n if (data.creator) {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"users\",\r\n key: data.creator.id,\r\n raw: data.creator,\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildScheduledEventDelete: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"delete\",\r\n store: \"scheduledEvents\",\r\n key: scheduledEventKey(data.guild_id, data.id),\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildSoundboardSoundCreate:\r\n case GatewayDispatchEvents.GuildSoundboardSoundUpdate: {\r\n const data = payload.d;\r\n if (!data.guild_id) break;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"soundboardSounds\",\r\n key: soundboardSoundKey(data.guild_id, data.sound_id),\r\n raw: data,\r\n merge: payload.t === GatewayDispatchEvents.GuildSoundboardSoundUpdate,\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildSoundboardSoundDelete: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"delete\",\r\n store: \"soundboardSounds\",\r\n key: soundboardSoundKey(data.guild_id, data.sound_id),\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.GuildSoundboardSoundsUpdate: {\r\n hydrateGuildSoundboardSoundsUpdate(operations, payload.d);\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.SoundboardSounds: {\r\n hydrateSoundboardSounds(operations, payload.d);\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.IntegrationCreate:\r\n case GatewayDispatchEvents.IntegrationUpdate: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"integrations\",\r\n key: integrationKey(data.guild_id, data.id),\r\n raw: data,\r\n merge: true,\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.IntegrationDelete: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"delete\",\r\n store: \"integrations\",\r\n key: integrationKey(data.guild_id, data.id),\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.InviteCreate: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"invites\",\r\n key: inviteKey(data.guild_id, data.code),\r\n raw: data,\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.InviteDelete: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"delete\",\r\n store: \"invites\",\r\n key: inviteKey(data.guild_id, data.code),\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.MessageCreate:\r\n case GatewayDispatchEvents.MessageUpdate: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"messages\",\r\n key: messageKey(data.channel_id, data.id),\r\n raw: data,\r\n merge: payload.t === GatewayDispatchEvents.MessageUpdate,\r\n });\r\n\r\n const author = \"author\" in data ? data.author : undefined;\r\n if (author) {\r\n operations.push({ type: \"upsert\", store: \"users\", key: author.id, raw: author });\r\n if (data.member && data.guild_id) {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"members\",\r\n key: memberKey(data.guild_id, author.id),\r\n raw: withGuildId(data.member, data.guild_id),\r\n merge: true,\r\n });\r\n }\r\n }\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.MessageDelete: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"delete\",\r\n store: \"messages\",\r\n key: messageKey(data.channel_id, data.id),\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.MessageDeleteBulk: {\r\n const data = payload.d;\r\n for (const id of data.ids) {\r\n operations.push({\r\n type: \"delete\",\r\n store: \"messages\",\r\n key: messageKey(data.channel_id, id),\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.MessageReactionAdd: {\r\n const data = payload.d;\r\n operations.push(\r\n updateMessage(data.channel_id, data.message_id, (message) =>\r\n addReaction(message, data, clientUserId),\r\n ),\r\n );\r\n // Guild reactions carry the reacting member, like messages carry their author.\r\n const user = data.member?.user;\r\n if (user && data.guild_id) {\r\n operations.push({ type: \"upsert\", store: \"users\", key: user.id, raw: user });\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"members\",\r\n key: memberKey(data.guild_id, user.id),\r\n raw: withGuildId(data.member!, data.guild_id),\r\n merge: true,\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.MessageReactionRemove: {\r\n const data = payload.d;\r\n operations.push(\r\n updateMessage(data.channel_id, data.message_id, (message) =>\r\n removeReaction(message, data, clientUserId),\r\n ),\r\n );\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.MessageReactionRemoveAll: {\r\n const data = payload.d;\r\n operations.push(\r\n updateMessage(data.channel_id, data.message_id, (message) => ({\r\n ...message,\r\n reactions: [],\r\n })),\r\n );\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.MessageReactionRemoveEmoji: {\r\n const data = payload.d;\r\n operations.push(\r\n updateMessage(data.channel_id, data.message_id, (message) =>\r\n removeReactionEmoji(message, data.emoji),\r\n ),\r\n );\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.MessagePollVoteAdd:\r\n case GatewayDispatchEvents.MessagePollVoteRemove: {\r\n const data = payload.d;\r\n const delta = payload.t === GatewayDispatchEvents.MessagePollVoteAdd ? 1 : -1;\r\n operations.push(\r\n updateMessage(data.channel_id, data.message_id, (message) =>\r\n countPollVote(message, data, delta, clientUserId),\r\n ),\r\n );\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.PresenceUpdate: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"presences\",\r\n key: presenceKey(data.guild_id, data.user.id),\r\n raw: data,\r\n merge: true,\r\n });\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"users\",\r\n key: data.user.id,\r\n raw: data.user,\r\n merge: true,\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.Ready: {\r\n const data = payload.d;\r\n operations.push({ type: \"upsert\", store: \"users\", key: data.user.id, raw: data.user });\r\n for (const guild of data.guilds) {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"guilds\",\r\n key: guild.id,\r\n raw: guild,\r\n merge: true,\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.StageInstanceCreate:\r\n case GatewayDispatchEvents.StageInstanceUpdate: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"stageInstances\",\r\n key: stageInstanceKey(data.guild_id, data.channel_id),\r\n raw: data,\r\n merge: true,\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.StageInstanceDelete: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"delete\",\r\n store: \"stageInstances\",\r\n key: stageInstanceKey(data.guild_id, data.channel_id),\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.SubscriptionCreate:\r\n case GatewayDispatchEvents.SubscriptionUpdate: {\r\n const data = payload.d;\r\n operations.push({ type: \"upsert\", store: \"subscriptions\", key: data.id, raw: data });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.SubscriptionDelete: {\r\n operations.push({ type: \"delete\", store: \"subscriptions\", key: payload.d.id });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.ThreadCreate:\r\n case GatewayDispatchEvents.ThreadUpdate: {\r\n const data = payload.d;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"threads\",\r\n key: data.id,\r\n raw: data,\r\n merge: payload.t === GatewayDispatchEvents.ThreadUpdate,\r\n });\r\n\r\n const member = \"member\" in data ? data.member : undefined;\r\n if (member?.user_id) {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"threadMembers\",\r\n key: threadMemberKey(data.id, member.user_id),\r\n // Thread members carry no guild ID of their own: without it, `GUILD_DELETE` could not sweep them.\r\n raw: data.guild_id ? withGuildId(member, data.guild_id) : member,\r\n merge: true,\r\n });\r\n }\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.ThreadDelete: {\r\n const data = payload.d;\r\n operations.push({ type: \"delete\", store: \"threads\", key: data.id });\r\n operations.push({ type: \"deletePrefix\", store: \"threadMembers\", prefix: `${data.id}:` });\r\n operations.push({ type: \"deletePrefix\", store: \"messages\", prefix: `${data.id}:` });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.ThreadListSync: {\r\n hydrateThreadListSync(operations, payload.d);\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.ThreadMemberUpdate: {\r\n const data = payload.d;\r\n if (!data.id || !data.user_id) break;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"threadMembers\",\r\n key: threadMemberKey(data.id, data.user_id),\r\n raw: data,\r\n merge: true,\r\n });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.ThreadMembersUpdate: {\r\n hydrateThreadMembersUpdate(operations, payload.d);\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.UserUpdate: {\r\n const data = payload.d;\r\n operations.push({ type: \"upsert\", store: \"users\", key: data.id, raw: data, merge: true });\r\n break;\r\n }\r\n\r\n case GatewayDispatchEvents.VoiceStateUpdate: {\r\n const data = payload.d;\r\n if (!data.guild_id) break;\r\n\r\n const key = voiceStateKey(data.guild_id, data.user_id);\r\n if (data.channel_id) {\r\n operations.push({ type: \"upsert\", store: \"voiceStates\", key, raw: data, merge: true });\r\n } else {\r\n operations.push({ type: \"delete\", store: \"voiceStates\", key });\r\n }\r\n\r\n const user = data.member?.user;\r\n if (data.member && user) {\r\n operations.push({ type: \"upsert\", store: \"users\", key: user.id, raw: user });\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"members\",\r\n key: memberKey(data.guild_id, user.id),\r\n raw: withGuildId(data.member, data.guild_id),\r\n merge: true,\r\n });\r\n }\r\n break;\r\n }\r\n\r\n default:\r\n break;\r\n }\r\n\r\n return operations;\r\n}\r\n\r\n/**\r\n * Applies a list of {@link CacheOperation}s to a {@link Cache}, sequentially and in order.\r\n *\r\n * @param cache The cache to mutate.\r\n * @param operations The operations to apply, usually created by {@link createCacheOperations}.\r\n */\r\nexport async function applyCacheOperations(\r\n cache: Cache,\r\n operations: readonly CacheOperation[],\r\n): Promise<void> {\r\n for (const operation of operations) {\r\n const store = cache[operation.store] as EntityCache<unknown>;\r\n\r\n switch (operation.type) {\r\n case \"upsert\": {\r\n const value = operation.merge\r\n ? mergeValues(await store.get(operation.key), operation.raw)\r\n : operation.raw;\r\n await store.set(operation.key, value);\r\n break;\r\n }\r\n case \"update\": {\r\n const existing = await store.get(operation.key);\r\n if (existing !== undefined) await store.set(operation.key, operation.update(existing));\r\n break;\r\n }\r\n case \"delete\":\r\n await store.delete(operation.key);\r\n break;\r\n case \"deletePrefix\":\r\n for (const key of await store.keys()) {\r\n if (key.startsWith(operation.prefix)) await store.delete(key);\r\n }\r\n break;\r\n case \"deleteWhere\":\r\n for (const [key, value] of await store.entries()) {\r\n if (operation.predicate(value)) await store.delete(key);\r\n }\r\n break;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Writes a gateway dispatch into every relevant entity cache of a {@link Cache}.\r\n *\r\n * @param cache The cache to mutate.\r\n * @param payload The gateway dispatch payload.\r\n * @param context The bot's user ID, for the `me` flags of reactions and poll votes.\r\n */\r\nexport function applyGatewayDispatch(\r\n cache: Cache,\r\n payload: GatewayDispatchPayload,\r\n context?: CacheOperationContext,\r\n): Promise<void> {\r\n return applyCacheOperations(cache, createCacheOperations(payload, context));\r\n}\r\n\r\n/**\r\n * Shallow-merges `value` onto `existing` when both are plain objects, returning `value` otherwise.\r\n */\r\nexport function mergeValues<Value>(existing: Value | undefined, value: Value): Value {\r\n if (isObject(existing) && isObject(value)) return { ...existing, ...value };\r\n return value;\r\n}\r\n\r\nfunction hydrateGuildCreate(\r\n operations: CacheOperation[],\r\n guild: GatewayGuildCreateDispatchData,\r\n): void {\r\n // Unavailable guilds carry no data besides their ID, see `GuildDelete`.\r\n if (\"unavailable\" in guild && guild.unavailable) {\r\n operations.push({ type: \"upsert\", store: \"guilds\", key: guild.id, raw: guild, merge: true });\r\n return;\r\n }\r\n\r\n const {\r\n channels,\r\n threads,\r\n members,\r\n presences,\r\n voice_states: voiceStates,\r\n stage_instances: stageInstances,\r\n guild_scheduled_events: scheduledEvents,\r\n soundboard_sounds: soundboardSounds,\r\n roles,\r\n emojis,\r\n stickers,\r\n ...rest\r\n } = guild;\r\n // Collections are stored in their own entity caches, keeping the guild entry small.\r\n operations.push({ type: \"upsert\", store: \"guilds\", key: guild.id, raw: rest });\r\n\r\n for (const channel of channels ?? []) {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"channels\",\r\n key: channel.id,\r\n raw: withGuildId(channel, guild.id),\r\n });\r\n }\r\n\r\n for (const thread of threads ?? []) {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"threads\",\r\n key: thread.id,\r\n raw: withGuildId(thread, guild.id),\r\n });\r\n if (thread.member?.user_id) {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"threadMembers\",\r\n key: threadMemberKey(thread.id, thread.member.user_id),\r\n raw: withGuildId(thread.member, guild.id),\r\n });\r\n }\r\n }\r\n\r\n for (const member of members ?? []) hydrateMember(operations, guild.id, member);\r\n\r\n for (const presence of presences ?? []) {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"presences\",\r\n key: presenceKey(guild.id, presence.user.id),\r\n raw: withGuildId(presence, guild.id),\r\n });\r\n }\r\n\r\n for (const role of roles ?? []) hydrateRole(operations, guild.id, role);\r\n for (const emoji of emojis ?? []) hydrateEmoji(operations, guild.id, emoji);\r\n for (const sticker of stickers ?? []) hydrateSticker(operations, guild.id, sticker);\r\n\r\n for (const voiceState of voiceStates ?? []) {\r\n if (!voiceState.channel_id) continue;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"voiceStates\",\r\n key: voiceStateKey(guild.id, voiceState.user_id),\r\n raw: withGuildId(voiceState, guild.id),\r\n });\r\n }\r\n\r\n for (const stageInstance of stageInstances ?? []) {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"stageInstances\",\r\n key: stageInstanceKey(guild.id, stageInstance.channel_id),\r\n raw: stageInstance,\r\n });\r\n }\r\n\r\n for (const scheduledEvent of scheduledEvents ?? []) {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"scheduledEvents\",\r\n key: scheduledEventKey(guild.id, scheduledEvent.id),\r\n raw: scheduledEvent,\r\n });\r\n }\r\n\r\n for (const sound of soundboardSounds ?? []) hydrateSoundboardSound(operations, guild.id, sound);\r\n}\r\n\r\nfunction hydrateGuildMembersChunk(\r\n operations: CacheOperation[],\r\n data: GatewayGuildMembersChunkDispatchData,\r\n): void {\r\n for (const member of data.members) hydrateMember(operations, data.guild_id, member);\r\n for (const presence of data.presences ?? []) {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"presences\",\r\n key: presenceKey(data.guild_id, presence.user.id),\r\n raw: withGuildId(presence, data.guild_id),\r\n });\r\n }\r\n}\r\n\r\nfunction hydrateGuildSoundboardSoundsUpdate(\r\n operations: CacheOperation[],\r\n data: GatewayGuildSoundboardSoundsUpdateDispatchData,\r\n): void {\r\n operations.push({ type: \"deletePrefix\", store: \"soundboardSounds\", prefix: `${data.guild_id}:` });\r\n for (const sound of data.soundboard_sounds)\r\n hydrateSoundboardSound(operations, data.guild_id, sound);\r\n}\r\n\r\nfunction hydrateSoundboardSounds(\r\n operations: CacheOperation[],\r\n data: GatewaySoundboardSoundsDispatchData,\r\n): void {\r\n for (const sound of data.soundboard_sounds)\r\n hydrateSoundboardSound(operations, data.guild_id, sound);\r\n}\r\n\r\nfunction hydrateThreadListSync(operations: CacheOperation[], data: GatewayThreadListSync): void {\r\n for (const thread of data.threads) {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"threads\",\r\n key: thread.id,\r\n raw: withGuildId(thread, data.guild_id),\r\n merge: true,\r\n });\r\n }\r\n\r\n for (const member of data.members) {\r\n if (!member.id || !member.user_id) continue;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"threadMembers\",\r\n key: threadMemberKey(member.id, member.user_id),\r\n raw: withGuildId(member, data.guild_id),\r\n merge: true,\r\n });\r\n }\r\n}\r\n\r\nfunction hydrateThreadMembersUpdate(\r\n operations: CacheOperation[],\r\n data: GatewayThreadMembersUpdateDispatchData,\r\n): void {\r\n for (const member of data.added_members ?? []) {\r\n if (!member.user_id) continue;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"threadMembers\",\r\n key: threadMemberKey(data.id, member.user_id),\r\n raw: withGuildId(member, data.guild_id),\r\n merge: true,\r\n });\r\n }\r\n\r\n for (const userId of data.removed_member_ids ?? []) {\r\n operations.push({\r\n type: \"delete\",\r\n store: \"threadMembers\",\r\n key: threadMemberKey(data.id, userId),\r\n });\r\n }\r\n}\r\n\r\nfunction hydrateMember(\r\n operations: CacheOperation[],\r\n guildId: Snowflake,\r\n member: APIGuildMember,\r\n): void {\r\n if (!member.user) return;\r\n\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"members\",\r\n key: memberKey(guildId, member.user.id),\r\n raw: withGuildId(member, guildId),\r\n merge: true,\r\n });\r\n operations.push({ type: \"upsert\", store: \"users\", key: member.user.id, raw: member.user });\r\n}\r\n\r\nfunction hydrateRole(operations: CacheOperation[], guildId: Snowflake, role: APIRole): void {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"roles\",\r\n key: roleKey(guildId, role.id),\r\n raw: withGuildId(role, guildId),\r\n });\r\n}\r\n\r\nfunction hydrateEmoji(operations: CacheOperation[], guildId: Snowflake, emoji: APIEmoji): void {\r\n if (!emoji.id) return;\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"emojis\",\r\n key: emojiKey(guildId, emoji.id),\r\n raw: withGuildId(emoji, guildId),\r\n });\r\n}\r\n\r\nfunction hydrateSticker(\r\n operations: CacheOperation[],\r\n guildId: Snowflake,\r\n sticker: APISticker,\r\n): void {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"stickers\",\r\n key: stickerKey(guildId, sticker.id),\r\n raw: withGuildId(sticker, guildId),\r\n });\r\n}\r\n\r\nfunction hydrateSoundboardSound(\r\n operations: CacheOperation[],\r\n guildId: Snowflake,\r\n sound: APISoundboardSound,\r\n): void {\r\n operations.push({\r\n type: \"upsert\",\r\n store: \"soundboardSounds\",\r\n key: soundboardSoundKey(guildId, sound.sound_id),\r\n raw: withGuildId(sound, guildId),\r\n });\r\n}\r\n\r\nfunction deleteGuildScopedResources(operations: CacheOperation[], guildId: Snowflake): void {\r\n // Entities keyed by `${guildId}:...` can be dropped by prefix, which is cheap.\r\n const prefixed = [\r\n \"auditLogEntries\",\r\n \"autoModerationRules\",\r\n \"bans\",\r\n \"emojis\",\r\n \"integrations\",\r\n \"members\",\r\n \"presences\",\r\n \"roles\",\r\n \"scheduledEvents\",\r\n \"soundboardSounds\",\r\n \"stageInstances\",\r\n \"stickers\",\r\n \"voiceStates\",\r\n ] as const satisfies readonly CacheEntityName[];\r\n\r\n for (const store of prefixed) {\r\n operations.push({ type: \"deletePrefix\", store, prefix: `${guildId}:` });\r\n }\r\n\r\n // The rest are keyed by their own ID and need a scan over the stored `guild_id`.\r\n const scanned = [\r\n \"applicationCommandPermissions\",\r\n \"channels\",\r\n \"threads\",\r\n \"threadMembers\",\r\n \"messages\",\r\n \"invites\",\r\n ] as const satisfies readonly CacheEntityName[];\r\n\r\n for (const store of scanned) {\r\n operations.push({\r\n type: \"deleteWhere\",\r\n store,\r\n predicate: (value) => isObject(value) && value.guild_id === guildId,\r\n });\r\n }\r\n}\r\n\r\n// An `update` of a cached message; a message the cache does not hold stays uncached.\r\nfunction updateMessage(\r\n channelId: Snowflake,\r\n messageId: Snowflake,\r\n update: (message: APIMessage) => APIMessage,\r\n): CacheOperation {\r\n return {\r\n type: \"update\",\r\n store: \"messages\",\r\n key: messageKey(channelId, messageId),\r\n update: (value) => update(value as APIMessage),\r\n };\r\n}\r\n\r\nfunction withGuildId<Value extends object>(\r\n value: Value,\r\n guildId: Snowflake,\r\n): Value & { guild_id: Snowflake } {\r\n return { ...value, guild_id: guildId };\r\n}\r\n\r\nfunction isObject(value: unknown): value is Record<string, unknown> {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n","import type { GatewayDispatchPayload } from \"discord-api-types/v10\";\nimport { applyGatewayDispatch, type CacheOperationContext } from \"./operations.js\";\nimport type { Cache } from \"./types.js\";\n\n/** A gateway that emits the dispatch event used by @discordjs/ws and @discordjs/core. */\nexport interface GatewayDispatchSource {\n on(\n event: \"dispatch\",\n listener: (payload: GatewayDispatchPayload, shardId: number) => void,\n ): unknown;\n off?(\n event: \"dispatch\",\n listener: (payload: GatewayDispatchPayload, shardId: number) => void,\n ): unknown;\n}\n\nexport interface CacheGatewayOptions extends CacheOperationContext {\n /** Receives cache write failures from the asynchronous gateway listener. */\n onError?: (error: unknown, payload: GatewayDispatchPayload, shardId: number) => void;\n}\n\n/**\n * Writes gateway dispatches into a cache. Call the returned function to stop listening.\n * Use this when a gateway has no GatewayClient managing its dispatch queue.\n */\nexport function attachCacheToGateway(\n gateway: GatewayDispatchSource,\n cache: Cache,\n options: CacheGatewayOptions = {},\n): () => void {\n const listener = (payload: GatewayDispatchPayload, shardId: number): void => {\n void applyGatewayDispatch(cache, payload, { clientUserId: options.clientUserId }).catch(\n (error) => {\n if (options.onError) options.onError(error, payload, shardId);\n else console.error(\"Failed to cache gateway dispatch\", error);\n },\n );\n };\n\n gateway.on(\"dispatch\", listener);\n return () => gateway.off?.(\"dispatch\", listener);\n}\n","import { CacheEntityNames } from \"./operations.js\";\nimport type { Cache, CacheEntityName, CacheEntityTypes, EntityCache } from \"./types.js\";\n\n/**\n * An {@link EntityCache} backed by a `Map`, optionally bounded as a least-recently-used cache.\n */\nexport class MemoryEntityCache<Raw> implements EntityCache<Raw> {\n /**\n * The maximum amount of entries, `Infinity` for an unbounded cache.\n */\n public readonly maxSize: number;\n\n readonly #items = new Map<string, Raw>();\n\n public constructor(maxSize = Infinity) {\n if (maxSize !== Infinity && (!Number.isInteger(maxSize) || maxSize < 0)) {\n throw new RangeError(\n `maxSize must be a non-negative integer or Infinity, received ${maxSize}`,\n );\n }\n\n this.maxSize = maxSize;\n }\n\n public get(key: string): Raw | undefined {\n const value = this.#items.get(key);\n if (value !== undefined && this.maxSize !== Infinity) {\n // Re-insert to mark the entry as the most recently used one.\n this.#items.delete(key);\n this.#items.set(key, value);\n }\n\n return value;\n }\n\n public set(key: string, value: Raw): void {\n if (this.maxSize === 0) return;\n\n this.#items.delete(key);\n this.#items.set(key, value);\n\n if (this.#items.size > this.maxSize) {\n // Maps iterate in insertion order, so the first key is the least recently used one.\n this.#items.delete(this.#items.keys().next().value!);\n }\n }\n\n public has(key: string): boolean {\n return this.#items.has(key);\n }\n\n public delete(key: string): boolean {\n return this.#items.delete(key);\n }\n\n public clear(): void {\n this.#items.clear();\n }\n\n public getSize(): number {\n return this.#items.size;\n }\n\n public keys(): string[] {\n return [...this.#items.keys()];\n }\n\n public values(): Raw[] {\n return [...this.#items.values()];\n }\n\n public entries(): [key: string, value: Raw][] {\n return [...this.#items.entries()];\n }\n}\n\n/**\n * A {@link Cache} whose entity caches are all {@link MemoryEntityCache}s.\n */\nexport type InMemoryCache = {\n readonly [Name in CacheEntityName]: MemoryEntityCache<CacheEntityTypes[Name]>;\n};\n\nexport interface InMemoryCacheOptions {\n /**\n * The maximum amount of entries kept per entity cache before evicting the least recently used ones, either for\n * every entity cache or per entity cache. Entity caches left out are unbounded.\n *\n * @default Infinity\n */\n maxSize?: number | Partial<Record<CacheEntityName, number>>;\n}\n\n/**\n * Creates a {@link Cache} that keeps everything in the process' memory.\n *\n * @example\n * ```typescript\n * import { createInMemoryCache } from '@wolfstar/plugin-cache';\n *\n * // Keep at most 1000 messages around, everything else is unbounded.\n * const cache = createInMemoryCache({ maxSize: { messages: 1_000 } });\n * ```\n *\n * @param options The options for the cache.\n */\nexport function createInMemoryCache(options: InMemoryCacheOptions = {}): InMemoryCache & Cache {\n const { maxSize } = options;\n const resolve = (name: CacheEntityName) =>\n typeof maxSize === \"number\" ? maxSize : (maxSize?.[name] ?? Infinity);\n\n return Object.freeze(\n Object.fromEntries(\n CacheEntityNames.map((name) => [name, new MemoryEntityCache(resolve(name))]),\n ) as InMemoryCache,\n );\n}\n","/// <reference types=\"node\" />\r\nimport { promisify } from \"node:util\";\r\nimport { brotliCompress, brotliDecompress, gunzip, gzip } from \"node:zlib\";\r\nimport { CacheEntityNames } from \"./operations.js\";\r\nimport type { Cache, CacheEntityName, CacheEntityTypes, EntityCache } from \"./types.js\";\r\n\r\nconst gzipAsync = promisify(gzip);\r\nconst gunzipAsync = promisify(gunzip);\r\nconst brotliCompressAsync = promisify(brotliCompress);\r\nconst brotliDecompressAsync = promisify(brotliDecompress);\r\n\r\n/**\r\n * The subset of the [`ioredis`](https://github.com/redis/ioredis) client API the Redis cache relies on. An `ioredis`\r\n * `Redis` or `Cluster` instance satisfies it, as can any other client exposing the same commands.\r\n */\r\nexport interface RedisClientLike {\r\n get(key: string): Promise<string | null>;\r\n mget(...keys: string[]): Promise<(string | null)[]>;\r\n set(key: string, value: string): Promise<unknown>;\r\n set(key: string, value: string, mode: \"PX\", milliseconds: number): Promise<unknown>;\r\n del(...keys: string[]): Promise<number>;\r\n exists(...keys: string[]): Promise<number>;\r\n zadd(key: string, ...scoreMembers: (string | number)[]): Promise<unknown>;\r\n zrem(key: string, ...members: string[]): Promise<number>;\r\n zrange(key: string, start: string, stop: string): Promise<string[]>;\r\n zcard(key: string): Promise<number>;\r\n zremrangebyscore(key: string, min: number | string, max: number | string): Promise<number>;\r\n multi(): RedisTransactionLike;\r\n}\r\n\r\n/**\r\n * The subset of an [`ioredis`](https://github.com/redis/ioredis) `MULTI` transaction the Redis cache relies on: every\r\n * queued command returns the transaction, and `exec` runs them atomically.\r\n */\r\nexport interface RedisTransactionLike {\r\n set(key: string, value: string): RedisTransactionLike;\r\n set(key: string, value: string, mode: \"PX\", milliseconds: number): RedisTransactionLike;\r\n del(...keys: string[]): RedisTransactionLike;\r\n zadd(key: string, ...scoreMembers: (string | number)[]): RedisTransactionLike;\r\n zrem(key: string, ...members: string[]): RedisTransactionLike;\r\n zremrangebyscore(key: string, min: number | string, max: number | string): RedisTransactionLike;\r\n exec(): Promise<[error: Error | null, result: unknown][] | null>;\r\n}\r\n\r\n/**\r\n * Thrown when a value stored in Redis cannot be read back: invalid JSON, or compressed bytes that fail to decompress.\r\n *\r\n * @remarks\r\n * A missing value is not an error, `get` resolves to `undefined` for it. Redis connection errors are not wrapped\r\n * either, they propagate as the client throws them.\r\n */\r\nexport class CacheValueError extends Error {\r\n /**\r\n * The Redis key holding the unreadable value.\r\n */\r\n public readonly key: string;\r\n\r\n public constructor(key: string, cause: unknown) {\r\n super(`Cannot read the cached value at \"${key}\"`, { cause });\r\n this.name = \"CacheValueError\";\r\n this.key = key;\r\n }\r\n}\r\n\r\n/**\r\n * The algorithm used to compress values before writing them to Redis.\r\n */\r\nexport type RedisCacheCompression = \"gzip\" | \"brotli\" | \"none\";\r\n\r\nexport interface RedisEntityCacheOptions {\r\n /**\r\n * The prefix of every Redis key owned by this entity cache.\r\n */\r\n prefix: string;\r\n /**\r\n * The time-to-live of every entry, in seconds. Entries never expire when omitted.\r\n */\r\n ttl?: number;\r\n /**\r\n * The compression algorithm to use.\r\n *\r\n * @default \"none\"\r\n */\r\n compression?: RedisCacheCompression;\r\n /**\r\n * The minimum size, in bytes, a serialized value must reach to be compressed. Small payloads rarely benefit from it.\r\n *\r\n * @default 1024\r\n */\r\n compressionThreshold?: number;\r\n}\r\n\r\n// Compressed values are stored as `<marker><base64>`. JSON can never start with either marker, so values written with\r\n// a different `compression` setting (e.g. before it was turned on) are still read back correctly.\r\nconst CompressionMarkers = { gzip: \"gz:\", brotli: \"br:\" } as const;\r\n\r\n/**\r\n * An {@link EntityCache} backed by Redis.\r\n *\r\n * @remarks\r\n * Every entry is stored as its own string key (`<prefix>:<key>`), and a sorted set (`<prefix>:@index`) tracks the\r\n * stored keys with their expiration time as score, which is what `keys`, `entries`, `getSize`, and `clear` read from.\r\n */\r\nexport class RedisEntityCache<Raw> implements EntityCache<Raw> {\r\n public readonly prefix: string;\r\n public readonly ttl: number | undefined;\r\n public readonly compression: RedisCacheCompression;\r\n public readonly compressionThreshold: number;\r\n\r\n readonly #redis: RedisClientLike;\r\n\r\n public constructor(redis: RedisClientLike, options: RedisEntityCacheOptions) {\r\n if (options.ttl !== undefined && !(options.ttl > 0)) {\r\n throw new RangeError(`ttl must be a positive amount of seconds, received ${options.ttl}`);\r\n }\r\n\r\n this.#redis = redis;\r\n this.prefix = options.prefix;\r\n this.ttl = options.ttl;\r\n this.compression = options.compression ?? \"none\";\r\n this.compressionThreshold = options.compressionThreshold ?? 1024;\r\n }\r\n\r\n public async get(key: string): Promise<Raw | undefined> {\r\n const valueKey = this.valueKey(key);\r\n const value = await this.#redis.get(valueKey);\r\n return value === null ? undefined : this.deserialize(valueKey, value);\r\n }\r\n\r\n public async set(key: string, value: Raw): Promise<void> {\r\n const serialized = await this.serialize(value);\r\n // The value and its index entry are written in one transaction, so neither can exist without the other.\r\n const transaction = this.#redis.multi();\r\n if (this.ttl === undefined) {\r\n transaction.set(this.valueKey(key), serialized).zadd(this.indexKey, \"+inf\", key);\r\n } else {\r\n const now = Date.now();\r\n const milliseconds = Math.round(this.ttl * 1000);\r\n transaction\r\n .set(this.valueKey(key), serialized, \"PX\", milliseconds)\r\n .zadd(this.indexKey, now + milliseconds, key)\r\n // Pruning on every write keeps the index bounded even when nothing ever enumerates it.\r\n .zremrangebyscore(this.indexKey, \"-inf\", now);\r\n }\r\n\r\n await execute(transaction);\r\n }\r\n\r\n public async has(key: string): Promise<boolean> {\r\n return (await this.#redis.exists(this.valueKey(key))) > 0;\r\n }\r\n\r\n public async delete(key: string): Promise<boolean> {\r\n const [deleted] = await execute(\r\n this.#redis.multi().del(this.valueKey(key)).zrem(this.indexKey, key),\r\n );\r\n return (deleted as number) > 0;\r\n }\r\n\r\n public async clear(): Promise<void> {\r\n const keys = await this.#redis.zrange(this.indexKey, \"0\", \"-1\");\r\n if (keys.length > 0) await this.#redis.del(...keys.map((key) => this.valueKey(key)));\r\n await this.#redis.del(this.indexKey);\r\n }\r\n\r\n public async getSize(): Promise<number> {\r\n await this.prune();\r\n return this.#redis.zcard(this.indexKey);\r\n }\r\n\r\n public async keys(): Promise<string[]> {\r\n await this.prune();\r\n return this.#redis.zrange(this.indexKey, \"0\", \"-1\");\r\n }\r\n\r\n public async values(): Promise<Raw[]> {\r\n return (await this.entries()).map(([, value]) => value);\r\n }\r\n\r\n public async entries(): Promise<[key: string, value: Raw][]> {\r\n const keys = await this.keys();\r\n if (keys.length === 0) return [];\r\n\r\n const values = await this.#redis.mget(...keys.map((key) => this.valueKey(key)));\r\n const entries: [key: string, value: Raw][] = [];\r\n for (const [index, value] of values.entries()) {\r\n // The value may have been evicted by Redis between both reads.\r\n if (value !== null) {\r\n const key = keys[index]!;\r\n entries.push([key, await this.deserialize(this.valueKey(key), value)]);\r\n }\r\n }\r\n\r\n return entries;\r\n }\r\n\r\n /**\r\n * Gets the Redis key a value is stored at.\r\n * @param key The entity cache key.\r\n */\r\n public valueKey(key: string): string {\r\n return `${this.prefix}:${key}`;\r\n }\r\n\r\n /**\r\n * The Redis key of the sorted set indexing the stored keys.\r\n */\r\n public get indexKey(): string {\r\n return `${this.prefix}:@index`;\r\n }\r\n\r\n private async prune(): Promise<void> {\r\n if (this.ttl !== undefined)\r\n await this.#redis.zremrangebyscore(this.indexKey, \"-inf\", Date.now());\r\n }\r\n\r\n private async serialize(value: Raw): Promise<string> {\r\n const json = JSON.stringify(value);\r\n if (this.compression === \"none\" || Buffer.byteLength(json) < this.compressionThreshold) {\r\n return json;\r\n }\r\n\r\n const compressed =\r\n this.compression === \"gzip\" ? await gzipAsync(json) : await brotliCompressAsync(json);\r\n return `${CompressionMarkers[this.compression]}${compressed.toString(\"base64\")}`;\r\n }\r\n\r\n private async deserialize(valueKey: string, value: string): Promise<Raw> {\r\n try {\r\n if (value.startsWith(CompressionMarkers.gzip)) {\r\n return JSON.parse((await gunzipAsync(decode(value))).toString(\"utf8\")) as Raw;\r\n }\r\n\r\n if (value.startsWith(CompressionMarkers.brotli)) {\r\n return JSON.parse((await brotliDecompressAsync(decode(value))).toString(\"utf8\")) as Raw;\r\n }\r\n\r\n return JSON.parse(value) as Raw;\r\n } catch (error) {\r\n throw new CacheValueError(valueKey, error);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Runs a transaction, throwing the first command error, and resolves to the command results.\r\n */\r\nasync function execute(transaction: RedisTransactionLike): Promise<unknown[]> {\r\n const results = await transaction.exec();\r\n if (results === null) throw new Error(\"The Redis transaction was aborted\");\r\n\r\n return results.map(([error, result]) => {\r\n if (error) throw error;\r\n return result;\r\n });\r\n}\r\n\r\nfunction decode(value: string): Buffer {\r\n return Buffer.from(value.slice(3), \"base64\");\r\n}\r\n\r\n/**\r\n * A {@link Cache} whose entity caches are all {@link RedisEntityCache}s.\r\n */\r\nexport type RedisCache = {\r\n readonly [Name in CacheEntityName]: RedisEntityCache<CacheEntityTypes[Name]>;\r\n};\r\n\r\nexport interface RedisCacheOptions {\r\n /**\r\n * The Redis client to use, e.g. an [`ioredis`](https://github.com/redis/ioredis) instance.\r\n */\r\n redis: RedisClientLike;\r\n /**\r\n * The prefix of every Redis key owned by the cache, which allows several caches to share a database.\r\n *\r\n * @default \"wolfstar:cache\"\r\n */\r\n prefix?: string;\r\n /**\r\n * The compression algorithm to use for values of at least {@link RedisCacheOptions.compressionThreshold} bytes.\r\n *\r\n * @default \"none\"\r\n */\r\n compression?: RedisCacheCompression;\r\n /**\r\n * The minimum size, in bytes, a serialized value must reach to be compressed.\r\n *\r\n * @default 1024\r\n */\r\n compressionThreshold?: number;\r\n /**\r\n * The time-to-live per entity cache, in seconds. Entity caches left out never expire.\r\n */\r\n ttl?: Partial<Record<CacheEntityName, number>>;\r\n}\r\n\r\n/**\r\n * The default prefix of every Redis key owned by a cache created with {@link createRedisCache}.\r\n */\r\nexport const DefaultRedisCachePrefix = \"wolfstar:cache\";\r\n\r\n/**\r\n * Creates a {@link Cache} stored in Redis, optionally compressing its values.\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createRedisCache } from '@wolfstar/plugin-cache';\r\n * import { Redis } from 'ioredis';\r\n *\r\n * const cache = createRedisCache({\r\n * redis: new Redis(process.env.REDIS_URL!),\r\n * compression: 'gzip',\r\n * ttl: { guilds: 60 * 60, users: 30 * 60 },\r\n * });\r\n * ```\r\n *\r\n * @param options The options for the cache.\r\n */\r\nexport function createRedisCache(options: RedisCacheOptions): RedisCache & Cache {\r\n const {\r\n redis,\r\n prefix = DefaultRedisCachePrefix,\r\n compression,\r\n compressionThreshold,\r\n ttl,\r\n } = options;\r\n\r\n return Object.freeze(\r\n Object.fromEntries(\r\n CacheEntityNames.map((name) => [\r\n name,\r\n new RedisEntityCache(redis, {\r\n prefix: `${prefix}:${name}`,\r\n ttl: ttl?.[name],\r\n compression,\r\n compressionThreshold,\r\n }),\r\n ]),\r\n ) as RedisCache,\r\n );\r\n}\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/lib/keys.ts","../../src/lib/reactions.ts","../../src/lib/operations.ts","../../src/lib/gateway.ts","../../src/lib/memory.ts","../../src/lib/redis.ts"],"sourcesContent":["import type { Snowflake } from \"discord-api-types/v10\";\n\n/**\n * Creates a stable key for a guild-scoped entity.\n */\nexport function guildScopedKey(guildId: Snowflake, id: Snowflake): string {\n return `${guildId}:${id}`;\n}\n\n/**\n * Creates a stable key for a channel message.\n */\nexport function messageKey(channelId: Snowflake, messageId: Snowflake): string {\n return `${channelId}:${messageId}`;\n}\n\n/**\n * Creates a stable key for a guild member.\n */\nexport function memberKey(guildId: Snowflake, userId: Snowflake): string {\n return guildScopedKey(guildId, userId);\n}\n\n/**\n * Creates a stable key for a guild presence.\n */\nexport function presenceKey(guildId: Snowflake, userId: Snowflake): string {\n return guildScopedKey(guildId, userId);\n}\n\n/**\n * Creates a stable key for a guild voice state.\n */\nexport function voiceStateKey(guildId: Snowflake, userId: Snowflake): string {\n return guildScopedKey(guildId, userId);\n}\n\n/**\n * Creates a stable key for a guild role.\n */\nexport function roleKey(guildId: Snowflake, roleId: Snowflake): string {\n return guildScopedKey(guildId, roleId);\n}\n\n/**\n * Creates a stable key for a guild emoji.\n */\nexport function emojiKey(guildId: Snowflake, emojiId: Snowflake): string {\n return guildScopedKey(guildId, emojiId);\n}\n\n/**\n * Creates a stable key for a guild sticker.\n */\nexport function stickerKey(guildId: Snowflake, stickerId: Snowflake): string {\n return guildScopedKey(guildId, stickerId);\n}\n\n/**\n * Creates a stable key for a guild scheduled event.\n */\nexport function scheduledEventKey(guildId: Snowflake, scheduledEventId: Snowflake): string {\n return guildScopedKey(guildId, scheduledEventId);\n}\n\n/**\n * Creates a stable key for a stage instance.\n */\nexport function stageInstanceKey(guildId: Snowflake, channelId: Snowflake): string {\n return guildScopedKey(guildId, channelId);\n}\n\n/**\n * Creates a stable key for a guild soundboard sound.\n */\nexport function soundboardSoundKey(guildId: Snowflake, soundId: Snowflake): string {\n return guildScopedKey(guildId, soundId);\n}\n\n/**\n * Creates a stable key for a guild auto moderation rule.\n */\nexport function autoModerationRuleKey(guildId: Snowflake, ruleId: Snowflake): string {\n return guildScopedKey(guildId, ruleId);\n}\n\n/**\n * Creates a stable key for a guild ban.\n */\nexport function banKey(guildId: Snowflake, userId: Snowflake): string {\n return guildScopedKey(guildId, userId);\n}\n\n/**\n * Creates a stable key for a guild integration.\n */\nexport function integrationKey(guildId: Snowflake, integrationId: Snowflake): string {\n return guildScopedKey(guildId, integrationId);\n}\n\n/**\n * Creates a stable key for an invite, using `@global` for invites that do not belong to a guild.\n */\nexport function inviteKey(guildId: Snowflake | null | undefined, code: string): string {\n return `${guildId ?? \"@global\"}:${code}`;\n}\n\n/**\n * Creates a stable key for a thread member.\n */\nexport function threadMemberKey(threadId: Snowflake, userId: Snowflake): string {\n return `${threadId}:${userId}`;\n}\n\n/**\n * Creates a stable key for application command permissions.\n */\nexport function applicationCommandPermissionsKey(\n applicationId: Snowflake,\n guildId: Snowflake,\n commandId: Snowflake,\n): string {\n return `${applicationId}:${guildId}:${commandId}`;\n}\n","import type {\n APIMessage,\n APIPartialEmoji,\n APIReaction,\n GatewayMessagePollVoteDispatchData,\n GatewayMessageReactionAddDispatchData,\n GatewayMessageReactionRemoveDispatchData,\n} from \"discord-api-types/v10\";\n\n// Reactions and poll votes only carry the voter's ID, so whether the bot is the voter needs the bot's own ID.\n\n/**\n * Whether two reaction emojis are the same: custom emojis match by ID, Unicode emojis by name.\n */\nfunction isSameEmoji(a: APIPartialEmoji, b: APIPartialEmoji): boolean {\n return a.id ? a.id === b.id : !b.id && a.name === b.name;\n}\n\n/**\n * Adds a `MESSAGE_REACTION_ADD` to a cached message's reactions.\n *\n * @param message The cached message.\n * @param data The dispatch data.\n * @param clientUserId The bot's user ID, to set `me` when the bot reacted.\n */\nexport function addReaction(\n message: APIMessage,\n data: GatewayMessageReactionAddDispatchData,\n clientUserId?: string,\n): APIMessage {\n const me = data.user_id === clientUserId;\n const kind = data.burst ? \"burst\" : \"normal\";\n const reactions = message.reactions ?? [];\n const existing = reactions.find((reaction) => isSameEmoji(reaction.emoji, data.emoji));\n\n if (!existing) {\n const reaction: APIReaction = {\n emoji: data.emoji,\n count: 1,\n count_details: { normal: data.burst ? 0 : 1, burst: data.burst ? 1 : 0 },\n me: me && !data.burst,\n me_burst: me && data.burst,\n burst_colors: data.burst_colors ?? [],\n };\n return { ...message, reactions: [...reactions, reaction] };\n }\n\n return {\n ...message,\n reactions: reactions.map((reaction) =>\n reaction === existing\n ? {\n ...reaction,\n count: reaction.count + 1,\n count_details: {\n ...reaction.count_details,\n [kind]: reaction.count_details[kind] + 1,\n },\n me: reaction.me || (me && !data.burst),\n me_burst: reaction.me_burst || (me && data.burst),\n burst_colors: data.burst\n ? (data.burst_colors ?? reaction.burst_colors)\n : reaction.burst_colors,\n }\n : reaction,\n ),\n };\n}\n\n/**\n * Removes a `MESSAGE_REACTION_REMOVE` from a cached message's reactions, dropping the reaction when its count reaches\n * zero.\n *\n * @param message The cached message.\n * @param data The dispatch data.\n * @param clientUserId The bot's user ID, to clear `me` when the bot's reaction was removed.\n */\nexport function removeReaction(\n message: APIMessage,\n data: GatewayMessageReactionRemoveDispatchData,\n clientUserId?: string,\n): APIMessage {\n const me = data.user_id === clientUserId;\n const kind = data.burst ? \"burst\" : \"normal\";\n const reactions = (message.reactions ?? []).flatMap((reaction) => {\n if (!isSameEmoji(reaction.emoji, data.emoji)) return [reaction];\n if (reaction.count <= 1) return [];\n return [\n {\n ...reaction,\n count: reaction.count - 1,\n count_details: {\n ...reaction.count_details,\n [kind]: Math.max(0, reaction.count_details[kind] - 1),\n },\n me: reaction.me && !(me && !data.burst),\n me_burst: reaction.me_burst && !(me && data.burst),\n },\n ];\n });\n return { ...message, reactions };\n}\n\n/**\n * Removes every reaction with one emoji from a cached message.\n *\n * @param message The cached message.\n * @param emoji The emoji.\n */\nexport function removeReactionEmoji(message: APIMessage, emoji: APIPartialEmoji): APIMessage {\n return {\n ...message,\n reactions: (message.reactions ?? []).filter((reaction) => !isSameEmoji(reaction.emoji, emoji)),\n };\n}\n\n/**\n * Counts a `MESSAGE_POLL_VOTE_ADD` or `MESSAGE_POLL_VOTE_REMOVE` in a cached message's poll results.\n *\n * @param message The cached message.\n * @param data The dispatch data.\n * @param delta `1` for a vote, `-1` for a removed vote.\n * @param clientUserId The bot's user ID, to set `me_voted` when the bot voted.\n */\nexport function countPollVote(\n message: APIMessage,\n data: GatewayMessagePollVoteDispatchData,\n delta: 1 | -1,\n clientUserId?: string,\n): APIMessage {\n const { poll } = message;\n if (!poll) return message;\n\n const me = data.user_id === clientUserId;\n const results = poll.results ?? { is_finalized: false, answer_counts: [] };\n const counts = results.answer_counts.some((count) => count.id === data.answer_id)\n ? results.answer_counts\n : [...results.answer_counts, { id: data.answer_id, count: 0, me_voted: false }];\n\n return {\n ...message,\n poll: {\n ...poll,\n results: {\n ...results,\n answer_counts: counts.map((count) =>\n count.id === data.answer_id\n ? {\n ...count,\n count: Math.max(0, count.count + delta),\n me_voted: me ? delta === 1 : count.me_voted,\n }\n : count,\n ),\n },\n },\n };\n}\n","import { GatewayDispatchEvents } from \"discord-api-types/v10\";\nimport type {\n APIEmoji,\n APIMessage,\n APIGuildMember,\n APIRole,\n APISoundboardSound,\n APISticker,\n GatewayDispatchPayload,\n GatewayGuildCreateDispatchData,\n GatewayGuildMembersChunkDispatchData,\n GatewayGuildSoundboardSoundsUpdateDispatchData,\n GatewaySoundboardSoundsDispatchData,\n GatewayThreadListSync,\n GatewayThreadMembersUpdateDispatchData,\n Snowflake,\n} from \"discord-api-types/v10\";\nimport {\n applicationCommandPermissionsKey,\n autoModerationRuleKey,\n banKey,\n emojiKey,\n guildScopedKey,\n integrationKey,\n inviteKey,\n memberKey,\n messageKey,\n presenceKey,\n roleKey,\n scheduledEventKey,\n soundboardSoundKey,\n stageInstanceKey,\n stickerKey,\n threadMemberKey,\n voiceStateKey,\n} from \"./keys.js\";\nimport { addReaction, countPollVote, removeReaction, removeReactionEmoji } from \"./reactions.js\";\nimport type { Cache, CacheEntityName, EntityCache } from \"./types.js\";\n\n// A record rather than an array so the compiler enforces that every entity cache is listed.\nconst cacheEntityNameRecord: Record<CacheEntityName, true> = {\n applicationCommandPermissions: true,\n auditLogEntries: true,\n autoModerationRules: true,\n bans: true,\n channels: true,\n emojis: true,\n entitlements: true,\n guilds: true,\n integrations: true,\n invites: true,\n members: true,\n messages: true,\n presences: true,\n roles: true,\n scheduledEvents: true,\n soundboardSounds: true,\n stageInstances: true,\n stickers: true,\n subscriptions: true,\n threadMembers: true,\n threads: true,\n users: true,\n voiceStates: true,\n};\n\n/**\n * The name of every entity cache held by a {@link Cache}.\n */\nexport const CacheEntityNames = Object.keys(cacheEntityNameRecord) as readonly CacheEntityName[];\n\n/**\n * A single mutation a gateway dispatch produces on a {@link Cache}.\n */\nexport type CacheOperation =\n | {\n type: \"upsert\";\n store: CacheEntityName;\n key: string;\n raw: unknown;\n /** Whether to shallow-merge `raw` onto the existing value, used for partial updates. */\n merge?: boolean;\n }\n | {\n type: \"update\";\n store: CacheEntityName;\n key: string;\n /** Computes the new value from the cached one. Nothing is written when the key is not cached. */\n update: (value: unknown) => unknown;\n }\n | { type: \"delete\"; store: CacheEntityName; key: string }\n | { type: \"deletePrefix\"; store: CacheEntityName; prefix: string }\n | { type: \"deleteWhere\"; store: CacheEntityName; predicate: (value: unknown) => boolean };\n\n/**\n * What {@link createCacheOperations} needs to know besides the dispatch.\n */\nexport interface CacheOperationContext {\n /**\n * The bot's user ID. Reactions and poll votes only carry the voter's ID, so without it the cached `me` and\n * `me_voted` flags are never set.\n */\n clientUserId?: string;\n}\n\n/**\n * Translates a gateway dispatch into the list of {@link CacheOperation}s it implies, including the cascades (e.g.\n * `CHANNEL_DELETE` also drops that channel's messages).\n *\n * @remarks\n * This is a pure function, it does not touch any cache. Use {@link applyGatewayDispatch} to apply them.\n * `INTERACTION_CREATE` is intentionally ignored: interactions are short-lived and never cached.\n *\n * @param payload The gateway dispatch payload.\n * @param context The bot's user ID, for the `me` flags of reactions and poll votes.\n */\nexport function createCacheOperations(\n payload: GatewayDispatchPayload,\n context: CacheOperationContext = {},\n): CacheOperation[] {\n const { clientUserId } = context;\n const operations: CacheOperation[] = [];\n\n switch (payload.t) {\n case GatewayDispatchEvents.ApplicationCommandPermissionsUpdate: {\n const data = payload.d;\n operations.push({\n type: \"upsert\",\n store: \"applicationCommandPermissions\",\n key: applicationCommandPermissionsKey(data.application_id, data.guild_id, data.id),\n raw: data,\n });\n break;\n }\n\n case GatewayDispatchEvents.AutoModerationRuleCreate:\n case GatewayDispatchEvents.AutoModerationRuleUpdate: {\n const data = payload.d;\n operations.push({\n type: \"upsert\",\n store: \"autoModerationRules\",\n key: autoModerationRuleKey(data.guild_id, data.id),\n raw: data,\n });\n break;\n }\n\n case GatewayDispatchEvents.AutoModerationRuleDelete: {\n const data = payload.d;\n operations.push({\n type: \"delete\",\n store: \"autoModerationRules\",\n key: autoModerationRuleKey(data.guild_id, data.id),\n });\n break;\n }\n\n case GatewayDispatchEvents.ChannelCreate:\n case GatewayDispatchEvents.ChannelUpdate: {\n const data = payload.d;\n operations.push({\n type: \"upsert\",\n store: \"channels\",\n key: data.id,\n raw: data,\n merge: payload.t === GatewayDispatchEvents.ChannelUpdate,\n });\n break;\n }\n\n case GatewayDispatchEvents.ChannelDelete: {\n const data = payload.d;\n operations.push({ type: \"delete\", store: \"channels\", key: data.id });\n operations.push({ type: \"deletePrefix\", store: \"messages\", prefix: `${data.id}:` });\n break;\n }\n\n case GatewayDispatchEvents.EntitlementCreate:\n case GatewayDispatchEvents.EntitlementUpdate: {\n const data = payload.d;\n operations.push({ type: \"upsert\", store: \"entitlements\", key: data.id, raw: data });\n break;\n }\n\n case GatewayDispatchEvents.EntitlementDelete: {\n operations.push({ type: \"delete\", store: \"entitlements\", key: payload.d.id });\n break;\n }\n\n case GatewayDispatchEvents.GuildAuditLogEntryCreate: {\n const data = payload.d;\n operations.push({\n type: \"upsert\",\n store: \"auditLogEntries\",\n key: guildScopedKey(data.guild_id, data.id),\n raw: data,\n });\n break;\n }\n\n case GatewayDispatchEvents.GuildBanAdd: {\n const data = payload.d;\n operations.push({\n type: \"upsert\",\n store: \"bans\",\n key: banKey(data.guild_id, data.user.id),\n raw: data,\n });\n operations.push({ type: \"upsert\", store: \"users\", key: data.user.id, raw: data.user });\n break;\n }\n\n case GatewayDispatchEvents.GuildBanRemove: {\n const data = payload.d;\n operations.push({ type: \"delete\", store: \"bans\", key: banKey(data.guild_id, data.user.id) });\n operations.push({ type: \"upsert\", store: \"users\", key: data.user.id, raw: data.user });\n break;\n }\n\n case GatewayDispatchEvents.GuildCreate: {\n hydrateGuildCreate(operations, payload.d);\n break;\n }\n\n case GatewayDispatchEvents.GuildUpdate: {\n // Like `GUILD_CREATE`, the roles and emojis go to their own entity caches rather than the guild entry.\n const { roles, emojis, stickers, ...data } = payload.d;\n operations.push({ type: \"upsert\", store: \"guilds\", key: data.id, raw: data, merge: true });\n for (const role of roles ?? []) hydrateRole(operations, data.id, role);\n for (const emoji of emojis ?? []) hydrateEmoji(operations, data.id, emoji);\n for (const sticker of stickers ?? []) hydrateSticker(operations, data.id, sticker);\n break;\n }\n\n case GatewayDispatchEvents.GuildDelete: {\n const data = payload.d;\n // An `unavailable` guild is an outage, not a removal: keep its data around until it comes back.\n if (data.unavailable) {\n operations.push({ type: \"upsert\", store: \"guilds\", key: data.id, raw: data, merge: true });\n break;\n }\n\n operations.push({ type: \"delete\", store: \"guilds\", key: data.id });\n deleteGuildScopedResources(operations, data.id);\n break;\n }\n\n case GatewayDispatchEvents.GuildEmojisUpdate: {\n const data = payload.d;\n operations.push({ type: \"deletePrefix\", store: \"emojis\", prefix: `${data.guild_id}:` });\n for (const emoji of data.emojis) {\n if (!emoji.id) continue;\n operations.push({\n type: \"upsert\",\n store: \"emojis\",\n key: emojiKey(data.guild_id, emoji.id),\n raw: withGuildId(emoji, data.guild_id),\n });\n }\n break;\n }\n\n case GatewayDispatchEvents.GuildStickersUpdate: {\n const data = payload.d;\n operations.push({ type: \"deletePrefix\", store: \"stickers\", prefix: `${data.guild_id}:` });\n for (const sticker of data.stickers) {\n operations.push({\n type: \"upsert\",\n store: \"stickers\",\n key: stickerKey(data.guild_id, sticker.id),\n raw: withGuildId(sticker, data.guild_id),\n });\n }\n break;\n }\n\n case GatewayDispatchEvents.GuildMemberAdd:\n case GatewayDispatchEvents.GuildMemberUpdate: {\n const data = payload.d;\n operations.push({\n type: \"upsert\",\n store: \"members\",\n key: memberKey(data.guild_id, data.user.id),\n raw: data,\n merge: true,\n });\n operations.push({ type: \"upsert\", store: \"users\", key: data.user.id, raw: data.user });\n break;\n }\n\n case GatewayDispatchEvents.GuildMemberRemove: {\n const data = payload.d;\n operations.push({\n type: \"delete\",\n store: \"members\",\n key: memberKey(data.guild_id, data.user.id),\n });\n operations.push({ type: \"upsert\", store: \"users\", key: data.user.id, raw: data.user });\n break;\n }\n\n case GatewayDispatchEvents.GuildMembersChunk: {\n hydrateGuildMembersChunk(operations, payload.d);\n break;\n }\n\n case GatewayDispatchEvents.GuildRoleCreate:\n case GatewayDispatchEvents.GuildRoleUpdate: {\n const data = payload.d;\n operations.push({\n type: \"upsert\",\n store: \"roles\",\n key: roleKey(data.guild_id, data.role.id),\n raw: withGuildId(data.role, data.guild_id),\n merge: payload.t === GatewayDispatchEvents.GuildRoleUpdate,\n });\n break;\n }\n\n case GatewayDispatchEvents.GuildRoleDelete: {\n const data = payload.d;\n operations.push({\n type: \"delete\",\n store: \"roles\",\n key: roleKey(data.guild_id, data.role_id),\n });\n break;\n }\n\n case GatewayDispatchEvents.GuildScheduledEventCreate:\n case GatewayDispatchEvents.GuildScheduledEventUpdate: {\n const data = payload.d;\n operations.push({\n type: \"upsert\",\n store: \"scheduledEvents\",\n key: scheduledEventKey(data.guild_id, data.id),\n raw: data,\n merge: true,\n });\n if (data.creator) {\n operations.push({\n type: \"upsert\",\n store: \"users\",\n key: data.creator.id,\n raw: data.creator,\n });\n }\n break;\n }\n\n case GatewayDispatchEvents.GuildScheduledEventDelete: {\n const data = payload.d;\n operations.push({\n type: \"delete\",\n store: \"scheduledEvents\",\n key: scheduledEventKey(data.guild_id, data.id),\n });\n break;\n }\n\n case GatewayDispatchEvents.GuildSoundboardSoundCreate:\n case GatewayDispatchEvents.GuildSoundboardSoundUpdate: {\n const data = payload.d;\n if (!data.guild_id) break;\n operations.push({\n type: \"upsert\",\n store: \"soundboardSounds\",\n key: soundboardSoundKey(data.guild_id, data.sound_id),\n raw: data,\n merge: payload.t === GatewayDispatchEvents.GuildSoundboardSoundUpdate,\n });\n break;\n }\n\n case GatewayDispatchEvents.GuildSoundboardSoundDelete: {\n const data = payload.d;\n operations.push({\n type: \"delete\",\n store: \"soundboardSounds\",\n key: soundboardSoundKey(data.guild_id, data.sound_id),\n });\n break;\n }\n\n case GatewayDispatchEvents.GuildSoundboardSoundsUpdate: {\n hydrateGuildSoundboardSoundsUpdate(operations, payload.d);\n break;\n }\n\n case GatewayDispatchEvents.SoundboardSounds: {\n hydrateSoundboardSounds(operations, payload.d);\n break;\n }\n\n case GatewayDispatchEvents.IntegrationCreate:\n case GatewayDispatchEvents.IntegrationUpdate: {\n const data = payload.d;\n operations.push({\n type: \"upsert\",\n store: \"integrations\",\n key: integrationKey(data.guild_id, data.id),\n raw: data,\n merge: true,\n });\n break;\n }\n\n case GatewayDispatchEvents.IntegrationDelete: {\n const data = payload.d;\n operations.push({\n type: \"delete\",\n store: \"integrations\",\n key: integrationKey(data.guild_id, data.id),\n });\n break;\n }\n\n case GatewayDispatchEvents.InviteCreate: {\n const data = payload.d;\n operations.push({\n type: \"upsert\",\n store: \"invites\",\n key: inviteKey(data.guild_id, data.code),\n raw: data,\n });\n break;\n }\n\n case GatewayDispatchEvents.InviteDelete: {\n const data = payload.d;\n operations.push({\n type: \"delete\",\n store: \"invites\",\n key: inviteKey(data.guild_id, data.code),\n });\n break;\n }\n\n case GatewayDispatchEvents.MessageCreate:\n case GatewayDispatchEvents.MessageUpdate: {\n const data = payload.d;\n operations.push({\n type: \"upsert\",\n store: \"messages\",\n key: messageKey(data.channel_id, data.id),\n raw: data,\n merge: payload.t === GatewayDispatchEvents.MessageUpdate,\n });\n\n const author = \"author\" in data ? data.author : undefined;\n if (author) {\n operations.push({ type: \"upsert\", store: \"users\", key: author.id, raw: author });\n if (data.member && data.guild_id) {\n operations.push({\n type: \"upsert\",\n store: \"members\",\n key: memberKey(data.guild_id, author.id),\n raw: withGuildId(data.member, data.guild_id),\n merge: true,\n });\n }\n }\n break;\n }\n\n case GatewayDispatchEvents.MessageDelete: {\n const data = payload.d;\n operations.push({\n type: \"delete\",\n store: \"messages\",\n key: messageKey(data.channel_id, data.id),\n });\n break;\n }\n\n case GatewayDispatchEvents.MessageDeleteBulk: {\n const data = payload.d;\n for (const id of data.ids) {\n operations.push({\n type: \"delete\",\n store: \"messages\",\n key: messageKey(data.channel_id, id),\n });\n }\n break;\n }\n\n case GatewayDispatchEvents.MessageReactionAdd: {\n const data = payload.d;\n operations.push(\n updateMessage(data.channel_id, data.message_id, (message) =>\n addReaction(message, data, clientUserId),\n ),\n );\n // Guild reactions carry the reacting member, like messages carry their author.\n const user = data.member?.user;\n if (user && data.guild_id) {\n operations.push({ type: \"upsert\", store: \"users\", key: user.id, raw: user });\n operations.push({\n type: \"upsert\",\n store: \"members\",\n key: memberKey(data.guild_id, user.id),\n raw: withGuildId(data.member!, data.guild_id),\n merge: true,\n });\n }\n break;\n }\n\n case GatewayDispatchEvents.MessageReactionRemove: {\n const data = payload.d;\n operations.push(\n updateMessage(data.channel_id, data.message_id, (message) =>\n removeReaction(message, data, clientUserId),\n ),\n );\n break;\n }\n\n case GatewayDispatchEvents.MessageReactionRemoveAll: {\n const data = payload.d;\n operations.push(\n updateMessage(data.channel_id, data.message_id, (message) => ({\n ...message,\n reactions: [],\n })),\n );\n break;\n }\n\n case GatewayDispatchEvents.MessageReactionRemoveEmoji: {\n const data = payload.d;\n operations.push(\n updateMessage(data.channel_id, data.message_id, (message) =>\n removeReactionEmoji(message, data.emoji),\n ),\n );\n break;\n }\n\n case GatewayDispatchEvents.MessagePollVoteAdd:\n case GatewayDispatchEvents.MessagePollVoteRemove: {\n const data = payload.d;\n const delta = payload.t === GatewayDispatchEvents.MessagePollVoteAdd ? 1 : -1;\n operations.push(\n updateMessage(data.channel_id, data.message_id, (message) =>\n countPollVote(message, data, delta, clientUserId),\n ),\n );\n break;\n }\n\n case GatewayDispatchEvents.PresenceUpdate: {\n const data = payload.d;\n operations.push({\n type: \"upsert\",\n store: \"presences\",\n key: presenceKey(data.guild_id, data.user.id),\n raw: data,\n merge: true,\n });\n operations.push({\n type: \"upsert\",\n store: \"users\",\n key: data.user.id,\n raw: data.user,\n merge: true,\n });\n break;\n }\n\n case GatewayDispatchEvents.Ready: {\n const data = payload.d;\n operations.push({ type: \"upsert\", store: \"users\", key: data.user.id, raw: data.user });\n for (const guild of data.guilds) {\n operations.push({\n type: \"upsert\",\n store: \"guilds\",\n key: guild.id,\n raw: guild,\n merge: true,\n });\n }\n break;\n }\n\n case GatewayDispatchEvents.StageInstanceCreate:\n case GatewayDispatchEvents.StageInstanceUpdate: {\n const data = payload.d;\n operations.push({\n type: \"upsert\",\n store: \"stageInstances\",\n key: stageInstanceKey(data.guild_id, data.channel_id),\n raw: data,\n merge: true,\n });\n break;\n }\n\n case GatewayDispatchEvents.StageInstanceDelete: {\n const data = payload.d;\n operations.push({\n type: \"delete\",\n store: \"stageInstances\",\n key: stageInstanceKey(data.guild_id, data.channel_id),\n });\n break;\n }\n\n case GatewayDispatchEvents.SubscriptionCreate:\n case GatewayDispatchEvents.SubscriptionUpdate: {\n const data = payload.d;\n operations.push({ type: \"upsert\", store: \"subscriptions\", key: data.id, raw: data });\n break;\n }\n\n case GatewayDispatchEvents.SubscriptionDelete: {\n operations.push({ type: \"delete\", store: \"subscriptions\", key: payload.d.id });\n break;\n }\n\n case GatewayDispatchEvents.ThreadCreate:\n case GatewayDispatchEvents.ThreadUpdate: {\n const data = payload.d;\n operations.push({\n type: \"upsert\",\n store: \"threads\",\n key: data.id,\n raw: data,\n merge: payload.t === GatewayDispatchEvents.ThreadUpdate,\n });\n\n const member = \"member\" in data ? data.member : undefined;\n if (member?.user_id) {\n operations.push({\n type: \"upsert\",\n store: \"threadMembers\",\n key: threadMemberKey(data.id, member.user_id),\n // Thread members carry no guild ID of their own: without it, `GUILD_DELETE` could not sweep them.\n raw: data.guild_id ? withGuildId(member, data.guild_id) : member,\n merge: true,\n });\n }\n break;\n }\n\n case GatewayDispatchEvents.ThreadDelete: {\n const data = payload.d;\n operations.push({ type: \"delete\", store: \"threads\", key: data.id });\n operations.push({ type: \"deletePrefix\", store: \"threadMembers\", prefix: `${data.id}:` });\n operations.push({ type: \"deletePrefix\", store: \"messages\", prefix: `${data.id}:` });\n break;\n }\n\n case GatewayDispatchEvents.ThreadListSync: {\n hydrateThreadListSync(operations, payload.d);\n break;\n }\n\n case GatewayDispatchEvents.ThreadMemberUpdate: {\n const data = payload.d;\n if (!data.id || !data.user_id) break;\n operations.push({\n type: \"upsert\",\n store: \"threadMembers\",\n key: threadMemberKey(data.id, data.user_id),\n raw: data,\n merge: true,\n });\n break;\n }\n\n case GatewayDispatchEvents.ThreadMembersUpdate: {\n hydrateThreadMembersUpdate(operations, payload.d);\n break;\n }\n\n case GatewayDispatchEvents.UserUpdate: {\n const data = payload.d;\n operations.push({ type: \"upsert\", store: \"users\", key: data.id, raw: data, merge: true });\n break;\n }\n\n case GatewayDispatchEvents.VoiceStateUpdate: {\n const data = payload.d;\n if (!data.guild_id) break;\n\n const key = voiceStateKey(data.guild_id, data.user_id);\n if (data.channel_id) {\n operations.push({ type: \"upsert\", store: \"voiceStates\", key, raw: data, merge: true });\n } else {\n operations.push({ type: \"delete\", store: \"voiceStates\", key });\n }\n\n const user = data.member?.user;\n if (data.member && user) {\n operations.push({ type: \"upsert\", store: \"users\", key: user.id, raw: user });\n operations.push({\n type: \"upsert\",\n store: \"members\",\n key: memberKey(data.guild_id, user.id),\n raw: withGuildId(data.member, data.guild_id),\n merge: true,\n });\n }\n break;\n }\n\n default:\n break;\n }\n\n return operations;\n}\n\n/**\n * Applies a list of {@link CacheOperation}s to a {@link Cache}, sequentially and in order.\n *\n * @param cache The cache to mutate.\n * @param operations The operations to apply, usually created by {@link createCacheOperations}.\n */\nexport async function applyCacheOperations(\n cache: Cache,\n operations: readonly CacheOperation[],\n): Promise<void> {\n for (const operation of operations) {\n const store = cache[operation.store] as EntityCache<unknown>;\n\n switch (operation.type) {\n case \"upsert\": {\n const value = operation.merge\n ? mergeValues(await store.get(operation.key), operation.raw)\n : operation.raw;\n await store.set(operation.key, value);\n break;\n }\n case \"update\": {\n const existing = await store.get(operation.key);\n if (existing !== undefined) await store.set(operation.key, operation.update(existing));\n break;\n }\n case \"delete\":\n await store.delete(operation.key);\n break;\n case \"deletePrefix\":\n for (const key of await store.keys()) {\n if (key.startsWith(operation.prefix)) await store.delete(key);\n }\n break;\n case \"deleteWhere\":\n for (const [key, value] of await store.entries()) {\n if (operation.predicate(value)) await store.delete(key);\n }\n break;\n }\n }\n}\n\n/**\n * Writes a gateway dispatch into every relevant entity cache of a {@link Cache}.\n *\n * @param cache The cache to mutate.\n * @param payload The gateway dispatch payload.\n * @param context The bot's user ID, for the `me` flags of reactions and poll votes.\n */\nexport function applyGatewayDispatch(\n cache: Cache,\n payload: GatewayDispatchPayload,\n context?: CacheOperationContext,\n): Promise<void> {\n return applyCacheOperations(cache, createCacheOperations(payload, context));\n}\n\n/**\n * Shallow-merges `value` onto `existing` when both are plain objects, returning `value` otherwise.\n */\nexport function mergeValues<Value>(existing: Value | undefined, value: Value): Value {\n if (isObject(existing) && isObject(value)) return { ...existing, ...value };\n return value;\n}\n\nfunction hydrateGuildCreate(\n operations: CacheOperation[],\n guild: GatewayGuildCreateDispatchData,\n): void {\n // Unavailable guilds carry no data besides their ID, see `GuildDelete`.\n if (\"unavailable\" in guild && guild.unavailable) {\n operations.push({ type: \"upsert\", store: \"guilds\", key: guild.id, raw: guild, merge: true });\n return;\n }\n\n const {\n channels,\n threads,\n members,\n presences,\n voice_states: voiceStates,\n stage_instances: stageInstances,\n guild_scheduled_events: scheduledEvents,\n soundboard_sounds: soundboardSounds,\n roles,\n emojis,\n stickers,\n ...rest\n } = guild;\n // Collections are stored in their own entity caches, keeping the guild entry small.\n operations.push({ type: \"upsert\", store: \"guilds\", key: guild.id, raw: rest });\n\n for (const channel of channels ?? []) {\n operations.push({\n type: \"upsert\",\n store: \"channels\",\n key: channel.id,\n raw: withGuildId(channel, guild.id),\n });\n }\n\n for (const thread of threads ?? []) {\n operations.push({\n type: \"upsert\",\n store: \"threads\",\n key: thread.id,\n raw: withGuildId(thread, guild.id),\n });\n if (thread.member?.user_id) {\n operations.push({\n type: \"upsert\",\n store: \"threadMembers\",\n key: threadMemberKey(thread.id, thread.member.user_id),\n raw: withGuildId(thread.member, guild.id),\n });\n }\n }\n\n for (const member of members ?? []) hydrateMember(operations, guild.id, member);\n\n for (const presence of presences ?? []) {\n operations.push({\n type: \"upsert\",\n store: \"presences\",\n key: presenceKey(guild.id, presence.user.id),\n raw: withGuildId(presence, guild.id),\n });\n }\n\n for (const role of roles ?? []) hydrateRole(operations, guild.id, role);\n for (const emoji of emojis ?? []) hydrateEmoji(operations, guild.id, emoji);\n for (const sticker of stickers ?? []) hydrateSticker(operations, guild.id, sticker);\n\n for (const voiceState of voiceStates ?? []) {\n if (!voiceState.channel_id) continue;\n operations.push({\n type: \"upsert\",\n store: \"voiceStates\",\n key: voiceStateKey(guild.id, voiceState.user_id),\n raw: withGuildId(voiceState, guild.id),\n });\n }\n\n for (const stageInstance of stageInstances ?? []) {\n operations.push({\n type: \"upsert\",\n store: \"stageInstances\",\n key: stageInstanceKey(guild.id, stageInstance.channel_id),\n raw: stageInstance,\n });\n }\n\n for (const scheduledEvent of scheduledEvents ?? []) {\n operations.push({\n type: \"upsert\",\n store: \"scheduledEvents\",\n key: scheduledEventKey(guild.id, scheduledEvent.id),\n raw: scheduledEvent,\n });\n }\n\n for (const sound of soundboardSounds ?? []) hydrateSoundboardSound(operations, guild.id, sound);\n}\n\nfunction hydrateGuildMembersChunk(\n operations: CacheOperation[],\n data: GatewayGuildMembersChunkDispatchData,\n): void {\n for (const member of data.members) hydrateMember(operations, data.guild_id, member);\n for (const presence of data.presences ?? []) {\n operations.push({\n type: \"upsert\",\n store: \"presences\",\n key: presenceKey(data.guild_id, presence.user.id),\n raw: withGuildId(presence, data.guild_id),\n });\n }\n}\n\nfunction hydrateGuildSoundboardSoundsUpdate(\n operations: CacheOperation[],\n data: GatewayGuildSoundboardSoundsUpdateDispatchData,\n): void {\n operations.push({ type: \"deletePrefix\", store: \"soundboardSounds\", prefix: `${data.guild_id}:` });\n for (const sound of data.soundboard_sounds)\n hydrateSoundboardSound(operations, data.guild_id, sound);\n}\n\nfunction hydrateSoundboardSounds(\n operations: CacheOperation[],\n data: GatewaySoundboardSoundsDispatchData,\n): void {\n for (const sound of data.soundboard_sounds)\n hydrateSoundboardSound(operations, data.guild_id, sound);\n}\n\nfunction hydrateThreadListSync(operations: CacheOperation[], data: GatewayThreadListSync): void {\n for (const thread of data.threads) {\n operations.push({\n type: \"upsert\",\n store: \"threads\",\n key: thread.id,\n raw: withGuildId(thread, data.guild_id),\n merge: true,\n });\n }\n\n for (const member of data.members) {\n if (!member.id || !member.user_id) continue;\n operations.push({\n type: \"upsert\",\n store: \"threadMembers\",\n key: threadMemberKey(member.id, member.user_id),\n raw: withGuildId(member, data.guild_id),\n merge: true,\n });\n }\n}\n\nfunction hydrateThreadMembersUpdate(\n operations: CacheOperation[],\n data: GatewayThreadMembersUpdateDispatchData,\n): void {\n for (const member of data.added_members ?? []) {\n if (!member.user_id) continue;\n operations.push({\n type: \"upsert\",\n store: \"threadMembers\",\n key: threadMemberKey(data.id, member.user_id),\n raw: withGuildId(member, data.guild_id),\n merge: true,\n });\n }\n\n for (const userId of data.removed_member_ids ?? []) {\n operations.push({\n type: \"delete\",\n store: \"threadMembers\",\n key: threadMemberKey(data.id, userId),\n });\n }\n}\n\nfunction hydrateMember(\n operations: CacheOperation[],\n guildId: Snowflake,\n member: APIGuildMember,\n): void {\n if (!member.user) return;\n\n operations.push({\n type: \"upsert\",\n store: \"members\",\n key: memberKey(guildId, member.user.id),\n raw: withGuildId(member, guildId),\n merge: true,\n });\n operations.push({ type: \"upsert\", store: \"users\", key: member.user.id, raw: member.user });\n}\n\nfunction hydrateRole(operations: CacheOperation[], guildId: Snowflake, role: APIRole): void {\n operations.push({\n type: \"upsert\",\n store: \"roles\",\n key: roleKey(guildId, role.id),\n raw: withGuildId(role, guildId),\n });\n}\n\nfunction hydrateEmoji(operations: CacheOperation[], guildId: Snowflake, emoji: APIEmoji): void {\n if (!emoji.id) return;\n operations.push({\n type: \"upsert\",\n store: \"emojis\",\n key: emojiKey(guildId, emoji.id),\n raw: withGuildId(emoji, guildId),\n });\n}\n\nfunction hydrateSticker(\n operations: CacheOperation[],\n guildId: Snowflake,\n sticker: APISticker,\n): void {\n operations.push({\n type: \"upsert\",\n store: \"stickers\",\n key: stickerKey(guildId, sticker.id),\n raw: withGuildId(sticker, guildId),\n });\n}\n\nfunction hydrateSoundboardSound(\n operations: CacheOperation[],\n guildId: Snowflake,\n sound: APISoundboardSound,\n): void {\n operations.push({\n type: \"upsert\",\n store: \"soundboardSounds\",\n key: soundboardSoundKey(guildId, sound.sound_id),\n raw: withGuildId(sound, guildId),\n });\n}\n\nfunction deleteGuildScopedResources(operations: CacheOperation[], guildId: Snowflake): void {\n // Entities keyed by `${guildId}:...` can be dropped by prefix, which is cheap.\n const prefixed = [\n \"auditLogEntries\",\n \"autoModerationRules\",\n \"bans\",\n \"emojis\",\n \"integrations\",\n \"members\",\n \"presences\",\n \"roles\",\n \"scheduledEvents\",\n \"soundboardSounds\",\n \"stageInstances\",\n \"stickers\",\n \"voiceStates\",\n ] as const satisfies readonly CacheEntityName[];\n\n for (const store of prefixed) {\n operations.push({ type: \"deletePrefix\", store, prefix: `${guildId}:` });\n }\n\n // The rest are keyed by their own ID and need a scan over the stored `guild_id`.\n const scanned = [\n \"applicationCommandPermissions\",\n \"channels\",\n \"threads\",\n \"threadMembers\",\n \"messages\",\n \"invites\",\n ] as const satisfies readonly CacheEntityName[];\n\n for (const store of scanned) {\n operations.push({\n type: \"deleteWhere\",\n store,\n predicate: (value) => isObject(value) && value.guild_id === guildId,\n });\n }\n}\n\n// An `update` of a cached message; a message the cache does not hold stays uncached.\nfunction updateMessage(\n channelId: Snowflake,\n messageId: Snowflake,\n update: (message: APIMessage) => APIMessage,\n): CacheOperation {\n return {\n type: \"update\",\n store: \"messages\",\n key: messageKey(channelId, messageId),\n update: (value) => update(value as APIMessage),\n };\n}\n\nfunction withGuildId<Value extends object>(\n value: Value,\n guildId: Snowflake,\n): Value & { guild_id: Snowflake } {\n return { ...value, guild_id: guildId };\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import type { GatewayDispatchPayload } from \"discord-api-types/v10\";\nimport { applyGatewayDispatch, type CacheOperationContext } from \"./operations.js\";\nimport type { Cache } from \"./types.js\";\n\n/** A gateway that emits the dispatch event used by @discordjs/ws and @discordjs/core. */\nexport interface GatewayDispatchSource {\n on(\n event: \"dispatch\",\n listener: (payload: GatewayDispatchPayload, shardId: number) => void,\n ): unknown;\n off?(\n event: \"dispatch\",\n listener: (payload: GatewayDispatchPayload, shardId: number) => void,\n ): unknown;\n}\n\nexport interface CacheGatewayOptions extends CacheOperationContext {\n /** Receives cache write failures from the asynchronous gateway listener. */\n onError?: (error: unknown, payload: GatewayDispatchPayload, shardId: number) => void;\n}\n\n/**\n * Writes gateway dispatches into a cache. Call the returned function to stop listening.\n * Use this when a gateway has no GatewayClient managing its dispatch queue.\n */\nexport function attachCacheToGateway(\n gateway: GatewayDispatchSource,\n cache: Cache,\n options: CacheGatewayOptions = {},\n): () => void {\n const listener = (payload: GatewayDispatchPayload, shardId: number): void => {\n void applyGatewayDispatch(cache, payload, { clientUserId: options.clientUserId }).catch(\n (error) => {\n if (options.onError) options.onError(error, payload, shardId);\n else console.error(\"Failed to cache gateway dispatch\", error);\n },\n );\n };\n\n gateway.on(\"dispatch\", listener);\n return () => gateway.off?.(\"dispatch\", listener);\n}\n","import { CacheEntityNames } from \"./operations.js\";\nimport type { Cache, CacheEntityName, CacheEntityTypes, EntityCache } from \"./types.js\";\n\n/**\n * An {@link EntityCache} backed by a `Map`, optionally bounded as a least-recently-used cache.\n */\nexport class MemoryEntityCache<Raw> implements EntityCache<Raw> {\n /**\n * The maximum amount of entries, `Infinity` for an unbounded cache.\n */\n public readonly maxSize: number;\n\n readonly #items = new Map<string, Raw>();\n\n public constructor(maxSize = Infinity) {\n if (maxSize !== Infinity && (!Number.isInteger(maxSize) || maxSize < 0)) {\n throw new RangeError(\n `maxSize must be a non-negative integer or Infinity, received ${maxSize}`,\n );\n }\n\n this.maxSize = maxSize;\n }\n\n public get(key: string): Raw | undefined {\n const value = this.#items.get(key);\n if (value !== undefined && this.maxSize !== Infinity) {\n // Re-insert to mark the entry as the most recently used one.\n this.#items.delete(key);\n this.#items.set(key, value);\n }\n\n return value;\n }\n\n public set(key: string, value: Raw): void {\n if (this.maxSize === 0) return;\n\n this.#items.delete(key);\n this.#items.set(key, value);\n\n if (this.#items.size > this.maxSize) {\n // Maps iterate in insertion order, so the first key is the least recently used one.\n this.#items.delete(this.#items.keys().next().value!);\n }\n }\n\n public has(key: string): boolean {\n return this.#items.has(key);\n }\n\n public delete(key: string): boolean {\n return this.#items.delete(key);\n }\n\n public clear(): void {\n this.#items.clear();\n }\n\n public getSize(): number {\n return this.#items.size;\n }\n\n public keys(): string[] {\n return [...this.#items.keys()];\n }\n\n public values(): Raw[] {\n return [...this.#items.values()];\n }\n\n public entries(): [key: string, value: Raw][] {\n return [...this.#items.entries()];\n }\n}\n\n/**\n * A {@link Cache} whose entity caches are all {@link MemoryEntityCache}s.\n */\nexport type InMemoryCache = {\n readonly [Name in CacheEntityName]: MemoryEntityCache<CacheEntityTypes[Name]>;\n};\n\nexport interface InMemoryCacheOptions {\n /**\n * The maximum amount of entries kept per entity cache before evicting the least recently used ones, either for\n * every entity cache or per entity cache. Entity caches left out are unbounded.\n *\n * @default Infinity\n */\n maxSize?: number | Partial<Record<CacheEntityName, number>>;\n}\n\n/**\n * Creates a {@link Cache} that keeps everything in the process' memory.\n *\n * @example\n * ```typescript\n * import { createInMemoryCache } from '@wolfstar/plugin-cache';\n *\n * // Keep at most 1000 messages around, everything else is unbounded.\n * const cache = createInMemoryCache({ maxSize: { messages: 1_000 } });\n * ```\n *\n * @param options The options for the cache.\n */\nexport function createInMemoryCache(options: InMemoryCacheOptions = {}): InMemoryCache & Cache {\n const { maxSize } = options;\n const resolve = (name: CacheEntityName) =>\n typeof maxSize === \"number\" ? maxSize : (maxSize?.[name] ?? Infinity);\n\n return Object.freeze(\n Object.fromEntries(\n CacheEntityNames.map((name) => [name, new MemoryEntityCache(resolve(name))]),\n ) as InMemoryCache,\n );\n}\n","/// <reference types=\"node\" />\nimport { promisify } from \"node:util\";\nimport { brotliCompress, brotliDecompress, gunzip, gzip } from \"node:zlib\";\nimport { CacheEntityNames } from \"./operations.js\";\nimport type { Cache, CacheEntityName, CacheEntityTypes, EntityCache } from \"./types.js\";\n\nconst gzipAsync = promisify(gzip);\nconst gunzipAsync = promisify(gunzip);\nconst brotliCompressAsync = promisify(brotliCompress);\nconst brotliDecompressAsync = promisify(brotliDecompress);\n\n/**\n * The subset of the [`ioredis`](https://github.com/redis/ioredis) client API the Redis cache relies on. An `ioredis`\n * `Redis` or `Cluster` instance satisfies it, as can any other client exposing the same commands.\n */\nexport interface RedisClientLike {\n get(key: string): Promise<string | null>;\n mget(...keys: string[]): Promise<(string | null)[]>;\n set(key: string, value: string): Promise<unknown>;\n set(key: string, value: string, mode: \"PX\", milliseconds: number): Promise<unknown>;\n del(...keys: string[]): Promise<number>;\n exists(...keys: string[]): Promise<number>;\n zadd(key: string, ...scoreMembers: (string | number)[]): Promise<unknown>;\n zrem(key: string, ...members: string[]): Promise<number>;\n zrange(key: string, start: string, stop: string): Promise<string[]>;\n zcard(key: string): Promise<number>;\n zremrangebyscore(key: string, min: number | string, max: number | string): Promise<number>;\n multi(): RedisTransactionLike;\n}\n\n/**\n * The subset of an [`ioredis`](https://github.com/redis/ioredis) `MULTI` transaction the Redis cache relies on: every\n * queued command returns the transaction, and `exec` runs them atomically.\n */\nexport interface RedisTransactionLike {\n set(key: string, value: string): RedisTransactionLike;\n set(key: string, value: string, mode: \"PX\", milliseconds: number): RedisTransactionLike;\n del(...keys: string[]): RedisTransactionLike;\n zadd(key: string, ...scoreMembers: (string | number)[]): RedisTransactionLike;\n zrem(key: string, ...members: string[]): RedisTransactionLike;\n zremrangebyscore(key: string, min: number | string, max: number | string): RedisTransactionLike;\n exec(): Promise<[error: Error | null, result: unknown][] | null>;\n}\n\n/**\n * Thrown when a value stored in Redis cannot be read back: invalid JSON, or compressed bytes that fail to decompress.\n *\n * @remarks\n * A missing value is not an error, `get` resolves to `undefined` for it. Redis connection errors are not wrapped\n * either, they propagate as the client throws them.\n */\nexport class CacheValueError extends Error {\n /**\n * The Redis key holding the unreadable value.\n */\n public readonly key: string;\n\n public constructor(key: string, cause: unknown) {\n super(`Cannot read the cached value at \"${key}\"`, { cause });\n this.name = \"CacheValueError\";\n this.key = key;\n }\n}\n\n/**\n * The algorithm used to compress values before writing them to Redis.\n */\nexport type RedisCacheCompression = \"gzip\" | \"brotli\" | \"none\";\n\nexport interface RedisEntityCacheOptions {\n /**\n * The prefix of every Redis key owned by this entity cache.\n */\n prefix: string;\n /**\n * The time-to-live of every entry, in seconds. Entries never expire when omitted.\n */\n ttl?: number;\n /**\n * The compression algorithm to use.\n *\n * @default \"none\"\n */\n compression?: RedisCacheCompression;\n /**\n * The minimum size, in bytes, a serialized value must reach to be compressed. Small payloads rarely benefit from it.\n *\n * @default 1024\n */\n compressionThreshold?: number;\n}\n\n// Compressed values are stored as `<marker><base64>`. JSON can never start with either marker, so values written with\n// a different `compression` setting (e.g. before it was turned on) are still read back correctly.\nconst CompressionMarkers = { gzip: \"gz:\", brotli: \"br:\" } as const;\n\n/**\n * An {@link EntityCache} backed by Redis.\n *\n * @remarks\n * Every entry is stored as its own string key (`<prefix>:<key>`), and a sorted set (`<prefix>:@index`) tracks the\n * stored keys with their expiration time as score, which is what `keys`, `entries`, `getSize`, and `clear` read from.\n */\nexport class RedisEntityCache<Raw> implements EntityCache<Raw> {\n public readonly prefix: string;\n public readonly ttl: number | undefined;\n public readonly compression: RedisCacheCompression;\n public readonly compressionThreshold: number;\n\n readonly #redis: RedisClientLike;\n\n public constructor(redis: RedisClientLike, options: RedisEntityCacheOptions) {\n if (options.ttl !== undefined && !(options.ttl > 0)) {\n throw new RangeError(`ttl must be a positive amount of seconds, received ${options.ttl}`);\n }\n\n this.#redis = redis;\n this.prefix = options.prefix;\n this.ttl = options.ttl;\n this.compression = options.compression ?? \"none\";\n this.compressionThreshold = options.compressionThreshold ?? 1024;\n }\n\n public async get(key: string): Promise<Raw | undefined> {\n const valueKey = this.valueKey(key);\n const value = await this.#redis.get(valueKey);\n return value === null ? undefined : this.deserialize(valueKey, value);\n }\n\n public async set(key: string, value: Raw): Promise<void> {\n const serialized = await this.serialize(value);\n // The value and its index entry are written in one transaction, so neither can exist without the other.\n const transaction = this.#redis.multi();\n if (this.ttl === undefined) {\n transaction.set(this.valueKey(key), serialized).zadd(this.indexKey, \"+inf\", key);\n } else {\n const now = Date.now();\n const milliseconds = Math.round(this.ttl * 1000);\n transaction\n .set(this.valueKey(key), serialized, \"PX\", milliseconds)\n .zadd(this.indexKey, now + milliseconds, key)\n // Pruning on every write keeps the index bounded even when nothing ever enumerates it.\n .zremrangebyscore(this.indexKey, \"-inf\", now);\n }\n\n await execute(transaction);\n }\n\n public async has(key: string): Promise<boolean> {\n return (await this.#redis.exists(this.valueKey(key))) > 0;\n }\n\n public async delete(key: string): Promise<boolean> {\n const [deleted] = await execute(\n this.#redis.multi().del(this.valueKey(key)).zrem(this.indexKey, key),\n );\n return (deleted as number) > 0;\n }\n\n public async clear(): Promise<void> {\n const keys = await this.#redis.zrange(this.indexKey, \"0\", \"-1\");\n if (keys.length > 0) await this.#redis.del(...keys.map((key) => this.valueKey(key)));\n await this.#redis.del(this.indexKey);\n }\n\n public async getSize(): Promise<number> {\n await this.prune();\n return this.#redis.zcard(this.indexKey);\n }\n\n public async keys(): Promise<string[]> {\n await this.prune();\n return this.#redis.zrange(this.indexKey, \"0\", \"-1\");\n }\n\n public async values(): Promise<Raw[]> {\n return (await this.entries()).map(([, value]) => value);\n }\n\n public async entries(): Promise<[key: string, value: Raw][]> {\n const keys = await this.keys();\n if (keys.length === 0) return [];\n\n const values = await this.#redis.mget(...keys.map((key) => this.valueKey(key)));\n const entries: [key: string, value: Raw][] = [];\n for (const [index, value] of values.entries()) {\n // The value may have been evicted by Redis between both reads.\n if (value !== null) {\n const key = keys[index]!;\n entries.push([key, await this.deserialize(this.valueKey(key), value)]);\n }\n }\n\n return entries;\n }\n\n /**\n * Gets the Redis key a value is stored at.\n * @param key The entity cache key.\n */\n public valueKey(key: string): string {\n return `${this.prefix}:${key}`;\n }\n\n /**\n * The Redis key of the sorted set indexing the stored keys.\n */\n public get indexKey(): string {\n return `${this.prefix}:@index`;\n }\n\n private async prune(): Promise<void> {\n if (this.ttl !== undefined)\n await this.#redis.zremrangebyscore(this.indexKey, \"-inf\", Date.now());\n }\n\n private async serialize(value: Raw): Promise<string> {\n const json = JSON.stringify(value);\n if (this.compression === \"none\" || Buffer.byteLength(json) < this.compressionThreshold) {\n return json;\n }\n\n const compressed =\n this.compression === \"gzip\" ? await gzipAsync(json) : await brotliCompressAsync(json);\n return `${CompressionMarkers[this.compression]}${compressed.toString(\"base64\")}`;\n }\n\n private async deserialize(valueKey: string, value: string): Promise<Raw> {\n try {\n if (value.startsWith(CompressionMarkers.gzip)) {\n return JSON.parse((await gunzipAsync(decode(value))).toString(\"utf8\")) as Raw;\n }\n\n if (value.startsWith(CompressionMarkers.brotli)) {\n return JSON.parse((await brotliDecompressAsync(decode(value))).toString(\"utf8\")) as Raw;\n }\n\n return JSON.parse(value) as Raw;\n } catch (error) {\n throw new CacheValueError(valueKey, error);\n }\n }\n}\n\n/**\n * Runs a transaction, throwing the first command error, and resolves to the command results.\n */\nasync function execute(transaction: RedisTransactionLike): Promise<unknown[]> {\n const results = await transaction.exec();\n if (results === null) throw new Error(\"The Redis transaction was aborted\");\n\n return results.map(([error, result]) => {\n if (error) throw error;\n return result;\n });\n}\n\nfunction decode(value: string): Buffer {\n return Buffer.from(value.slice(3), \"base64\");\n}\n\n/**\n * A {@link Cache} whose entity caches are all {@link RedisEntityCache}s.\n */\nexport type RedisCache = {\n readonly [Name in CacheEntityName]: RedisEntityCache<CacheEntityTypes[Name]>;\n};\n\nexport interface RedisCacheOptions {\n /**\n * The Redis client to use, e.g. an [`ioredis`](https://github.com/redis/ioredis) instance.\n */\n redis: RedisClientLike;\n /**\n * The prefix of every Redis key owned by the cache, which allows several caches to share a database.\n *\n * @default \"wolfstar:cache\"\n */\n prefix?: string;\n /**\n * The compression algorithm to use for values of at least {@link RedisCacheOptions.compressionThreshold} bytes.\n *\n * @default \"none\"\n */\n compression?: RedisCacheCompression;\n /**\n * The minimum size, in bytes, a serialized value must reach to be compressed.\n *\n * @default 1024\n */\n compressionThreshold?: number;\n /**\n * The time-to-live per entity cache, in seconds. Entity caches left out never expire.\n */\n ttl?: Partial<Record<CacheEntityName, number>>;\n}\n\n/**\n * The default prefix of every Redis key owned by a cache created with {@link createRedisCache}.\n */\nexport const DefaultRedisCachePrefix = \"wolfstar:cache\";\n\n/**\n * Creates a {@link Cache} stored in Redis, optionally compressing its values.\n *\n * @example\n * ```typescript\n * import { createRedisCache } from '@wolfstar/plugin-cache';\n * import { Redis } from 'ioredis';\n *\n * const cache = createRedisCache({\n * redis: new Redis(process.env.REDIS_URL!),\n * compression: 'gzip',\n * ttl: { guilds: 60 * 60, users: 30 * 60 },\n * });\n * ```\n *\n * @param options The options for the cache.\n */\nexport function createRedisCache(options: RedisCacheOptions): RedisCache & Cache {\n const {\n redis,\n prefix = DefaultRedisCachePrefix,\n compression,\n compressionThreshold,\n ttl,\n } = options;\n\n return Object.freeze(\n Object.fromEntries(\n CacheEntityNames.map((name) => [\n name,\n new RedisEntityCache(redis, {\n prefix: `${prefix}:${name}`,\n ttl: ttl?.[name],\n compression,\n compressionThreshold,\n }),\n ]),\n ) as RedisCache,\n );\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wolfstar/plugin-cache",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.0-next-20260926145943",
|
|
4
4
|
"description": "Pluggable, storage-agnostic Discord entity cache (in-memory and Redis, with optional compression) for @wolfstar/plugin-gateway",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cache",
|