seyfert 4.5.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/lib/api/Routes/cdn.d.ts +2 -2
  2. package/lib/api/Routes/guilds.d.ts +2 -2
  3. package/lib/api/Routes/invites.d.ts +2 -2
  4. package/lib/api/api.d.ts +20 -8
  5. package/lib/api/api.js +198 -44
  6. package/lib/api/shared.d.ts +30 -1
  7. package/lib/api/utils/constants.d.ts +1 -1
  8. package/lib/api/utils/constants.js +1 -1
  9. package/lib/api/utils/utils.d.ts +2 -1
  10. package/lib/api/utils/utils.js +1 -1
  11. package/lib/builders/Attachment.d.ts +1 -1
  12. package/lib/builders/Attachment.js +30 -8
  13. package/lib/builders/MediaGallery.d.ts +2 -2
  14. package/lib/builders/MediaGallery.js +10 -0
  15. package/lib/builders/Modal.d.ts +18 -8
  16. package/lib/builders/Modal.js +36 -7
  17. package/lib/builders/Poll.js +18 -0
  18. package/lib/builders/RadioGroup.d.ts +4 -3
  19. package/lib/builders/RadioGroup.js +24 -3
  20. package/lib/builders/SelectMenu.d.ts +8 -6
  21. package/lib/builders/SelectMenu.js +24 -3
  22. package/lib/builders/types.d.ts +3 -2
  23. package/lib/cache/adapters/default.d.ts +1 -1
  24. package/lib/cache/adapters/default.js +23 -26
  25. package/lib/cache/adapters/limited.d.ts +1 -0
  26. package/lib/cache/adapters/limited.js +47 -33
  27. package/lib/cache/index.d.ts +19 -25
  28. package/lib/cache/index.js +58 -6
  29. package/lib/cache/resources/bans.d.ts +1 -1
  30. package/lib/cache/resources/bans.js +4 -4
  31. package/lib/cache/resources/channels.d.ts +1 -1
  32. package/lib/cache/resources/channels.js +4 -4
  33. package/lib/cache/resources/default/base.d.ts +1 -1
  34. package/lib/cache/resources/default/base.js +8 -8
  35. package/lib/cache/resources/default/guild-based.d.ts +5 -5
  36. package/lib/cache/resources/default/guild-based.js +29 -16
  37. package/lib/cache/resources/default/guild-related.d.ts +5 -5
  38. package/lib/cache/resources/default/guild-related.js +14 -14
  39. package/lib/cache/resources/emojis.d.ts +1 -1
  40. package/lib/cache/resources/emojis.js +4 -4
  41. package/lib/cache/resources/guilds.js +28 -15
  42. package/lib/cache/resources/members.d.ts +1 -1
  43. package/lib/cache/resources/members.js +6 -6
  44. package/lib/cache/resources/messages.d.ts +7 -2
  45. package/lib/cache/resources/messages.js +43 -20
  46. package/lib/cache/resources/overwrites.d.ts +1 -1
  47. package/lib/cache/resources/overwrites.js +5 -8
  48. package/lib/cache/resources/roles.d.ts +1 -1
  49. package/lib/cache/resources/roles.js +4 -4
  50. package/lib/cache/resources/stickers.d.ts +1 -1
  51. package/lib/cache/resources/stickers.js +4 -4
  52. package/lib/cache/resources/users.js +4 -4
  53. package/lib/cache/resources/voice-states.d.ts +1 -1
  54. package/lib/cache/resources/voice-states.js +4 -4
  55. package/lib/client/base.d.ts +83 -24
  56. package/lib/client/base.js +594 -39
  57. package/lib/client/client.d.ts +28 -3
  58. package/lib/client/client.js +33 -9
  59. package/lib/client/collectors.d.ts +9 -8
  60. package/lib/client/collectors.js +19 -52
  61. package/lib/client/httpclient.d.ts +3 -0
  62. package/lib/client/index.d.ts +3 -1
  63. package/lib/client/index.js +4 -0
  64. package/lib/client/intents.d.ts +3 -0
  65. package/lib/client/intents.js +9 -0
  66. package/lib/client/plugins/api.d.ts +4 -0
  67. package/lib/client/plugins/api.js +550 -0
  68. package/lib/client/plugins/errors.d.ts +25 -0
  69. package/lib/client/plugins/errors.js +79 -0
  70. package/lib/client/plugins/order.d.ts +10 -0
  71. package/lib/client/plugins/order.js +32 -0
  72. package/lib/client/plugins/registry.d.ts +273 -0
  73. package/lib/client/plugins/registry.js +868 -0
  74. package/lib/client/plugins/shared.d.ts +23 -0
  75. package/lib/client/plugins/shared.js +193 -0
  76. package/lib/client/plugins/types.d.ts +398 -0
  77. package/lib/client/plugins/types.js +8 -0
  78. package/lib/client/plugins.d.ts +78 -0
  79. package/lib/client/plugins.js +558 -0
  80. package/lib/client/transformers.d.ts +33 -33
  81. package/lib/client/workerclient.d.ts +10 -1
  82. package/lib/client/workerclient.js +27 -17
  83. package/lib/collection.d.ts +10 -8
  84. package/lib/collection.js +19 -25
  85. package/lib/commands/applications/chat.d.ts +20 -18
  86. package/lib/commands/applications/chat.js +39 -14
  87. package/lib/commands/applications/chatcontext.d.ts +23 -15
  88. package/lib/commands/applications/chatcontext.js +23 -2
  89. package/lib/commands/applications/entryPoint.d.ts +4 -3
  90. package/lib/commands/applications/entryPoint.js +1 -1
  91. package/lib/commands/applications/entrycontext.d.ts +7 -9
  92. package/lib/commands/applications/entrycontext.js +3 -1
  93. package/lib/commands/applications/menu.d.ts +4 -3
  94. package/lib/commands/applications/menucontext.d.ts +7 -9
  95. package/lib/commands/applications/menucontext.js +3 -1
  96. package/lib/commands/applications/options.d.ts +23 -23
  97. package/lib/commands/applications/shared.d.ts +39 -17
  98. package/lib/commands/decorators.d.ts +50 -38
  99. package/lib/commands/decorators.js +15 -5
  100. package/lib/commands/handle.d.ts +19 -8
  101. package/lib/commands/handle.js +224 -143
  102. package/lib/commands/handler.d.ts +21 -8
  103. package/lib/commands/handler.js +157 -69
  104. package/lib/commands/index.d.ts +1 -0
  105. package/lib/commands/optionresolver.d.ts +2 -2
  106. package/lib/common/it/colors.js +12 -2
  107. package/lib/common/it/error.d.ts +9 -0
  108. package/lib/common/it/error.js +8 -0
  109. package/lib/common/it/fake-promise.d.ts +4 -0
  110. package/lib/common/it/fake-promise.js +10 -0
  111. package/lib/common/it/formatter.d.ts +14 -11
  112. package/lib/common/it/formatter.js +4 -3
  113. package/lib/common/it/logger.d.ts +7 -1
  114. package/lib/common/it/logger.js +24 -6
  115. package/lib/common/it/utils.d.ts +6 -8
  116. package/lib/common/it/utils.js +44 -42
  117. package/lib/common/shorters/application.d.ts +3 -3
  118. package/lib/common/shorters/application.js +3 -2
  119. package/lib/common/shorters/bans.d.ts +8 -4
  120. package/lib/common/shorters/bans.js +13 -5
  121. package/lib/common/shorters/channels.d.ts +4 -4
  122. package/lib/common/shorters/channels.js +4 -4
  123. package/lib/common/shorters/emojis.js +1 -0
  124. package/lib/common/shorters/guilds.d.ts +8 -8
  125. package/lib/common/shorters/guilds.js +14 -31
  126. package/lib/common/shorters/interaction.d.ts +1 -1
  127. package/lib/common/shorters/invites.d.ts +201 -201
  128. package/lib/common/shorters/members.d.ts +7 -7
  129. package/lib/common/shorters/members.js +13 -14
  130. package/lib/common/shorters/messages.d.ts +2 -2
  131. package/lib/common/shorters/soundboard.d.ts +5 -5
  132. package/lib/common/shorters/users.d.ts +1 -1
  133. package/lib/common/shorters/webhook.d.ts +3 -2
  134. package/lib/common/shorters/webhook.js +0 -7
  135. package/lib/common/types/options.d.ts +4 -0
  136. package/lib/common/types/util.d.ts +8 -0
  137. package/lib/common/types/write.d.ts +2 -1
  138. package/lib/components/BaseSelectMenuComponent.d.ts +1 -1
  139. package/lib/components/BaseSelectMenuComponent.js +1 -1
  140. package/lib/components/ButtonComponent.d.ts +3 -3
  141. package/lib/components/ChannelSelectMenuComponent.d.ts +2 -2
  142. package/lib/components/File.d.ts +1 -1
  143. package/lib/components/MediaGallery.d.ts +1 -1
  144. package/lib/components/MentionableSelectMenuComponent.d.ts +1 -1
  145. package/lib/components/RoleSelectMenuComponent.d.ts +1 -1
  146. package/lib/components/Separator.d.ts +1 -1
  147. package/lib/components/StringSelectMenuComponent.d.ts +1 -1
  148. package/lib/components/TextInputComponent.d.ts +1 -1
  149. package/lib/components/Thumbnail.d.ts +1 -1
  150. package/lib/components/UserSelectMenuComponent.d.ts +1 -1
  151. package/lib/components/componentcommand.d.ts +8 -7
  152. package/lib/components/componentcontext.d.ts +24 -36
  153. package/lib/components/componentcontext.js +7 -17
  154. package/lib/components/handler.d.ts +17 -7
  155. package/lib/components/handler.js +108 -49
  156. package/lib/components/index.d.ts +1 -0
  157. package/lib/components/index.js +1 -0
  158. package/lib/components/interactioncontext.d.ts +45 -0
  159. package/lib/components/interactioncontext.js +93 -0
  160. package/lib/components/modalcommand.d.ts +5 -4
  161. package/lib/components/modalcontext.d.ts +39 -20
  162. package/lib/components/modalcontext.js +59 -6
  163. package/lib/events/event.d.ts +9 -3
  164. package/lib/events/handler.d.ts +51 -6
  165. package/lib/events/handler.js +165 -36
  166. package/lib/events/hooks/application_command.d.ts +1 -1
  167. package/lib/events/hooks/auto_moderation.d.ts +2 -2
  168. package/lib/events/hooks/guild.d.ts +150 -150
  169. package/lib/events/hooks/interactions.d.ts +1 -1
  170. package/lib/events/hooks/invite.d.ts +20 -20
  171. package/lib/events/hooks/message.d.ts +27 -27
  172. package/lib/events/hooks/presence.d.ts +11 -11
  173. package/lib/events/hooks/soundboard.d.ts +6 -6
  174. package/lib/events/hooks/stage.d.ts +2 -2
  175. package/lib/events/hooks/subscriptions.d.ts +3 -3
  176. package/lib/events/hooks/thread.d.ts +30 -30
  177. package/lib/events/hooks/voice.d.ts +3 -4
  178. package/lib/events/hooks/voice.js +2 -1
  179. package/lib/events/utils.d.ts +4 -0
  180. package/lib/events/utils.js +59 -0
  181. package/lib/index.d.ts +9 -4
  182. package/lib/index.js +13 -8
  183. package/lib/langs/handler.d.ts +14 -11
  184. package/lib/langs/handler.js +46 -9
  185. package/lib/langs/router.d.ts +10 -3
  186. package/lib/structures/Application.d.ts +1 -1
  187. package/lib/structures/Emoji.d.ts +3 -3
  188. package/lib/structures/Emoji.js +2 -2
  189. package/lib/structures/Guild.d.ts +154 -154
  190. package/lib/structures/GuildBan.d.ts +4 -4
  191. package/lib/structures/GuildBan.js +3 -3
  192. package/lib/structures/GuildMember.d.ts +7 -7
  193. package/lib/structures/GuildMember.js +28 -7
  194. package/lib/structures/GuildRole.d.ts +1 -1
  195. package/lib/structures/GuildRole.js +2 -2
  196. package/lib/structures/Interaction.d.ts +11 -9
  197. package/lib/structures/Interaction.js +33 -12
  198. package/lib/structures/Message.d.ts +21 -14
  199. package/lib/structures/Message.js +29 -14
  200. package/lib/structures/User.d.ts +1 -1
  201. package/lib/structures/VoiceState.d.ts +4 -0
  202. package/lib/structures/VoiceState.js +13 -1
  203. package/lib/structures/Webhook.d.ts +9 -1
  204. package/lib/structures/Webhook.js +4 -1
  205. package/lib/structures/channels.d.ts +148 -134
  206. package/lib/structures/channels.js +27 -26
  207. package/lib/structures/extra/BitField.d.ts +4 -4
  208. package/lib/structures/extra/BitField.js +20 -4
  209. package/lib/structures/extra/DiscordBase.js +1 -1
  210. package/lib/structures/extra/Permissions.d.ts +2 -4
  211. package/lib/structures/extra/Permissions.js +1 -17
  212. package/lib/types/payloads/_interactions/responses.d.ts +2 -2
  213. package/lib/types/payloads/components.d.ts +4 -4
  214. package/lib/websocket/SharedTypes.d.ts +4 -4
  215. package/lib/websocket/constants/index.d.ts +1 -1
  216. package/lib/websocket/constants/index.js +3 -2
  217. package/lib/websocket/discord/events/memberUpdate.js +2 -2
  218. package/lib/websocket/discord/heartbeater.d.ts +1 -0
  219. package/lib/websocket/discord/heartbeater.js +7 -0
  220. package/lib/websocket/discord/shard.d.ts +2 -2
  221. package/lib/websocket/discord/shard.js +15 -13
  222. package/lib/websocket/discord/sharder.d.ts +8 -7
  223. package/lib/websocket/discord/sharder.js +25 -5
  224. package/lib/websocket/discord/shared.d.ts +19 -6
  225. package/lib/websocket/discord/socket/custom.js +5 -0
  226. package/lib/websocket/discord/worker.d.ts +1 -0
  227. package/lib/websocket/discord/worker.js +2 -0
  228. package/lib/websocket/discord/workermanager.d.ts +25 -11
  229. package/lib/websocket/discord/workermanager.js +41 -10
  230. package/package.json +12 -16
@@ -6,6 +6,7 @@ const node_path_1 = require("node:path");
6
6
  const api_1 = require("../api");
7
7
  const utils_1 = require("../api/utils/utils");
8
8
  const cache_1 = require("../cache");
9
+ const commands_1 = require("../commands");
9
10
  const shared_1 = require("../commands/applications/shared");
10
11
  const handle_1 = require("../commands/handle");
11
12
  const handler_1 = require("../commands/handler");
@@ -14,8 +15,29 @@ const utils_2 = require("../common/it/utils");
14
15
  const bans_1 = require("../common/shorters/bans");
15
16
  const soundboard_1 = require("../common/shorters/soundboard");
16
17
  const voiceStates_1 = require("../common/shorters/voiceStates");
18
+ const components_1 = require("../components");
17
19
  const handler_2 = require("../components/handler");
20
+ const events_1 = require("../events");
18
21
  const handler_3 = require("../langs/handler");
22
+ const types_1 = require("../types");
23
+ const intents_1 = require("./intents");
24
+ const plugins_1 = require("./plugins");
25
+ const errors_1 = require("./plugins/errors");
26
+ const order_1 = require("./plugins/order");
27
+ const registry_1 = require("./plugins/registry");
28
+ const shared_2 = require("./plugins/shared");
29
+ const pluginSourceKey = '__seyfertPluginSource';
30
+ function componentIdentity(kind, customId) {
31
+ return `${kind}:${customId}`;
32
+ }
33
+ function capitalizePluginKind(kind) {
34
+ return kind[0].toUpperCase() + kind.slice(1);
35
+ }
36
+ function commandIdentity(command) {
37
+ const guildId = 'guildId' in command ? command.guildId : undefined;
38
+ const guildScope = Array.isArray(guildId) ? [...guildId].sort().join(',') : (guildId ?? '*');
39
+ return `${command.type}:${command.name}:${guildScope}`;
40
+ }
19
41
  class BaseClient {
20
42
  rest = new api_1.ApiHandler({ token: 'INVALID' });
21
43
  cache = new cache_1.Cache(0, new cache_1.MemoryAdapter(), {}, this);
@@ -50,11 +72,24 @@ class BaseClient {
50
72
  static getBotIdFromToken(token) {
51
73
  return Buffer.from(token.split('.')[0], 'base64').toString('ascii');
52
74
  }
75
+ plugins = [];
76
+ shared;
77
+ events = new events_1.CustomEventHandler(this);
78
+ /** @internal */
79
+ pluginRegistry;
80
+ pluginsSetupPromise;
81
+ pluginsClosePromise;
82
+ langBaseValues = {};
83
+ pluginCacheDisabledCache = {};
84
+ pluginBaseGatewayIntents = this.cache.intents;
85
+ pluginComponentsBeforeLoadDepth = 0;
53
86
  options;
54
87
  /**@internal */
55
88
  static _seyfertCfWorkerConfig;
89
+ /**@internal */
90
+ _rcCache;
56
91
  constructor(options) {
57
- this.options = (0, common_1.MergeOptions)({
92
+ const defaults = {
58
93
  commands: {
59
94
  defaults: {
60
95
  onRunError(context, error) {
@@ -85,8 +120,8 @@ class BaseClient {
85
120
  onMiddlewaresError(context, error) {
86
121
  context.client.logger.fatal('ComponentCommand.<onMiddlewaresError>', context.author.id, error);
87
122
  },
88
- onInternalError(client, error) {
89
- client.logger.fatal(error);
123
+ onInternalError(client, component, error) {
124
+ client.logger.fatal(`[${component.customId ?? 'ComponentCommand'}].<onInternalError>`, error);
90
125
  },
91
126
  },
92
127
  },
@@ -98,12 +133,33 @@ class BaseClient {
98
133
  onMiddlewaresError(context, error) {
99
134
  context.client.logger.fatal('ModalCommand.<onMiddlewaresError>', context.author.id, error);
100
135
  },
101
- onInternalError(client, error) {
102
- client.logger.fatal(error);
136
+ onInternalError(client, modal, error) {
137
+ client.logger.fatal(`[${modal.customId ?? 'ModalCommand'}].<onInternalError>`, error);
103
138
  },
104
139
  },
105
140
  },
106
- }, options);
141
+ };
142
+ const resolved = (0, plugins_1.resolveClientPlugins)(defaults, options);
143
+ this.options = resolved.options;
144
+ this.configureLogger({ name: '[Seyfert]' }, this.options.logger);
145
+ this.plugins = resolved.plugins;
146
+ this.pluginRegistry = resolved.registry;
147
+ this.shared = (0, shared_2.createSharedRegistry)(this, this.pluginRegistry);
148
+ this.bindPluginLangReload();
149
+ (0, plugins_1.bindClientPlugins)(this, this.pluginRegistry);
150
+ this.bindPluginRestObserverProvider();
151
+ this.refreshPluginCacheResources();
152
+ }
153
+ configureLogger(defaults, options) {
154
+ const loggerOptions = (0, common_1.MergeOptions)(defaults, options ?? {});
155
+ if (loggerOptions.active !== undefined)
156
+ this.logger.active = loggerOptions.active;
157
+ if (loggerOptions.logLevel !== undefined)
158
+ this.logger.level = loggerOptions.logLevel;
159
+ if (loggerOptions.name !== undefined)
160
+ this.logger.name = loggerOptions.name;
161
+ if (loggerOptions.saveOnFile !== undefined)
162
+ this.logger.saveOnFile = loggerOptions.saveOnFile;
107
163
  }
108
164
  get proxy() {
109
165
  return this.rest.proxy;
@@ -126,6 +182,7 @@ class BaseClient {
126
182
  rest.onSuccessRequest ??= this.rest.onSuccessRequest?.bind(rest);
127
183
  rest.onFailRequest ??= this.rest.onFailRequest?.bind(rest);
128
184
  this.rest = rest;
185
+ this.bindPluginRestObserverProvider();
129
186
  }
130
187
  if (cache) {
131
188
  const caches = [
@@ -160,16 +217,19 @@ class BaseClient {
160
217
  }
161
218
  if (cache.adapter)
162
219
  this.cache.adapter = cache.adapter;
163
- if (cache.disabledCache)
164
- this.cache.buildCache(disabledCache, this);
220
+ if (cache.disabledCache !== undefined)
221
+ this.refreshPluginCacheResources(disabledCache);
165
222
  }
166
223
  if (middlewares) {
167
- this.middlewares = middlewares;
224
+ this.middlewares = { ...(this.middlewares ?? {}), ...middlewares };
168
225
  }
169
226
  if (langs) {
170
227
  this.langs ??= new handler_3.LangsHandler(this.logger);
228
+ this.bindPluginLangReload();
171
229
  if (langs.default)
172
230
  this.langs.defaultLang = langs.default;
231
+ if (langs.preferGuildLocale !== undefined)
232
+ this.langs.preferGuildLocale = langs.preferGuildLocale;
173
233
  if (langs.aliases)
174
234
  this.langs.aliases = Object.entries(langs.aliases);
175
235
  }
@@ -185,20 +245,392 @@ class BaseClient {
185
245
  }
186
246
  }
187
247
  async start(options = {}) {
188
- await this.loadLangs(options.langsDir);
189
- await this.loadCommands(options.commandsDir);
190
- await this.loadComponents(options.componentsDir);
191
248
  const { token: tokenRC, debug } = await this.getRC();
192
249
  const token = options.token ?? tokenRC;
193
- (0, common_1.assertString)(token, 'token is not a string');
250
+ if (typeof token !== 'string' || token.length === 0) {
251
+ throw new common_1.SeyfertError('INVALID_TOKEN', { metadata: { detail: 'token is not a string' } });
252
+ }
194
253
  if (this.rest.options.token === 'INVALID')
195
254
  this.rest.options.token = token;
196
- this.rest.debug = debug;
255
+ this.rest.debug = !!debug;
197
256
  if (!this.handleCommand)
198
257
  this.handleCommand = new handle_1.HandleCommand(this);
258
+ await this.setupPlugins();
259
+ this.refreshPluginCacheResources();
260
+ this.reloadPluginMiddlewares();
261
+ await (0, plugins_1.runPluginHooks)(this, 'plugins:setupComplete', this);
262
+ await (0, plugins_1.runPluginHooks)(this, 'plugins:ready', this);
199
263
  // The reason of this method is so for adapters that need to connect somewhere, have time to connect.
200
264
  // Or maybe clear cache?
201
265
  await this.cache.adapter.start();
266
+ await this.loadLangs(options.langsDir);
267
+ await (0, plugins_1.runPluginHooks)(this, 'commands:beforeLoad', this, options.commandsDir);
268
+ await this.loadCommands(options.commandsDir);
269
+ await this.reloadPluginCommands();
270
+ await (0, plugins_1.runPluginHooks)(this, 'components:beforeLoad', this, options.componentsDir);
271
+ this.pluginComponentsBeforeLoadDepth++;
272
+ try {
273
+ await this.loadComponents(options.componentsDir);
274
+ }
275
+ finally {
276
+ this.pluginComponentsBeforeLoadDepth--;
277
+ }
278
+ await this.reloadPluginComponents();
279
+ }
280
+ async reloadPluginContributions() {
281
+ this.refreshPluginContributions();
282
+ const commandsMetadata = this.createPluginLoadedMetadata('commands', this.loadedCommands);
283
+ await (0, plugins_1.runPluginHooks)(this, 'commands:afterLoad', commandsMetadata);
284
+ await this.emitPluginCustomEvent('commandsLoaded', commandsMetadata);
285
+ const componentsMetadata = this.createPluginLoadedMetadata('components', this.components.commands);
286
+ await (0, plugins_1.runPluginHooks)(this, 'components:afterLoad', componentsMetadata);
287
+ await this.emitPluginCustomEvent('componentsLoaded', componentsMetadata);
288
+ }
289
+ /** @internal */
290
+ refreshPluginContributions() {
291
+ this.reloadPluginMiddlewares();
292
+ this.refreshPluginCacheResources();
293
+ this.applyPluginLangs();
294
+ this.applyPluginCommands();
295
+ this.applyPluginComponents();
296
+ }
297
+ bindPluginRestObserverProvider() {
298
+ this.rest.pluginRestObserverClient = this;
299
+ this.rest.pluginRestObserverProvider = () => (0, order_1.orderedPluginContributions)(this.pluginRegistry.restObservers)
300
+ .filter(contribution => contribution.active)
301
+ .map(contribution => ({
302
+ plugin: contribution.record.identity,
303
+ observer: contribution.observer,
304
+ }));
305
+ }
306
+ bindPluginLangReload() {
307
+ this.langs.onReload = (locale, value) => {
308
+ this.langBaseValues[locale] = cloneRecursive(value);
309
+ this.applyPluginLangs();
310
+ };
311
+ }
312
+ refreshPluginCacheResources(disabledCache = this.pluginCacheDisabledCache) {
313
+ this.pluginCacheDisabledCache = disabledCache;
314
+ this.cache.intents = (0, plugins_1.resolveClientPluginIntents)(this, this.pluginBaseGatewayIntents);
315
+ this.cache.buildCache(disabledCache, this);
316
+ }
317
+ resolvePluginGatewayIntents(base) {
318
+ this.pluginBaseGatewayIntents = (0, intents_1.resolveGatewayIntents)(base);
319
+ this.cache.intents = (0, plugins_1.resolveClientPluginIntents)(this, this.pluginBaseGatewayIntents);
320
+ return this.cache.intents;
321
+ }
322
+ reloadPluginMiddlewares() {
323
+ (0, registry_1.installPluginMiddlewares)(this, this.pluginRegistry);
324
+ (0, plugins_1.refreshClientPluginOptions)(this, this.pluginRegistry);
325
+ }
326
+ async reloadPluginCommands() {
327
+ this.applyPluginCommands();
328
+ const metadata = this.createPluginLoadedMetadata('commands', this.loadedCommands);
329
+ await (0, plugins_1.runPluginHooks)(this, 'commands:afterLoad', metadata);
330
+ await this.emitPluginCustomEvent('commandsLoaded', metadata);
331
+ }
332
+ async reloadPluginComponents() {
333
+ this.applyPluginComponents();
334
+ const metadata = this.createPluginLoadedMetadata('components', this.components.commands);
335
+ await (0, plugins_1.runPluginHooks)(this, 'components:afterLoad', metadata);
336
+ await this.emitPluginCustomEvent('componentsLoaded', metadata);
337
+ }
338
+ async setupPlugins() {
339
+ if (this.pluginsClosePromise)
340
+ await this.pluginsClosePromise;
341
+ this.pluginsSetupPromise ??= (0, plugins_1.setupClientPlugins)(this, this.plugins);
342
+ try {
343
+ await this.pluginsSetupPromise;
344
+ }
345
+ catch (error) {
346
+ this.pluginsSetupPromise = undefined;
347
+ throw error;
348
+ }
349
+ }
350
+ /**
351
+ * Closes resources managed by the plugin lifecycle.
352
+ *
353
+ * This waits for in-flight plugin setup and runs `SeyfertPlugin.teardown`.
354
+ * It does not close the gateway, REST client, or cache adapter.
355
+ */
356
+ async close() {
357
+ const setup = this.pluginsSetupPromise;
358
+ if (!setup)
359
+ return;
360
+ const close = this.pluginsClosePromise ??
361
+ (async () => {
362
+ await setup;
363
+ await (0, plugins_1.runPluginHooks)(this, 'client:close', this);
364
+ await (0, plugins_1.teardownClientPlugins)(this, this.plugins);
365
+ })();
366
+ this.pluginsClosePromise = close;
367
+ try {
368
+ await close;
369
+ }
370
+ finally {
371
+ if (this.pluginsClosePromise === close) {
372
+ this.pluginsSetupPromise = undefined;
373
+ this.pluginsClosePromise = undefined;
374
+ }
375
+ }
376
+ }
377
+ applyPluginCommands() {
378
+ const contributions = this.pluginRegistry.commands;
379
+ const removals = this.pluginRegistry.commandRemovals;
380
+ const hasPluginCommands = this.commands.values.some(command => pluginSourceKey in command) ||
381
+ !!(this.commands.entryPoint && pluginSourceKey in this.commands.entryPoint);
382
+ if (!(contributions.length || removals.length || hasPluginCommands))
383
+ return;
384
+ this.commands.values = this.commands.values.filter(command => !(pluginSourceKey in command));
385
+ if (this.commands.entryPoint && pluginSourceKey in this.commands.entryPoint)
386
+ this.commands.entryPoint = null;
387
+ const existingCommands = new Map();
388
+ for (const command of this.commands.values)
389
+ existingCommands.set(commandIdentity(command), { command });
390
+ if (this.commands.entryPoint)
391
+ existingCommands.set(commandIdentity(this.commands.entryPoint), { command: this.commands.entryPoint });
392
+ const mutations = (0, order_1.orderedPluginContributions)([
393
+ ...contributions.map(contribution => ({ ...contribution, kind: 'add' })),
394
+ ...removals.map(contribution => ({ ...contribution, kind: 'remove' })),
395
+ ]);
396
+ for (const mutation of mutations) {
397
+ if (mutation.kind === 'remove') {
398
+ for (const name of mutation.names) {
399
+ const matches = [...existingCommands].filter(([, entry]) => entry.command.name === name);
400
+ if (!matches.length)
401
+ continue;
402
+ for (const [key, existing] of matches) {
403
+ (0, registry_1.assertCanMutatePluginContribution)(this.pluginRegistry, mutation.record, 'remove', 'command', name, existing.owner, 'commands.remove');
404
+ existingCommands.delete(key);
405
+ (0, registry_1.recordContributionMutationDiagnostic)(this.pluginRegistry, mutation, 'remove', 'command', name, existing.owner, 'commands.remove');
406
+ }
407
+ }
408
+ continue;
409
+ }
410
+ for (const command of mutation.commands) {
411
+ const instance = this.createPluginCommandInstance(command, mutation.record, 'commands.add');
412
+ if (instance instanceof commands_1.SubCommand) {
413
+ throw (0, errors_1.createPluginConflictError)(mutation.record.plugin.name, 'commands.add', mutation.record.index, `SubCommand "${instance.name}" cannot be registered as a top-level plugin command.`, mutation.record.plugin.instanceId);
414
+ }
415
+ if (!instance.name) {
416
+ throw (0, errors_1.createPluginConflictError)(mutation.record.plugin.name, 'commands.add', mutation.record.index, 'Plugin command is missing a name.', mutation.record.plugin.instanceId);
417
+ }
418
+ if (mutation.guilds?.length) {
419
+ if ('guildId' in instance) {
420
+ instance.guildId = [...mutation.guilds];
421
+ }
422
+ else {
423
+ (0, registry_1.addPluginDiagnostic)(this.pluginRegistry, mutation.record, {
424
+ phase: 'commands.add',
425
+ severity: 'warn',
426
+ code: 'command-guild-scope',
427
+ message: `Command "${instance.name}" does not support guild-scoped registration.`,
428
+ data: { command: instance.name, guilds: [...mutation.guilds] },
429
+ });
430
+ }
431
+ }
432
+ const identity = commandIdentity(instance);
433
+ const existing = existingCommands.get(identity);
434
+ if (existing && !mutation.override) {
435
+ throw (0, errors_1.createPluginConflictError)(mutation.record.plugin.name, 'commands.add', mutation.record.index, `Command "${instance.name}" is already registered.`, mutation.record.plugin.instanceId);
436
+ }
437
+ if (existing) {
438
+ (0, registry_1.assertCanMutatePluginContribution)(this.pluginRegistry, mutation.record, 'override', 'command', instance.name, existing.owner, 'commands.add');
439
+ (0, registry_1.recordContributionMutationDiagnostic)(this.pluginRegistry, mutation, 'override', 'command', instance.name, existing.owner, 'commands.add');
440
+ }
441
+ instance[pluginSourceKey] = mutation.record.identity;
442
+ existingCommands.set(identity, { command: instance, owner: mutation.record });
443
+ }
444
+ }
445
+ const commands = [...existingCommands.values()]
446
+ .filter(entry => !!entry.owner)
447
+ .map(entry => entry.command);
448
+ this.commands.set(commands, command => {
449
+ const source = command[pluginSourceKey];
450
+ const transformed = this.runPluginHandlerTransformers('command', command);
451
+ if (source)
452
+ transformed[pluginSourceKey] = source;
453
+ return transformed;
454
+ });
455
+ }
456
+ get loadedCommands() {
457
+ return this.commands.entryPoint ? [...this.commands.values, this.commands.entryPoint] : this.commands.values;
458
+ }
459
+ applyPluginComponents() {
460
+ const contributions = this.pluginRegistry.components;
461
+ const modalContributions = this.pluginRegistry.modals;
462
+ const removals = this.pluginRegistry.componentRemovals;
463
+ const modalRemovals = this.pluginRegistry.modalRemovals;
464
+ const hasPluginComponents = this.components.commands.some(command => pluginSourceKey in command);
465
+ if (!(contributions.length ||
466
+ modalContributions.length ||
467
+ removals.length ||
468
+ modalRemovals.length ||
469
+ hasPluginComponents)) {
470
+ return;
471
+ }
472
+ const existing = this.components.commands.filter(command => !(pluginSourceKey in command));
473
+ this.components.commands.splice(0, this.components.commands.length, ...existing);
474
+ const componentsByCustomId = new Map();
475
+ for (const component of this.components.commands) {
476
+ if (typeof component.customId === 'string') {
477
+ componentsByCustomId.set(componentIdentity(component instanceof components_1.ModalCommand ? 'modal' : 'component', component.customId), {
478
+ component,
479
+ });
480
+ }
481
+ }
482
+ const dynamicComponents = [];
483
+ const mutations = (0, order_1.orderedPluginContributions)([
484
+ ...contributions.map(contribution => ({
485
+ ...contribution,
486
+ kind: 'add',
487
+ contributionKind: 'component',
488
+ })),
489
+ ...modalContributions.map(contribution => ({
490
+ ...contribution,
491
+ kind: 'add',
492
+ contributionKind: 'modal',
493
+ })),
494
+ ...removals.map(contribution => ({
495
+ ...contribution,
496
+ kind: 'remove',
497
+ contributionKind: 'component',
498
+ })),
499
+ ...modalRemovals.map(contribution => ({
500
+ ...contribution,
501
+ kind: 'remove',
502
+ contributionKind: 'modal',
503
+ })),
504
+ ]);
505
+ for (const mutation of mutations) {
506
+ if (mutation.kind === 'remove') {
507
+ for (const customId of mutation.customIds) {
508
+ const key = componentIdentity(mutation.contributionKind, customId);
509
+ const existing = componentsByCustomId.get(key);
510
+ if (!existing)
511
+ continue;
512
+ (0, registry_1.assertCanMutatePluginContribution)(this.pluginRegistry, mutation.record, 'remove', mutation.contributionKind, customId, existing.owner, `${mutation.contributionKind}s.remove`);
513
+ componentsByCustomId.delete(key);
514
+ (0, registry_1.recordContributionMutationDiagnostic)(this.pluginRegistry, mutation, 'remove', mutation.contributionKind, customId, existing.owner, `${mutation.contributionKind}s.remove`);
515
+ }
516
+ continue;
517
+ }
518
+ const constructors = mutation.contributionKind === 'component'
519
+ ? mutation.components
520
+ : mutation.modals;
521
+ for (const constructor of constructors) {
522
+ const instance = this.createPluginComponentInstance(constructor, mutation.record, `${mutation.contributionKind}s.add`, mutation.contributionKind);
523
+ instance[pluginSourceKey] = mutation.record.identity;
524
+ if (typeof instance.customId !== 'string') {
525
+ dynamicComponents.push({ component: instance, owner: mutation.record });
526
+ continue;
527
+ }
528
+ const key = componentIdentity(mutation.contributionKind, instance.customId);
529
+ const existing = componentsByCustomId.get(key);
530
+ if (existing && !mutation.override) {
531
+ throw (0, errors_1.createPluginConflictError)(mutation.record.plugin.name, `${mutation.contributionKind}s.add`, mutation.record.index, `${capitalizePluginKind(mutation.contributionKind)} "${instance.customId}" is already registered.`, mutation.record.plugin.instanceId);
532
+ }
533
+ if (existing) {
534
+ (0, registry_1.assertCanMutatePluginContribution)(this.pluginRegistry, mutation.record, 'override', mutation.contributionKind, instance.customId, existing.owner, `${mutation.contributionKind}s.add`);
535
+ (0, registry_1.recordContributionMutationDiagnostic)(this.pluginRegistry, mutation, 'override', mutation.contributionKind, instance.customId, existing.owner, `${mutation.contributionKind}s.add`);
536
+ }
537
+ componentsByCustomId.set(key, { component: instance, owner: mutation.record });
538
+ }
539
+ }
540
+ const components = [...componentsByCustomId.values(), ...dynamicComponents]
541
+ .filter((entry) => !!entry.owner)
542
+ .map(entry => entry.component);
543
+ this.components.set(components, component => {
544
+ const source = component[pluginSourceKey];
545
+ const transformed = this.runPluginHandlerTransformers(component instanceof components_1.ModalCommand ? 'modal' : 'component', component);
546
+ if (source)
547
+ transformed[pluginSourceKey] = source;
548
+ return transformed;
549
+ });
550
+ }
551
+ createPluginCommandInstance(command, record, phase) {
552
+ if (typeof command !== 'function')
553
+ return command;
554
+ return this.runPluginHandlerCreators('command', command, () => {
555
+ try {
556
+ return new command();
557
+ }
558
+ catch (error) {
559
+ throw (0, errors_1.wrapPluginError)(record.plugin.name, phase, record.index, error, undefined, record.plugin.instanceId);
560
+ }
561
+ });
562
+ }
563
+ createPluginComponentInstance(constructor, record, phase, kind) {
564
+ const instance = typeof constructor !== 'function'
565
+ ? constructor
566
+ : this.runPluginHandlerCreators(kind, constructor, () => {
567
+ try {
568
+ return new constructor();
569
+ }
570
+ catch (error) {
571
+ throw (0, errors_1.wrapPluginError)(record.plugin.name, phase, record.index, error, undefined, record.plugin.instanceId);
572
+ }
573
+ });
574
+ if (kind === 'modal' && !(instance instanceof components_1.ModalCommand)) {
575
+ throw (0, errors_1.createPluginConflictError)(record.plugin.name, phase, record.index, 'Plugin modal contribution must be a ModalCommand.', record.plugin.instanceId);
576
+ }
577
+ if (kind === 'component' && !(instance instanceof components_1.ComponentCommand)) {
578
+ throw (0, errors_1.createPluginConflictError)(record.plugin.name, phase, record.index, 'Plugin component contribution must be a ComponentCommand.', record.plugin.instanceId);
579
+ }
580
+ return instance;
581
+ }
582
+ runPluginHandlerCreators(kind, constructor, create) {
583
+ const creators = (0, order_1.orderedPluginContributions)(this.pluginRegistry.handlerCreators).filter(contribution => this.matchesPluginHandlerKind(contribution.kinds, kind));
584
+ const metadata = { kind };
585
+ return creators.reduceRight((next, contribution) => () => {
586
+ try {
587
+ return contribution.creator(constructor, next, metadata);
588
+ }
589
+ catch (error) {
590
+ throw (0, errors_1.wrapPluginError)(contribution.record.plugin.name, `handlers.construct:${kind}`, contribution.record.index, error, undefined, contribution.record.plugin.instanceId);
591
+ }
592
+ }, create)();
593
+ }
594
+ /** @internal */
595
+ runPluginHandlerTransformers(kind, instance) {
596
+ let current = instance;
597
+ const metadata = { kind };
598
+ for (const contribution of (0, order_1.orderedPluginContributions)(this.pluginRegistry.handlerTransformers)) {
599
+ if (!this.matchesPluginHandlerKind(contribution.kinds, kind))
600
+ continue;
601
+ try {
602
+ const transform = contribution.transformer;
603
+ current = (transform(current, metadata) ?? current);
604
+ }
605
+ catch (error) {
606
+ throw (0, errors_1.wrapPluginError)(contribution.record.plugin.name, `handlers.transform:${kind}`, contribution.record.index, error, undefined, contribution.record.plugin.instanceId);
607
+ }
608
+ }
609
+ return current;
610
+ }
611
+ matchesPluginHandlerKind(kinds, kind) {
612
+ return !kinds?.length || kinds.includes(kind);
613
+ }
614
+ createPluginLoadedMetadata(kind, items) {
615
+ const sources = Object.create(null);
616
+ for (const item of items) {
617
+ const source = item[pluginSourceKey];
618
+ if (source)
619
+ sources[source] = (sources[source] ?? 0) + 1;
620
+ }
621
+ const sourceSnapshot = Object.freeze(sources);
622
+ return Object.freeze({
623
+ kind,
624
+ total: items.length,
625
+ items: Object.freeze([...items]),
626
+ plugin: Object.freeze({
627
+ total: Object.values(sources).reduce((sum, value) => sum + value, 0),
628
+ sources: sourceSnapshot,
629
+ }),
630
+ });
631
+ }
632
+ async emitPluginCustomEvent(name, ...args) {
633
+ await this.events?.runCustom(name, ...args);
202
634
  }
203
635
  async onPacket(..._packet) {
204
636
  throw new common_1.SeyfertError('FUNCTION_NOT_IMPLEMENTED', { metadata: { detail: 'Function not implemented' } });
@@ -209,8 +641,15 @@ class BaseClient {
209
641
  * @returns
210
642
  */
211
643
  async onInteractionRequest(rawBody) {
212
- return new Promise(async (r) => {
213
- await this.handleCommand.interaction(rawBody, -1, async ({ body, files }) => {
644
+ if (rawBody.type === types_1.InteractionType.Ping) {
645
+ return {
646
+ headers: { 'Content-Type': 'application/json' },
647
+ response: { type: types_1.InteractionResponseType.Pong },
648
+ };
649
+ }
650
+ return new Promise((resolve, reject) => {
651
+ this.handleCommand
652
+ .interaction(rawBody, -1, async ({ body, files }) => {
214
653
  let response;
215
654
  const headers = {};
216
655
  if (files) {
@@ -241,11 +680,12 @@ class BaseClient {
241
680
  response = body ?? {};
242
681
  headers['Content-Type'] = 'application/json';
243
682
  }
244
- return r({
683
+ resolve({
245
684
  headers,
246
685
  response,
247
686
  });
248
- });
687
+ })
688
+ .catch(reject);
249
689
  });
250
690
  }
251
691
  async shouldUploadCommands(cachePath, guildId) {
@@ -260,6 +700,29 @@ class BaseClient {
260
700
  .filter(cmd => !('ignore' in cmd) || cmd.ignore !== shared_1.IgnoreCommand.Slash)
261
701
  .map(x => x.toJSON())));
262
702
  }
703
+ async cachedCommandGuilds(cachePath) {
704
+ const guilds = new Set();
705
+ const cached = await node_fs_1.promises.readFile(cachePath, 'utf8').catch(() => undefined);
706
+ if (!cached)
707
+ return guilds;
708
+ try {
709
+ const commands = JSON.parse(cached);
710
+ for (const command of commands) {
711
+ const guildId = command.guild_id;
712
+ if (Array.isArray(guildId)) {
713
+ for (const id of guildId)
714
+ guilds.add(id);
715
+ }
716
+ else if (typeof guildId === 'string') {
717
+ guilds.add(guildId);
718
+ }
719
+ }
720
+ }
721
+ catch {
722
+ return guilds;
723
+ }
724
+ return guilds;
725
+ }
263
726
  async uploadCommands({ applicationId, cachePath } = {}) {
264
727
  applicationId ??= await this.getRC().then(x => x.applicationId ?? this.applicationId);
265
728
  (0, common_1.assertString)(applicationId, 'applicationId is not a string');
@@ -268,68 +731,129 @@ class BaseClient {
268
731
  if (this.commands.entryPoint) {
269
732
  filter.expect.push(this.commands.entryPoint);
270
733
  }
271
- if (!cachePath || (await this.shouldUploadCommands(cachePath)))
734
+ const globalCommands = filter.expect
735
+ .filter(cmd => !('ignore' in cmd) || cmd.ignore !== shared_1.IgnoreCommand.Slash)
736
+ .map(x => x.toJSON());
737
+ const shouldUploadGlobal = !cachePath || (await this.shouldUploadCommands(cachePath));
738
+ if (shouldUploadGlobal) {
272
739
  await this.proxy.applications(applicationId).commands.put({
273
- body: filter.expect
274
- .filter(cmd => !('ignore' in cmd) || cmd.ignore !== shared_1.IgnoreCommand.Slash)
275
- .map(x => x.toJSON()),
740
+ body: globalCommands,
276
741
  });
742
+ }
743
+ await this.emitUploadCommandsMetadata({
744
+ applicationId,
745
+ cachePath,
746
+ commands: globalCommands.length,
747
+ reason: cachePath ? (shouldUploadGlobal ? 'cache-miss' : 'cache-hit') : 'forced',
748
+ scope: 'global',
749
+ status: shouldUploadGlobal ? 'uploaded' : 'skipped',
750
+ });
277
751
  const guilds = new Set();
752
+ if (cachePath) {
753
+ for (const guildId of await this.cachedCommandGuilds(cachePath))
754
+ guilds.add(guildId);
755
+ }
278
756
  for (const command of filter.never) {
279
757
  for (const guild_id of command.guildId) {
280
758
  guilds.add(guild_id);
281
759
  }
282
760
  }
283
761
  for (const guildId of guilds) {
284
- if (!cachePath || (await this.shouldUploadCommands(cachePath, guildId))) {
285
- await this.proxy
286
- .applications(applicationId)
287
- .guilds(guildId)
288
- .commands.put({
289
- body: filter.never
290
- .filter(cmd => cmd.guildId.includes(guildId) && (!('ignore' in cmd) || cmd.ignore !== shared_1.IgnoreCommand.Slash))
291
- .map(x => x.toJSON()),
762
+ const guildCommands = filter.never
763
+ .filter(cmd => cmd.guildId.includes(guildId) && (!('ignore' in cmd) || cmd.ignore !== shared_1.IgnoreCommand.Slash))
764
+ .map(x => x.toJSON());
765
+ const shouldUploadGuild = !cachePath || (await this.shouldUploadCommands(cachePath, guildId));
766
+ if (shouldUploadGuild) {
767
+ await this.proxy.applications(applicationId).guilds(guildId).commands.put({
768
+ body: guildCommands,
292
769
  });
293
770
  }
771
+ await this.emitUploadCommandsMetadata({
772
+ applicationId,
773
+ cachePath,
774
+ commands: guildCommands.length,
775
+ guildId,
776
+ reason: cachePath ? (shouldUploadGuild ? 'cache-miss' : 'cache-hit') : 'forced',
777
+ scope: 'guild',
778
+ status: shouldUploadGuild ? 'uploaded' : 'skipped',
779
+ });
294
780
  }
295
781
  if (cachePath)
296
782
  await this.syncCachePath(cachePath);
297
783
  }
784
+ async emitUploadCommandsMetadata(metadata) {
785
+ await this.emitPluginCustomEvent('uploadCommands', metadata);
786
+ }
298
787
  async loadCommands(dir) {
299
788
  dir ??= await this.getRC().then(x => x.locations.commands);
300
789
  if (dir && this.commands) {
301
- await this.commands.load(dir, this);
790
+ await this.commands.load(dir, this, this.createPluginCommandLoadOptions());
302
791
  this.logger.info('CommandHandler loaded');
303
792
  }
304
793
  }
305
794
  async loadComponents(dir) {
306
795
  dir ??= await this.getRC().then(x => x.locations.components);
796
+ if (!this.pluginComponentsBeforeLoadDepth)
797
+ await (0, plugins_1.runPluginHooks)(this, 'components:beforeLoad', this, dir);
307
798
  if (dir && this.components) {
308
- await this.components.load(dir);
799
+ await this.components.load(dir, this.createPluginComponentLoadOptions());
309
800
  this.logger.info('ComponentHandler loaded');
310
801
  }
311
802
  }
803
+ /** @internal */
804
+ createPluginCommandLoadOptions() {
805
+ return {
806
+ create: (constructor, next) => this.runPluginHandlerCreators('command', constructor, next),
807
+ transform: command => this.runPluginHandlerTransformers('command', command),
808
+ };
809
+ }
810
+ /** @internal */
811
+ createPluginComponentLoadOptions() {
812
+ return {
813
+ create: (kind, constructor, next) => this.runPluginHandlerCreators(kind, constructor, next),
814
+ transform: (kind, component) => this.runPluginHandlerTransformers(kind, component),
815
+ };
816
+ }
312
817
  async loadLangs(dir) {
313
818
  dir ??= await this.getRC().then(x => x.locations.langs);
314
819
  if (dir && this.langs) {
315
820
  await this.langs.load(dir);
316
821
  this.logger.info('LangsHandler loaded');
317
822
  }
823
+ this.langBaseValues = this.langs ? cloneRecursive(this.langs.values) : this.langBaseValues;
824
+ this.applyPluginLangs();
825
+ }
826
+ applyPluginLangs() {
827
+ if (!this.langs)
828
+ return;
829
+ const localeContributions = (0, order_1.orderedPluginContributions)(this.pluginRegistry.langs);
830
+ const values = cloneRecursive(this.langBaseValues);
831
+ for (const contribution of localeContributions) {
832
+ const current = values[contribution.locale] ?? {};
833
+ values[contribution.locale] = (0, common_1.MergeOptions)(current, createNestedLangValues(contribution.prefix, cloneRecursive(contribution.values)));
834
+ }
835
+ this.langs.values = values;
318
836
  }
319
837
  t(locale) {
320
838
  return this.langs.get(locale);
321
839
  }
322
840
  async getRC() {
841
+ if (this._rcCache)
842
+ return this._rcCache;
323
843
  const seyfertConfig = (BaseClient._seyfertCfWorkerConfig ||
324
844
  (await this.options?.getRC?.()) ||
325
845
  (await Promise.any(['.js', '.mjs', '.cjs', '.ts', '.mts', '.cts'].map(ext => (0, common_1.magicImport)((0, node_path_1.join)(process.cwd(), `seyfert.config${ext}`)).then(x => x.default ?? x))).catch((e) => {
326
- const errors = e.errors.map((err) => {
327
- err.message = err.message.replace(/seyfert\.config\.(js|mjs|cjs|ts|mts|cts)/g, 'seyfert.config');
328
- return err;
329
- });
846
+ const errors = e.errors.map((err) => ({
847
+ error: err,
848
+ message: err.message.replace(/seyfert\.config\.(js|mjs|cjs|ts|mts|cts)/g, 'seyfert.config'),
849
+ }));
330
850
  const uniqueError = errors.find(er => errors.filter(err => err.message === er.message).length === 1);
331
- if (uniqueError)
332
- throw uniqueError;
851
+ if (uniqueError) {
852
+ throw new common_1.SeyfertError('SEYFERT_CONFIG_LOAD_ERROR', {
853
+ metadata: { detail: uniqueError.message },
854
+ cause: uniqueError.error,
855
+ });
856
+ }
333
857
  throw new common_1.SeyfertError('NO_SEYFERT_CONFIG', {
334
858
  metadata: { detail: 'No seyfert.config file found' },
335
859
  });
@@ -349,11 +873,42 @@ class BaseClient {
349
873
  locationsFullPaths[key] = location;
350
874
  }
351
875
  const obj = {
352
- debug: !!debug,
353
876
  ...env,
877
+ debug: !!debug,
878
+ intents: (0, intents_1.resolveGatewayIntents)('intents' in seyfertConfig ? (seyfertConfig.intents ?? 0) : 0),
354
879
  locations: locationsFullPaths,
355
880
  };
881
+ this._rcCache = obj;
356
882
  return obj;
357
883
  }
358
884
  }
359
885
  exports.BaseClient = BaseClient;
886
+ function createNestedLangValues(prefix, values) {
887
+ const route = prefix.split('.').filter(Boolean);
888
+ const clonedValues = cloneRecursive(values);
889
+ const root = {};
890
+ let current = root;
891
+ for (let i = 0; i < route.length; i++) {
892
+ const key = route[i];
893
+ if (i === route.length - 1) {
894
+ current[key] = clonedValues;
895
+ break;
896
+ }
897
+ const nested = {};
898
+ current[key] = nested;
899
+ current = nested;
900
+ }
901
+ return root;
902
+ }
903
+ function cloneRecursive(value) {
904
+ if (Array.isArray(value))
905
+ return value.map(item => cloneRecursive(item));
906
+ if (!value || typeof value !== 'object')
907
+ return value;
908
+ const entries = value;
909
+ const cloned = {};
910
+ for (const key of Object.keys(entries)) {
911
+ cloned[key] = cloneRecursive(entries[key]);
912
+ }
913
+ return cloned;
914
+ }