virello 0.0.0-stage → 0.1.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 (603) hide show
  1. package/BREAKING_CHANGES.md +69 -0
  2. package/LICENSE +21 -0
  3. package/README.md +161 -2
  4. package/docs/console-logging.md +257 -0
  5. package/docs/engine.md +144 -0
  6. package/docs/sharding-recovery.md +163 -0
  7. package/docs/sharding-scaling.md +197 -0
  8. package/docs/sharding-stats.md +121 -0
  9. package/examples/README.md +288 -0
  10. package/examples/bot.ts +42 -0
  11. package/examples/client.ts +36 -0
  12. package/examples/commands/ping.ts +25 -0
  13. package/examples/commands/shard.ts +67 -0
  14. package/examples/commands/stats.ts +46 -0
  15. package/examples/config.ts +110 -0
  16. package/examples/contracts.ts +15 -0
  17. package/examples/coordinator.ts +50 -0
  18. package/examples/engine/MockDiscord.ts +159 -0
  19. package/examples/engine/live.ts +78 -0
  20. package/examples/engine/offline.ts +83 -0
  21. package/examples/host.ts +48 -0
  22. package/examples/listeners/ready.ts +20 -0
  23. package/examples/logging.ts +50 -0
  24. package/examples/offline.ts +93 -0
  25. package/examples/registration.ts +11 -0
  26. package/examples/shutdown.ts +50 -0
  27. package/examples/stats.ts +44 -0
  28. package/examples/unregisterCommands.ts +21 -0
  29. package/package.json +110 -5
  30. package/src/commands/Command.ts +424 -0
  31. package/src/commands/CommandStore.ts +71 -0
  32. package/src/commands/arguments/Args.ts +688 -0
  33. package/src/commands/arguments/Argument.ts +116 -0
  34. package/src/commands/arguments/ArgumentStore.ts +10 -0
  35. package/src/commands/arguments/builtins/Boolean.ts +27 -0
  36. package/src/commands/arguments/builtins/Channel.ts +24 -0
  37. package/src/commands/arguments/builtins/DMChannel.ts +24 -0
  38. package/src/commands/arguments/builtins/Date.ts +36 -0
  39. package/src/commands/arguments/builtins/Emoji.ts +23 -0
  40. package/src/commands/arguments/builtins/Enum.ts +27 -0
  41. package/src/commands/arguments/builtins/Float.ts +36 -0
  42. package/src/commands/arguments/builtins/Guild.ts +24 -0
  43. package/src/commands/arguments/builtins/GuildCategoryChannel.ts +36 -0
  44. package/src/commands/arguments/builtins/GuildChannel.ts +35 -0
  45. package/src/commands/arguments/builtins/GuildNewsChannel.ts +36 -0
  46. package/src/commands/arguments/builtins/GuildNewsThreadChannel.ts +36 -0
  47. package/src/commands/arguments/builtins/GuildPrivateThreadChannel.ts +36 -0
  48. package/src/commands/arguments/builtins/GuildPublicThreadChannel.ts +35 -0
  49. package/src/commands/arguments/builtins/GuildStageVoiceChannel.ts +36 -0
  50. package/src/commands/arguments/builtins/GuildTextChannel.ts +35 -0
  51. package/src/commands/arguments/builtins/GuildThreadChannel.ts +35 -0
  52. package/src/commands/arguments/builtins/GuildVoiceChannel.ts +35 -0
  53. package/src/commands/arguments/builtins/Hyperlink.ts +24 -0
  54. package/src/commands/arguments/builtins/Integer.ts +36 -0
  55. package/src/commands/arguments/builtins/Member.ts +41 -0
  56. package/src/commands/arguments/builtins/Message.ts +31 -0
  57. package/src/commands/arguments/builtins/Number.ts +36 -0
  58. package/src/commands/arguments/builtins/PartialDMChannel.ts +26 -0
  59. package/src/commands/arguments/builtins/Role.ts +35 -0
  60. package/src/commands/arguments/builtins/String.ts +34 -0
  61. package/src/commands/arguments/builtins/User.ts +24 -0
  62. package/src/commands/arguments/contexts.ts +32 -0
  63. package/src/commands/arguments/register.ts +166 -0
  64. package/src/commands/arguments/resolvers/boolean.ts +33 -0
  65. package/src/commands/arguments/resolvers/channel.ts +33 -0
  66. package/src/commands/arguments/resolvers/date.ts +41 -0
  67. package/src/commands/arguments/resolvers/dmChannel.ts +30 -0
  68. package/src/commands/arguments/resolvers/emoji.ts +51 -0
  69. package/src/commands/arguments/resolvers/enum.ts +38 -0
  70. package/src/commands/arguments/resolvers/float.ts +39 -0
  71. package/src/commands/arguments/resolvers/guild.ts +25 -0
  72. package/src/commands/arguments/resolvers/guildCategoryChannel.ts +27 -0
  73. package/src/commands/arguments/resolvers/guildChannel.ts +53 -0
  74. package/src/commands/arguments/resolvers/guildNewsChannel.ts +27 -0
  75. package/src/commands/arguments/resolvers/guildNewsThreadChannel.ts +28 -0
  76. package/src/commands/arguments/resolvers/guildPrivateThreadChannel.ts +28 -0
  77. package/src/commands/arguments/resolvers/guildPublicThreadChannel.ts +28 -0
  78. package/src/commands/arguments/resolvers/guildStageVoiceChannel.ts +27 -0
  79. package/src/commands/arguments/resolvers/guildTextChannel.ts +27 -0
  80. package/src/commands/arguments/resolvers/guildThreadChannel.ts +27 -0
  81. package/src/commands/arguments/resolvers/guildVoiceChannel.ts +27 -0
  82. package/src/commands/arguments/resolvers/hyperlink.ts +18 -0
  83. package/src/commands/arguments/resolvers/index.ts +27 -0
  84. package/src/commands/arguments/resolvers/integer.ts +39 -0
  85. package/src/commands/arguments/resolvers/internal/resolveGuildChannelPredicate.ts +24 -0
  86. package/src/commands/arguments/resolvers/member.ts +59 -0
  87. package/src/commands/arguments/resolvers/message.ts +179 -0
  88. package/src/commands/arguments/resolvers/number.ts +38 -0
  89. package/src/commands/arguments/resolvers/partialDMChannel.ts +30 -0
  90. package/src/commands/arguments/resolvers/role.ts +46 -0
  91. package/src/commands/arguments/resolvers/string.ts +37 -0
  92. package/src/commands/arguments/resolvers/user.ts +31 -0
  93. package/src/commands/checks/Precondition.ts +266 -0
  94. package/src/commands/checks/PreconditionStore.ts +153 -0
  95. package/src/commands/checks/builtins/ClientPermissions.ts +220 -0
  96. package/src/commands/checks/builtins/Cooldown.ts +173 -0
  97. package/src/commands/checks/builtins/DMOnly.ts +48 -0
  98. package/src/commands/checks/builtins/Enabled.ts +73 -0
  99. package/src/commands/checks/builtins/GuildNewsOnly.ts +65 -0
  100. package/src/commands/checks/builtins/GuildNewsThreadOnly.ts +59 -0
  101. package/src/commands/checks/builtins/GuildOnly.ts +48 -0
  102. package/src/commands/checks/builtins/GuildPrivateThreadOnly.ts +58 -0
  103. package/src/commands/checks/builtins/GuildPublicThreadOnly.ts +58 -0
  104. package/src/commands/checks/builtins/GuildTextOnly.ts +64 -0
  105. package/src/commands/checks/builtins/GuildThreadOnly.ts +50 -0
  106. package/src/commands/checks/builtins/GuildVoiceOnly.ts +51 -0
  107. package/src/commands/checks/builtins/NSFW.ts +64 -0
  108. package/src/commands/checks/builtins/RunIn.ts +111 -0
  109. package/src/commands/checks/builtins/UserPermissions.ts +109 -0
  110. package/src/commands/checks/containers/Container.ts +43 -0
  111. package/src/commands/checks/containers/Entry.ts +151 -0
  112. package/src/commands/checks/containers/Group.ts +236 -0
  113. package/src/commands/checks/containers/conditions/Condition.ts +66 -0
  114. package/src/commands/checks/containers/conditions/all.ts +71 -0
  115. package/src/commands/checks/containers/conditions/any.ts +102 -0
  116. package/src/commands/checks/containers/permissions/client.ts +24 -0
  117. package/src/commands/checks/containers/permissions/user.ts +24 -0
  118. package/src/commands/checks/core.ts +90 -0
  119. package/src/commands/checks/register.ts +94 -0
  120. package/src/commands/checks/resolvers/clientPermissions.ts +17 -0
  121. package/src/commands/checks/resolvers/cooldown.ts +37 -0
  122. package/src/commands/checks/resolvers/index.ts +5 -0
  123. package/src/commands/checks/resolvers/nsfw.ts +11 -0
  124. package/src/commands/checks/resolvers/runIn.ts +55 -0
  125. package/src/commands/checks/resolvers/userPermissions.ts +17 -0
  126. package/src/commands/enums.ts +93 -0
  127. package/src/commands/errors/ArgumentError.ts +44 -0
  128. package/src/commands/errors/Identifiers.ts +134 -0
  129. package/src/commands/errors/PreconditionError.ts +38 -0
  130. package/src/commands/errors/UserError.ts +39 -0
  131. package/src/commands/execution/autocomplete.ts +57 -0
  132. package/src/commands/execution/chatInput/accepted.ts +58 -0
  133. package/src/commands/execution/chatInput/beforeRun.ts +47 -0
  134. package/src/commands/execution/chatInput/resolve.ts +52 -0
  135. package/src/commands/execution/contextMenu/accepted.ts +58 -0
  136. package/src/commands/execution/contextMenu/beforeRun.ts +47 -0
  137. package/src/commands/execution/contextMenu/resolve.ts +52 -0
  138. package/src/commands/message/listeners/messageCommandAccepted.ts +55 -0
  139. package/src/commands/message/listeners/messageCommandTyping.ts +38 -0
  140. package/src/commands/message/listeners/messageCreate.ts +19 -0
  141. package/src/commands/message/listeners/preMessageCommandRun.ts +47 -0
  142. package/src/commands/message/listeners/preMessageParser.ts +117 -0
  143. package/src/commands/message/listeners/prefixedMessage.ts +78 -0
  144. package/src/commands/message/listeners/register.ts +41 -0
  145. package/src/commands/registration/Registry.ts +845 -0
  146. package/src/commands/registration/api.ts +33 -0
  147. package/src/commands/registration/computeDifferences/_shared.ts +84 -0
  148. package/src/commands/registration/computeDifferences/contexts.ts +57 -0
  149. package/src/commands/registration/computeDifferences/default_member_permissions.ts +14 -0
  150. package/src/commands/registration/computeDifferences/description.ts +19 -0
  151. package/src/commands/registration/computeDifferences/dm_permission.ts +14 -0
  152. package/src/commands/registration/computeDifferences/integration_types.ts +58 -0
  153. package/src/commands/registration/computeDifferences/localizations.ts +89 -0
  154. package/src/commands/registration/computeDifferences/name.ts +19 -0
  155. package/src/commands/registration/computeDifferences/option/autocomplete.ts +120 -0
  156. package/src/commands/registration/computeDifferences/option/channelTypes.ts +99 -0
  157. package/src/commands/registration/computeDifferences/option/minMaxLength.ts +76 -0
  158. package/src/commands/registration/computeDifferences/option/minMaxValue.ts +78 -0
  159. package/src/commands/registration/computeDifferences/option/required.ts +19 -0
  160. package/src/commands/registration/computeDifferences/option/type.ts +26 -0
  161. package/src/commands/registration/computeDifferences/options.ts +310 -0
  162. package/src/commands/registration/computeDifferences.ts +167 -0
  163. package/src/commands/registration/getNeededParameters.ts +62 -0
  164. package/src/commands/registration/listeners/bulkOverwrite.ts +28 -0
  165. package/src/commands/registration/listeners/initialising.ts +22 -0
  166. package/src/commands/registration/listeners/register.ts +23 -0
  167. package/src/commands/registration/listeners/registered.ts +27 -0
  168. package/src/commands/registration/normalizeInputs.ts +202 -0
  169. package/src/commands/registration/registries.ts +340 -0
  170. package/src/commands/registration/registriesErrors.ts +41 -0
  171. package/src/commands/registration/registriesLog.ts +41 -0
  172. package/src/commands/types.ts +256 -0
  173. package/src/core/Container.ts +41 -0
  174. package/src/core/client/RiloClient.ts +636 -0
  175. package/src/core/config/extensions.ts +87 -0
  176. package/src/core/config/options.ts +29 -0
  177. package/src/core/errors/MissingModuleError.ts +19 -0
  178. package/src/core/errors/ModuleCleanupError.ts +2 -0
  179. package/src/core/errors/ModuleLoadError.ts +32 -0
  180. package/src/core/index.ts +69 -0
  181. package/src/core/lifecycle/Extension.ts +25 -0
  182. package/src/core/loading/ModuleGlob.ts +159 -0
  183. package/src/core/loading/ModuleLoader.ts +116 -0
  184. package/src/core/loading/Shared.ts +2 -0
  185. package/src/core/loading/constants.ts +2 -0
  186. package/src/core/loading/contracts.ts +71 -0
  187. package/src/core/logging/LoggerLike.ts +27 -0
  188. package/src/core/logging/console.ts +325 -0
  189. package/src/core/logging/diagnostics.ts +60 -0
  190. package/src/core/logging/format.ts +406 -0
  191. package/src/core/logging/index.ts +15 -0
  192. package/src/core/logging/presentation.ts +343 -0
  193. package/src/core/logging/redact.ts +167 -0
  194. package/src/core/logging/text.ts +46 -0
  195. package/src/core/modules/AliasModule.ts +64 -0
  196. package/src/core/modules/AliasModuleStore.ts +48 -0
  197. package/src/core/modules/Module.ts +136 -0
  198. package/src/core/modules/ModuleLocation.ts +66 -0
  199. package/src/core/modules/ModuleRegistry.ts +372 -0
  200. package/src/core/modules/ModuleStore.ts +447 -0
  201. package/src/core/modules/index.ts +12 -0
  202. package/src/core/runtime.ts +2 -0
  203. package/src/engine/cache/CacheStore.ts +126 -0
  204. package/src/engine/cache/EngineCache.ts +374 -0
  205. package/src/engine/cache/ScopedCache.ts +126 -0
  206. package/src/engine/cache/activity.ts +78 -0
  207. package/src/engine/cache/merge.ts +26 -0
  208. package/src/engine/cache/types.ts +96 -0
  209. package/src/engine/client/EngineClient.ts +280 -0
  210. package/src/engine/client/EngineInteraction.ts +83 -0
  211. package/src/engine/client/EngineMessage.ts +34 -0
  212. package/src/engine/client/EventHub.ts +70 -0
  213. package/src/engine/client/types.ts +76 -0
  214. package/src/engine/common.ts +72 -0
  215. package/src/engine/gateway/GatewayShard.ts +392 -0
  216. package/src/engine/gateway/Heartbeat.ts +48 -0
  217. package/src/engine/gateway/IdentifyGate.ts +46 -0
  218. package/src/engine/gateway/protocol.ts +60 -0
  219. package/src/engine/gateway/types.ts +27 -0
  220. package/src/engine/rest/RateLimits.ts +164 -0
  221. package/src/engine/rest/RequestQueue.ts +100 -0
  222. package/src/engine/rest/RestClient.ts +402 -0
  223. package/src/engine/rest/RestError.ts +17 -0
  224. package/src/events/errors/autocomplete.ts +28 -0
  225. package/src/events/errors/chatInput.ts +28 -0
  226. package/src/events/errors/contextMenu.ts +28 -0
  227. package/src/events/errors/interaction.ts +28 -0
  228. package/src/events/errors/interactionParse.ts +31 -0
  229. package/src/events/errors/listener.ts +23 -0
  230. package/src/events/errors/message.ts +28 -0
  231. package/src/events/errors/register.ts +53 -0
  232. package/src/events/errors/registration.ts +24 -0
  233. package/src/events/events.ts +855 -0
  234. package/src/events/interactionCreate.ts +41 -0
  235. package/src/events/interactions/interactionHandler.ts +113 -0
  236. package/src/events/interactions/interactionHandlerStore.ts +158 -0
  237. package/src/events/listener.ts +120 -0
  238. package/src/events/listenerModuleLoader.ts +42 -0
  239. package/src/events/listenerStore.ts +14 -0
  240. package/src/events/ready.ts +27 -0
  241. package/src/events/register.ts +58 -0
  242. package/src/extensions/localisation/LocaleManager.ts +394 -0
  243. package/src/extensions/localisation/commands.ts +479 -0
  244. package/src/extensions/localisation/extension.ts +21 -0
  245. package/src/extensions/localisation/functions.ts +316 -0
  246. package/src/extensions/localisation/index.ts +4 -0
  247. package/src/extensions/localisation/resources.ts +143 -0
  248. package/src/extensions/localisation/types.ts +216 -0
  249. package/src/extensions/patternCommands/PatternCommand.ts +82 -0
  250. package/src/extensions/patternCommands/PatternCommandStore.ts +10 -0
  251. package/src/extensions/patternCommands/events.ts +19 -0
  252. package/src/extensions/patternCommands/extension.ts +14 -0
  253. package/src/extensions/patternCommands/index.ts +8 -0
  254. package/src/extensions/patternCommands/listeners/commandAccepted.ts +56 -0
  255. package/src/extensions/patternCommands/listeners/messageParse.ts +123 -0
  256. package/src/extensions/patternCommands/listeners/preCommandRun.ts +66 -0
  257. package/src/extensions/patternCommands/listeners/register.ts +23 -0
  258. package/src/extensions/patternCommands/types.ts +70 -0
  259. package/src/extensions/scheduledTasks/Task.ts +101 -0
  260. package/src/extensions/scheduledTasks/TaskScheduler.ts +523 -0
  261. package/src/extensions/scheduledTasks/TaskStore.ts +47 -0
  262. package/src/extensions/scheduledTasks/backends/MemoryBackend.ts +103 -0
  263. package/src/extensions/scheduledTasks/backends/RedisBackend.ts +163 -0
  264. package/src/extensions/scheduledTasks/backends/TaskBackend.ts +19 -0
  265. package/src/extensions/scheduledTasks/backends/scripts.ts +83 -0
  266. package/src/extensions/scheduledTasks/extension.ts +26 -0
  267. package/src/extensions/scheduledTasks/index.ts +6 -0
  268. package/src/extensions/scheduledTasks/listeners/error.ts +27 -0
  269. package/src/extensions/scheduledTasks/listeners/notFound.ts +24 -0
  270. package/src/extensions/scheduledTasks/listeners/register.ts +17 -0
  271. package/src/extensions/scheduledTasks/timing.ts +179 -0
  272. package/src/extensions/scheduledTasks/types/TaskEvents.ts +55 -0
  273. package/src/extensions/scheduledTasks/types/TaskTypes.ts +199 -0
  274. package/src/extensions/services/Service.ts +18 -0
  275. package/src/extensions/services/ServiceStore.ts +10 -0
  276. package/src/extensions/services/Services.ts +20 -0
  277. package/src/extensions/services/extension.ts +14 -0
  278. package/src/extensions/services/index.ts +14 -0
  279. package/src/extensions/subcommands/Subcommand.ts +715 -0
  280. package/src/extensions/subcommands/extension.ts +15 -0
  281. package/src/extensions/subcommands/index.ts +30 -0
  282. package/src/extensions/subcommands/listeners/chatInputError.ts +35 -0
  283. package/src/extensions/subcommands/listeners/chatInputNoMatch.ts +28 -0
  284. package/src/extensions/subcommands/listeners/messageError.ts +32 -0
  285. package/src/extensions/subcommands/listeners/messageNoMatch.ts +30 -0
  286. package/src/extensions/subcommands/listeners/missingChatInputHandler.ts +37 -0
  287. package/src/extensions/subcommands/listeners/missingMessageHandler.ts +37 -0
  288. package/src/extensions/subcommands/listeners/register.ts +42 -0
  289. package/src/extensions/subcommands/preconditionResolvers/subcommandCooldown.ts +83 -0
  290. package/src/extensions/subcommands/preconditions/SubcommandCooldown.ts +189 -0
  291. package/src/extensions/subcommands/preconditions/register.ts +12 -0
  292. package/src/extensions/subcommands/types/Enums.ts +11 -0
  293. package/src/extensions/subcommands/types/Events.ts +228 -0
  294. package/src/extensions/subcommands/types/mappings.ts +67 -0
  295. package/src/index.ts +19 -0
  296. package/src/public/client.ts +10 -0
  297. package/src/public/commands.ts +45 -0
  298. package/src/public/discord.ts +12 -0
  299. package/src/public/engine.ts +58 -0
  300. package/src/public/events.ts +12 -0
  301. package/src/public/extensions.ts +16 -0
  302. package/src/public/localisation.ts +7 -0
  303. package/src/public/modules.ts +32 -0
  304. package/src/public/scheduling.ts +11 -0
  305. package/src/public/services.ts +7 -0
  306. package/src/public/sharding.ts +7 -0
  307. package/src/public/time.ts +9 -0
  308. package/src/public/utilities.ts +22 -0
  309. package/src/public/validation.ts +14 -0
  310. package/src/sharding/LICENSE +191 -0
  311. package/src/sharding/client/Link.ts +735 -0
  312. package/src/sharding/client/gateway.ts +113 -0
  313. package/src/sharding/coordinator/Coordinator.ts +1696 -0
  314. package/src/sharding/coordinator/identify.ts +111 -0
  315. package/src/sharding/coordinator/scaling.ts +186 -0
  316. package/src/sharding/index.ts +4 -0
  317. package/src/sharding/manager/Manager.ts +1430 -0
  318. package/src/sharding/messaging.ts +185 -0
  319. package/src/sharding/stats.ts +91 -0
  320. package/src/sharding/transport/availability.ts +76 -0
  321. package/src/sharding/transport/pending.ts +79 -0
  322. package/src/sharding/transport/protocol.ts +317 -0
  323. package/src/sharding/transport/socket.ts +5 -0
  324. package/src/sharding/types.ts +292 -0
  325. package/src/utilities/array/arrayStrictEquals.ts +13 -0
  326. package/src/utilities/array/chunk.ts +11 -0
  327. package/src/utilities/array/filterNullAndUndefined.ts +11 -0
  328. package/src/utilities/array/filterNullAndUndefinedAndEmpty.ts +15 -0
  329. package/src/utilities/array/filterNullAndUndefinedAndZero.ts +15 -0
  330. package/src/utilities/array/partition.ts +26 -0
  331. package/src/utilities/array/pickRandom.ts +36 -0
  332. package/src/utilities/array/range.ts +6 -0
  333. package/src/utilities/async/events/index.ts +149 -0
  334. package/src/utilities/async/queue/AsyncQueue.ts +70 -0
  335. package/src/utilities/async/queue/_AsyncQueueEntry.ts +59 -0
  336. package/src/utilities/async/queue/index.ts +1 -0
  337. package/src/utilities/binary/buffer/DuplexBuffer.ts +209 -0
  338. package/src/utilities/binary/buffer/UnalignedUint16Array.ts +520 -0
  339. package/src/utilities/binary/index.ts +8 -0
  340. package/src/utilities/binary/schema/Schema.ts +376 -0
  341. package/src/utilities/binary/schema/SchemaStore.ts +157 -0
  342. package/src/utilities/binary/shared/Pointer.ts +57 -0
  343. package/src/utilities/binary/shared/_common.ts +24 -0
  344. package/src/utilities/binary/shared/codepoints.ts +21 -0
  345. package/src/utilities/binary/types/Array.ts +33 -0
  346. package/src/utilities/binary/types/BigInt32.ts +15 -0
  347. package/src/utilities/binary/types/BigInt64.ts +15 -0
  348. package/src/utilities/binary/types/BigUint32.ts +15 -0
  349. package/src/utilities/binary/types/BigUint64.ts +15 -0
  350. package/src/utilities/binary/types/Bit.ts +15 -0
  351. package/src/utilities/binary/types/Boolean.ts +15 -0
  352. package/src/utilities/binary/types/Constant.ts +18 -0
  353. package/src/utilities/binary/types/FixedLengthArray.ts +40 -0
  354. package/src/utilities/binary/types/Float32.ts +15 -0
  355. package/src/utilities/binary/types/Float64.ts +15 -0
  356. package/src/utilities/binary/types/Int16.ts +15 -0
  357. package/src/utilities/binary/types/Int2.ts +15 -0
  358. package/src/utilities/binary/types/Int32.ts +15 -0
  359. package/src/utilities/binary/types/Int4.ts +15 -0
  360. package/src/utilities/binary/types/Int64.ts +15 -0
  361. package/src/utilities/binary/types/Int8.ts +15 -0
  362. package/src/utilities/binary/types/Nullable.ts +25 -0
  363. package/src/utilities/binary/types/Snowflake.ts +15 -0
  364. package/src/utilities/binary/types/String.ts +29 -0
  365. package/src/utilities/binary/types/Uint16.ts +15 -0
  366. package/src/utilities/binary/types/Uint2.ts +15 -0
  367. package/src/utilities/binary/types/Uint32.ts +15 -0
  368. package/src/utilities/binary/types/Uint4.ts +15 -0
  369. package/src/utilities/binary/types/Uint64.ts +15 -0
  370. package/src/utilities/binary/types/Uint8.ts +15 -0
  371. package/src/utilities/binary/types/base/IType.ts +18 -0
  372. package/src/utilities/binary/types/index.ts +113 -0
  373. package/src/utilities/binary/utilities.ts +42 -0
  374. package/src/utilities/collections/bitfield/BitField.ts +232 -0
  375. package/src/utilities/collections/bitfield/index.ts +2 -0
  376. package/src/utilities/collections/bitfield/utilities.ts +12 -0
  377. package/src/utilities/decorators/base-decorators.ts +25 -0
  378. package/src/utilities/decorators/djs-decorators.ts +161 -0
  379. package/src/utilities/decorators/index.ts +4 -0
  380. package/src/utilities/decorators/module-decorators.ts +221 -0
  381. package/src/utilities/decorators/utils.ts +60 -0
  382. package/src/utilities/discord/builders/MessageBuilder.ts +119 -0
  383. package/src/utilities/discord/constants/TwemojiRegex.ts +8 -0
  384. package/src/utilities/discord/constants/index.ts +8 -0
  385. package/src/utilities/discord/constants/limits.ts +499 -0
  386. package/src/utilities/discord/constants/regexes.ts +59 -0
  387. package/src/utilities/discord/constants/resolvers/AutocompleteInteractionOptionResolver.ts +139 -0
  388. package/src/utilities/discord/constants/resolvers/ChatInputInteractionOptionResolver.ts +501 -0
  389. package/src/utilities/discord/constants/resolvers/ContextMenuInteractionOptionResolver.ts +96 -0
  390. package/src/utilities/discord/constants/resolvers/ModalInteractionOptionResolver.ts +135 -0
  391. package/src/utilities/discord/constants/resolvers/util.ts +72 -0
  392. package/src/utilities/discord/index.ts +7 -0
  393. package/src/utilities/discord/pagination/LazyPaginatedMessage.ts +121 -0
  394. package/src/utilities/discord/pagination/PaginatedFieldMessageEmbed.ts +118 -0
  395. package/src/utilities/discord/pagination/PaginatedMessage.ts +1345 -0
  396. package/src/utilities/discord/pagination/PaginatedMessageEmbedFields.ts +103 -0
  397. package/src/utilities/discord/pagination/PaginatedMessageTypes.ts +238 -0
  398. package/src/utilities/discord/pagination/Pagination.ts +536 -0
  399. package/src/utilities/discord/pagination/index.ts +7 -0
  400. package/src/utilities/discord/pagination/utils.ts +244 -0
  401. package/src/utilities/discord/prompts/ExplicitReturnTypes.ts +41 -0
  402. package/src/utilities/discord/prompts/MessagePrompter.ts +134 -0
  403. package/src/utilities/discord/prompts/constants.ts +17 -0
  404. package/src/utilities/discord/prompts/index.ts +12 -0
  405. package/src/utilities/discord/prompts/strategies/MessagePrompterBaseStrategy.ts +161 -0
  406. package/src/utilities/discord/prompts/strategies/MessagePrompterConfirmStrategy.ts +60 -0
  407. package/src/utilities/discord/prompts/strategies/MessagePrompterMessageStrategy.ts +82 -0
  408. package/src/utilities/discord/prompts/strategies/MessagePrompterNumberStrategy.ts +84 -0
  409. package/src/utilities/discord/prompts/strategies/MessagePrompterReactionStrategy.ts +50 -0
  410. package/src/utilities/discord/prompts/strategyOptions.ts +35 -0
  411. package/src/utilities/discord/snowflake/DiscordSnowflake.ts +4 -0
  412. package/src/utilities/discord/snowflake/Snowflake.ts +208 -0
  413. package/src/utilities/discord/snowflake/TwitterSnowflake.ts +4 -0
  414. package/src/utilities/discord/snowflake/index.ts +3 -0
  415. package/src/utilities/discord/type-guards.ts +262 -0
  416. package/src/utilities/discord/utilities.ts +127 -0
  417. package/src/utilities/discord/utility-types.ts +86 -0
  418. package/src/utilities/filesystem/findFilesRecursively.ts +78 -0
  419. package/src/utilities/filesystem/index.ts +1 -0
  420. package/src/utilities/function/cast.ts +4 -0
  421. package/src/utilities/function/debounce/LICENSE +47 -0
  422. package/src/utilities/function/debounce/debounce.ts +164 -0
  423. package/src/utilities/function/lazy.ts +6 -0
  424. package/src/utilities/function/noop.ts +2 -0
  425. package/src/utilities/function/poll.ts +82 -0
  426. package/src/utilities/function/pollSync.ts +81 -0
  427. package/src/utilities/function/retry.ts +27 -0
  428. package/src/utilities/function/retrySync.ts +22 -0
  429. package/src/utilities/function/sleep.ts +45 -0
  430. package/src/utilities/function/sleepSync.ts +6 -0
  431. package/src/utilities/function/throttle.ts +37 -0
  432. package/src/utilities/guards/classExtends.ts +15 -0
  433. package/src/utilities/guards/hasAtLeastOneKeyInMap.ts +7 -0
  434. package/src/utilities/guards/hasAtLeastOneKeyInObject.ts +9 -0
  435. package/src/utilities/guards/isClass.ts +6 -0
  436. package/src/utilities/guards/isFunction.ts +6 -0
  437. package/src/utilities/guards/isNullOrUndefined.ts +8 -0
  438. package/src/utilities/guards/isNullOrUndefinedOrEmpty.ts +11 -0
  439. package/src/utilities/guards/isNullOrUndefinedOrZero.ts +9 -0
  440. package/src/utilities/guards/isNumber.ts +7 -0
  441. package/src/utilities/guards/isObject.ts +36 -0
  442. package/src/utilities/guards/isPrimitive.ts +8 -0
  443. package/src/utilities/guards/isThenable.ts +31 -0
  444. package/src/utilities/http/HttpError.ts +28 -0
  445. package/src/utilities/http/index.ts +2 -0
  446. package/src/utilities/http/request.ts +135 -0
  447. package/src/utilities/index.ts +53 -0
  448. package/src/utilities/iterators/all.ts +1 -0
  449. package/src/utilities/iterators/any.ts +1 -0
  450. package/src/utilities/iterators/append.ts +12 -0
  451. package/src/utilities/iterators/at.ts +17 -0
  452. package/src/utilities/iterators/average.ts +23 -0
  453. package/src/utilities/iterators/chain.ts +11 -0
  454. package/src/utilities/iterators/chunk.ts +29 -0
  455. package/src/utilities/iterators/collect.ts +1 -0
  456. package/src/utilities/iterators/collectInto.ts +14 -0
  457. package/src/utilities/iterators/compact.ts +12 -0
  458. package/src/utilities/iterators/compare.ts +15 -0
  459. package/src/utilities/iterators/compareBy.ts +34 -0
  460. package/src/utilities/iterators/compress.ts +20 -0
  461. package/src/utilities/iterators/contains.ts +14 -0
  462. package/src/utilities/iterators/count.ts +14 -0
  463. package/src/utilities/iterators/cycle.ts +22 -0
  464. package/src/utilities/iterators/difference.ts +17 -0
  465. package/src/utilities/iterators/drop.ts +28 -0
  466. package/src/utilities/iterators/dropLast.ts +20 -0
  467. package/src/utilities/iterators/dropWhile.ts +40 -0
  468. package/src/utilities/iterators/empty.ts +11 -0
  469. package/src/utilities/iterators/enumerate.ts +12 -0
  470. package/src/utilities/iterators/equal.ts +12 -0
  471. package/src/utilities/iterators/equalBy.ts +26 -0
  472. package/src/utilities/iterators/every.ts +40 -0
  473. package/src/utilities/iterators/filter.ts +38 -0
  474. package/src/utilities/iterators/find.ts +30 -0
  475. package/src/utilities/iterators/findIndex.ts +22 -0
  476. package/src/utilities/iterators/first.ts +8 -0
  477. package/src/utilities/iterators/flat.ts +11 -0
  478. package/src/utilities/iterators/flatMap.ts +19 -0
  479. package/src/utilities/iterators/forEach.ts +16 -0
  480. package/src/utilities/iterators/from.ts +50 -0
  481. package/src/utilities/iterators/fuse.ts +23 -0
  482. package/src/utilities/iterators/greaterOrEqualThan.ts +14 -0
  483. package/src/utilities/iterators/greaterThan.ts +14 -0
  484. package/src/utilities/iterators/index.ts +91 -0
  485. package/src/utilities/iterators/indexOf.ts +19 -0
  486. package/src/utilities/iterators/inspect.ts +22 -0
  487. package/src/utilities/iterators/intersect.ts +12 -0
  488. package/src/utilities/iterators/intersperse.ts +34 -0
  489. package/src/utilities/iterators/isEmpty.ts +8 -0
  490. package/src/utilities/iterators/isSorted.ts +10 -0
  491. package/src/utilities/iterators/isSortedBy.ts +37 -0
  492. package/src/utilities/iterators/isSortedByKey.ts +41 -0
  493. package/src/utilities/iterators/last.ts +14 -0
  494. package/src/utilities/iterators/lessOrEqualThan.ts +14 -0
  495. package/src/utilities/iterators/lessThan.ts +14 -0
  496. package/src/utilities/iterators/map.ts +19 -0
  497. package/src/utilities/iterators/max.ts +13 -0
  498. package/src/utilities/iterators/maxBy.ts +34 -0
  499. package/src/utilities/iterators/maxByKey.ts +44 -0
  500. package/src/utilities/iterators/min.ts +10 -0
  501. package/src/utilities/iterators/minBy.ts +35 -0
  502. package/src/utilities/iterators/minByKey.ts +44 -0
  503. package/src/utilities/iterators/notEqual.ts +12 -0
  504. package/src/utilities/iterators/nth.ts +1 -0
  505. package/src/utilities/iterators/partition.ts +48 -0
  506. package/src/utilities/iterators/peekable.ts +32 -0
  507. package/src/utilities/iterators/position.ts +1 -0
  508. package/src/utilities/iterators/prepend.ts +14 -0
  509. package/src/utilities/iterators/product.ts +13 -0
  510. package/src/utilities/iterators/range.ts +44 -0
  511. package/src/utilities/iterators/reduce.ts +40 -0
  512. package/src/utilities/iterators/repeat.ts +21 -0
  513. package/src/utilities/iterators/reverse.ts +12 -0
  514. package/src/utilities/iterators/shared/_assertFunction.ts +9 -0
  515. package/src/utilities/iterators/shared/_assertNotNegative.ts +7 -0
  516. package/src/utilities/iterators/shared/_assertPositive.ts +7 -0
  517. package/src/utilities/iterators/shared/_compare.ts +47 -0
  518. package/src/utilities/iterators/shared/_makeIterableIterator.ts +10 -0
  519. package/src/utilities/iterators/shared/_toIntegerOrInfinityOrThrow.ts +10 -0
  520. package/src/utilities/iterators/shared/_toIntegerOrThrow.ts +12 -0
  521. package/src/utilities/iterators/shared/_toNumberOrThrow.ts +38 -0
  522. package/src/utilities/iterators/shared/comparators.ts +33 -0
  523. package/src/utilities/iterators/skip.ts +1 -0
  524. package/src/utilities/iterators/skipLast.ts +1 -0
  525. package/src/utilities/iterators/skipWhile.ts +1 -0
  526. package/src/utilities/iterators/slice.ts +70 -0
  527. package/src/utilities/iterators/some.ts +23 -0
  528. package/src/utilities/iterators/sorted.ts +10 -0
  529. package/src/utilities/iterators/starMap.ts +32 -0
  530. package/src/utilities/iterators/stepBy.ts +30 -0
  531. package/src/utilities/iterators/sum.ts +16 -0
  532. package/src/utilities/iterators/take.ts +25 -0
  533. package/src/utilities/iterators/takeLast.ts +30 -0
  534. package/src/utilities/iterators/takeWhile.ts +1 -0
  535. package/src/utilities/iterators/tee.ts +42 -0
  536. package/src/utilities/iterators/toArray.ts +9 -0
  537. package/src/utilities/iterators/toIterableIterator.ts +14 -0
  538. package/src/utilities/iterators/union.ts +20 -0
  539. package/src/utilities/iterators/unique.ts +10 -0
  540. package/src/utilities/iterators/unzip.ts +43 -0
  541. package/src/utilities/iterators/windows.ts +30 -0
  542. package/src/utilities/iterators/zip.ts +36 -0
  543. package/src/utilities/number/roundNumber.ts +11 -0
  544. package/src/utilities/object/deepClone.ts +86 -0
  545. package/src/utilities/object/getDeepObjectKeys.ts +92 -0
  546. package/src/utilities/object/makeObject.ts +32 -0
  547. package/src/utilities/object/mergeDefault.ts +37 -0
  548. package/src/utilities/object/mergeObjects.ts +33 -0
  549. package/src/utilities/object/objectEntries.ts +14 -0
  550. package/src/utilities/object/objectKeys.ts +12 -0
  551. package/src/utilities/object/objectToTuples.ts +19 -0
  552. package/src/utilities/object/objectValues.ts +12 -0
  553. package/src/utilities/object/omitKeysFromObject.ts +15 -0
  554. package/src/utilities/parsing/ArgumentStream.ts +440 -0
  555. package/src/utilities/parsing/index.ts +13 -0
  556. package/src/utilities/parsing/lexer/Lexer.ts +48 -0
  557. package/src/utilities/parsing/lexer/streams/ParameterStream.ts +37 -0
  558. package/src/utilities/parsing/lexer/streams/parameters/BaseParameter.ts +21 -0
  559. package/src/utilities/parsing/lexer/streams/parameters/QuotedParameter.ts +32 -0
  560. package/src/utilities/parsing/lexer/streams/parameters/WordParameter.ts +26 -0
  561. package/src/utilities/parsing/lexer/streams/raw/TokenStream.ts +110 -0
  562. package/src/utilities/parsing/parser/Parser.ts +37 -0
  563. package/src/utilities/parsing/parser/ParserResult.ts +60 -0
  564. package/src/utilities/parsing/parser/strategies/EmptyStrategy.ts +15 -0
  565. package/src/utilities/parsing/parser/strategies/IUnorderedStrategy.ts +10 -0
  566. package/src/utilities/parsing/parser/strategies/PrefixedStrategy.ts +71 -0
  567. package/src/utilities/parsing/strategies/FlagUnorderedStrategy.ts +76 -0
  568. package/src/utilities/parsing/util/util.ts +29 -0
  569. package/src/utilities/result/Option.ts +481 -0
  570. package/src/utilities/result/OptionError.ts +7 -0
  571. package/src/utilities/result/Result.ts +564 -0
  572. package/src/utilities/result/ResultError.ts +20 -0
  573. package/src/utilities/result/common/utils.ts +38 -0
  574. package/src/utilities/result/index.ts +4 -0
  575. package/src/utilities/text/capitalizeFirstLetter.ts +4 -0
  576. package/src/utilities/text/codeBlock.ts +15 -0
  577. package/src/utilities/text/cutText.ts +26 -0
  578. package/src/utilities/text/inlineCodeBlock.ts +13 -0
  579. package/src/utilities/text/regExpEsc.ts +6 -0
  580. package/src/utilities/text/snakeToCamelCase.ts +8 -0
  581. package/src/utilities/text/splitText.ts +13 -0
  582. package/src/utilities/text/toTitleCase.ts +48 -0
  583. package/src/utilities/text/tryParseJSON.ts +16 -0
  584. package/src/utilities/text/tryParseURL.ts +13 -0
  585. package/src/utilities/time/cron/Cron.ts +162 -0
  586. package/src/utilities/time/cron/constants.ts +88 -0
  587. package/src/utilities/time/cron/index.ts +2 -0
  588. package/src/utilities/time/duration/Duration.ts +157 -0
  589. package/src/utilities/time/duration/DurationFormatter.ts +113 -0
  590. package/src/utilities/time/duration/constants.ts +109 -0
  591. package/src/utilities/time/duration/index.ts +3 -0
  592. package/src/utilities/time/index.ts +29 -0
  593. package/src/utilities/time/ratelimits/RateLimit.ts +63 -0
  594. package/src/utilities/time/ratelimits/RateLimitManager.ts +85 -0
  595. package/src/utilities/time/ratelimits/index.ts +2 -0
  596. package/src/utilities/time/stopwatch/index.ts +68 -0
  597. package/src/utilities/time/timers/TimerManager.ts +53 -0
  598. package/src/utilities/time/timers/index.ts +1 -0
  599. package/src/utilities/time/timestamp/Timestamp.ts +264 -0
  600. package/src/utilities/time/timestamp/constants.ts +62 -0
  601. package/src/utilities/time/timestamp/index.ts +2 -0
  602. package/src/utilities/types.ts +191 -0
  603. package/src/version.ts +3 -0
package/docs/engine.md ADDED
@@ -0,0 +1,144 @@
1
+ # Original Discord engine milestone
2
+
3
+ `rilo/engine` is an experimental, independent Bun client implemented inside Rilo. It owns its gateway session, REST transport and synchronous cache. The existing RiloClient, module system, commands, extensions and root exports retain their current behavior. Importing the engine does not migrate framework features.
4
+
5
+ ## Run it
6
+
7
+ Use Bun canary (`bun upgrade --canary`) and `bun install --frozen-lockfile`.
8
+
9
+ ```sh
10
+ bun run engine:test
11
+ bun check
12
+ bun lint
13
+ bun fmt --check
14
+ bun examples/engine/offline.ts
15
+ ```
16
+
17
+ The offline example creates a loopback HTTP/WebSocket server, receives a message, replies using the engine's REST layer, then reconnects and resumes. It uses a literal fake token.
18
+
19
+ `bun examples/engine/live.ts` only logs instructions. To opt into Discord yourself, set `DISCORD_TOKEN` and add `--live`. The example requires Guilds, GuildMessages and MessageContent intents, plus permission to read and send in the channel. It replies to `!engine-ping`. Its interaction branch handles an already registered `engine-ping` command; it does not register commands. No live Discord validation was performed.
20
+
21
+ ```ts
22
+ import { createConsoleLogger, EngineClient, logEvent } from "rilo/engine";
23
+ import {
24
+ GatewayIntentBits,
25
+ InteractionResponseType,
26
+ } from "discord-api-types/v10";
27
+
28
+ const logger = createConsoleLogger("MyBot");
29
+ const client = new EngineClient({
30
+ token: suppliedToken,
31
+ intents: GatewayIntentBits.Guilds | GatewayIntentBits.GuildMessages,
32
+ cache: { membersPerGuild: 1000, messagesPerChannel: 0 },
33
+ onError: ({ source, error, fatal }) =>
34
+ logEvent(logger, fatal ? "error" : "alert", {
35
+ component: `engine.${source}`,
36
+ event: "diagnostic",
37
+ message: fatal
38
+ ? "Engine cannot continue; inspect the diagnostic cause before restarting."
39
+ : "Engine reported a recoverable failure; inspect the diagnostic cause.",
40
+ context: { fatal },
41
+ error,
42
+ }),
43
+ });
44
+ client.on("messageCreate", async (message) => {
45
+ if (message.data.author.bot) return;
46
+ await message.reply({ content: "Hello", allowed_mentions: { parse: [] } });
47
+ });
48
+ client.on("interactionCreate", async (interaction) => {
49
+ if (interaction.data.type === 2)
50
+ await interaction.respond({
51
+ type: InteractionResponseType.ChannelMessageWithSource,
52
+ data: { content: "Hello", allowed_mentions: { parse: [] } },
53
+ });
54
+ });
55
+ await client.connect();
56
+ // client.close() aborts transport work and clears the session and caches.
57
+ ```
58
+
59
+ Construction and imports open no connections. The engine never reads a token from the environment. Request bodies preserve snake_case fields and native discord-api-types/v10 types. `message.data` is an APIMessage; `interaction.data` is an APIInteraction. `message.reply` supplies a message_reference while preserving native reference options. `interaction.respond` accepts a complete native callback body.
60
+
61
+ The logging helpers share the framework's level, JSON/text, redaction and stack
62
+ settings; see [console logging](console-logging.md). The supplied `onError`
63
+ callback still receives the original error. Add fixed operation wording to the
64
+ record rather than printing arbitrary provider messages.
65
+
66
+ ## Cache contract
67
+
68
+ | Cache | Default | Lookup | Retention |
69
+ | -------------------- | ------- | ------------------------------------ | ---------------------- |
70
+ | Guild metadata | On | `cache.guilds.get(id)` | Until removal/reset |
71
+ | Channels and threads | On | `cache.channels.get(id)` | Until removal/reset |
72
+ | Roles | On | `cache.roles.get(guildId, id)` | Until removal/reset |
73
+ | Members | On | `cache.members.get(guildId, userId)` | LRU, 1,000 per guild |
74
+ | Messages | Off | `cache.messages.get(channelId, id)` | Opt-in LRU per channel |
75
+
76
+ Members have **no combined client limit**. `membersPerGuild` accepts a nonnegative integer or a function of guild ID. Zero disables storage. `guilds`, `channels` and `roles` accept false. `messagesPerChannel` opts into a finite per-channel limit. A synchronous `policy({ kind, id, scope, data })` can reject admission; false also removes an existing entry. A thrown policy error stops the client and clears state instead of continuing after a partly applied transaction. Custom backends are deferred.
77
+
78
+ Results are undefined or a `$CacheEntry<T>` with complete and data. Patches create `complete: false`; accumulated partial fields never promote it. A full typed put, full gateway creation/chunk, or explicit REST fetch can promote it in place. Guild entries intentionally remain partial metadata: bulk members, channels, roles, presences and voice states live separately. This avoids retaining a second unbounded member snapshot inside the guild.
79
+
80
+ Resident entry and data identities remain stable during updates. Nested objects merge; omitted/undefined fields remain; explicit null replaces; arrays replace old contents, so `roles: []` removes membership. Identity ends at eviction, deletion, fresh identification or close. Treat cached objects as engine-owned mutable views; use structuredClone when you need a snapshot.
81
+
82
+ Targeted get, writes and gateway activity update LRU recency. Peek, has, values, entries and iteration do not. Activity discovery follows nested member payloads, guild-scoped user/author IDs, resolved member maps, mentioned users and member/user ID lists. Messages, commands, buttons, reactions, typing and voice payloads participate without an event-name whitelist. Future shapes without recognizable guild/member identity require an explicit cache call or adapter.
83
+
84
+ Deletion removes data before handlers. `cacheDelete` supplies the original dispatch in payload and previous when resident. Missing entries yield undefined; partial previous entries remain partial. Bulk message deletion finishes all removals before any deletion handler. Guild removal clears resident children. An unavailable guild remains marked unavailable and invalidates its member scope. Role deletion removes its ID from resident member role arrays without touching recency.
85
+
86
+ `fetchMember`, `fetchChannel` and `fetchMessage` are explicit HTTP operations; cache lookup never fetches. A fetch writes back only if no gateway dispatch or session reset occurred while pending. Otherwise it returns the HTTP snapshot without overwriting newer gateway state. This conservative rule avoids resurrecting deleted entries, but may skip insertion during unrelated activity.
87
+
88
+ ## Ordering and failures
89
+
90
+ Each EngineClient owns one shard. Decoding, cache mutation and event invocation run synchronously in arrival order. Promise-returning handlers overlap; later cache processing does not await them. A live object's fields can change across await. Synchronous CPU-heavy user code still blocks Bun's event loop.
91
+
92
+ Events are ready, resumed, messageCreate, messageUpdate, interactionCreate, cacheDelete, dispatch and gatewayState. Raw dispatch follows specialized callbacks and sees updated cache. On returns an unsubscribe function. Handler exceptions/rejections go to onError without stopping later handlers. The default ceiling is 1,024 outstanding handler promises. Overflow reports a fatal error and closes the client instead of retaining unbounded work. Closing does not await or cancel developer promises; idle is available when they are known to settle.
93
+
94
+ Gateway ownership includes HELLO/session timeouts, jittered heartbeats, requested beats, ACK debt, reconnect backoff, session ID/sequence/resume URL, stale-generation rejection and cleanup. Fresh identification clears state; resume preserves it. Fatal close codes stop retries. Defaults: 10 reconnect attempts, 15-second handshake deadline, 8 MiB input frames, and capped exponential reconnect delays with jitter. Uncompressed v10 JSON needs no async decoding queue. Runtime validation covers the envelope/session fields, not every entity schema.
95
+
96
+ REST admits up to 8 concurrent attempts. Identical normalized routes and learned bucket hashes serialize within each channel/guild/webhook major partition; independent routes progress concurrently. Cooldowns apply before admitting more attempts. The bound is 1,024 logical requests, including retry delays. Each attempt has a 15-second timeout and an 8 MiB response limit. Rate-limit metadata is bounded independently; exhausting it while cooldowns remain active fails explicitly.
97
+
98
+ 429 handling uses retry_after or Retry-After with a separate retry ceiling of 5. Transport and 5xx failures retry GET/PUT/DELETE at most twice. POST/PATCH are not replayed after ambiguous failure. Interaction initial responses cannot race; ambiguity leaves replyState unknown. JSON bodies are snapshotted on submission. Redirects are rejected and endpoints require TLS except loopback tests. Client/transport token fields are private and absent from ordinary JSON serialization.
99
+
100
+ ## Validation results
101
+
102
+ Historical validation on 2026-10-11 used Bun 1.4.2 on Windows x64 and a disposable Redis 7.4.11 container:
103
+
104
+ - `bun install --frozen-lockfile --ignore-scripts`: succeeded without lock changes.
105
+ - `bun run engine:test`: 76 passing tests across four files, 279 assertions.
106
+ - `bun scripts/ci.ts` with `RILO_TEST_REDIS_URL`: 2,361 passing tests across 226 files, 4,943 assertions, zero failures and zero skipped tests.
107
+ - The same CI run passed type checking, the lint and formatting checks configured at the time, the existing offline framework example, the engine offline example and `bun run smoke`.
108
+ - The smoke test packed and installed the package in a temporary consumer, audited public exports/notices, loaded a framework command and ran the native engine connect/reply/resume example.
109
+
110
+ Engine coverage comprises 14 cache tests, 11 client/event/helper tests, 28 gateway/protocol/identify tests and 23 REST tests. They exercise partial/null updates, resident identity, LRU boundaries and recency, deletion ordering, concurrent handlers, fetch/delete races, heartbeat debt, disconnect/resume/session invalidation, malformed/premature frames, stale sockets, cleanup, rate limits, bounded retries, cancellation and request limits.
111
+
112
+ The live example was checked without `--live`. No real Discord token was retrieved and no live bot connection or Discord message was sent.
113
+
114
+ ## Protocol and architectural references
115
+
116
+ Reviewed on 2026-10-11:
117
+
118
+ - [Gateway lifecycle](https://docs.discord.com/developers/events/gateway): discovery, HELLO, heartbeat/ACK, identify, resume URLs, sequences and session budgets.
119
+ - [Gateway events](https://docs.discord.com/developers/events/gateway-events) and [close codes](https://docs.discord.com/developers/topics/opcodes-and-status-codes): payloads and recoverable/fatal closures.
120
+ - [Rate limits](https://docs.discord.com/developers/topics/rate-limits): bucket hashes, major resources, fractional resets and global 429 handling.
121
+ - [Message resource](https://docs.discord.com/developers/resources/message) and [interaction responses](https://docs.discord.com/developers/interactions/receiving-and-responding): native body fields and callback endpoints.
122
+ - [discord-api-types 0.38.56](https://github.com/discordjs/discord-api-types/releases/tag/0.38.56): checked against public npm latest and pinned exactly in package.json and bun.lock.
123
+
124
+ `$MessageUpdateData` conservatively permits omitted native update fields with Partial plus required id/channel_id. Version 0.38.56 declares the create fields required for updates. This engine retains the agreed partial-update contract without renaming or reinterpreting fields.
125
+
126
+ The Ovencord checkout was read only. Package boundaries, WebSocketShard/identify strategies, REST SequentialHandler's bucket/major/global separation, and CachedManager's resident patching boundary informed the review. Its source, Collection abstraction, compatibility API and benchmark claims were not copied. Rilo uses its own Map/Set stores, scheduler, lifecycle and helpers.
127
+
128
+ ## Production gaps
129
+
130
+ - A real bot session needs explicit approval. Extended reconnect soak tests and large real guild payloads remain untested; this milestone uses deterministic mocks and local servers.
131
+ - One shard per client is supported. The local identify budget cannot account for other processes or persist session starts across restarts. Supply waitForIdentify when sharing a token and integrate the existing Rilo coordinator.
132
+ - Add full payload validation and broader cache projections. Reaction counts, user updates across every guild, thread membership and ancillary guild collections still need reconciliation. This is not complete Discord cache coverage.
133
+ - Add compression, multipart uploads, additional typed endpoints, proactive global pacing, route-specific sublimits, retry telemetry and deadline-aware prioritization. Different routes can be coalesced only after headers reveal their shared bucket.
134
+ - Interaction callbacks share the bounded REST scheduler. Respond or defer promptly to meet Discord's initial-response deadline; automatic deferral, follow-up helpers and deadline reservation remain future work.
135
+ - Profile real traces before changing policy. Activity traversal, cache misses and JSON parsing need realistic workload evaluation.
136
+
137
+ ## Future Rilo integration
138
+
139
+ 1. Introduce engine-facing command/listener contexts using native payloads and thin helpers, then test adapters for current framework contracts.
140
+ 2. Replace discord.js-specific permission, resolver, collector, pagination and registration dependencies at explicit boundaries without building a compatibility clone.
141
+ 3. Wire ShardLink.waitForIdentify, shard readiness and cleanup into EngineClient's injected permits and state hooks.
142
+ 4. Port extensions and example bots with contract tests before changing RiloClient's runtime and retiring discord.js dependencies.
143
+
144
+ The independent subpath is deliberate. The root API baseline stays intact, and a test verifies that this engine and the existing offline RiloClient coexist without changing the framework container.
@@ -0,0 +1,163 @@
1
+ # Shard maintenance, leases and recovery
2
+
3
+ Each shard runs in its own Bun OS process. A `ShardManager` supervises its local
4
+ children and proxies their authenticated coordinator traffic. A child receives
5
+ only its own assignment and total count: no peer list, peer connections or
6
+ dependency on another shard's arrival. Coordination is entirely in memory.
7
+ There are no ownership files, state directories or persistent locks.
8
+
9
+ Fixed shard totals remain the default. Opt-in [automatic scaling](sharding-scaling.md)
10
+ retains its five-minute polling, three matching decisions and thirty-minute
11
+ cooldown defaults.
12
+
13
+ ## Maintenance and bounded calls
14
+
15
+ A managed client starts with `client.maintenance === true`. A detected coordinator
16
+ connection loss immediately sets it back to `true` and keeps the existing Discord
17
+ session open. Socket closure is detected directly; a silent partition uses the
18
+ existing fifteen-second heartbeat deadline. Parent/child IPC heartbeats continue
19
+ through coordinator outages. Unmanaged clients default to `maintenance = false`.
20
+
21
+ Only authenticated control, an accepted lease, local assignment application and
22
+ coordinator registration clear maintenance. Opening a socket or receiving a
23
+ welcome is insufficient. Rilo does not install a command policy or send outage
24
+ replies: developers choose the response appropriate to each operation.
25
+
26
+ ```ts
27
+ if (client.maintenance) {
28
+ return interaction.reply(
29
+ "Coordination is temporarily unavailable. Try again shortly.",
30
+ );
31
+ }
32
+ ```
33
+
34
+ Ordinary requests fail with `DISCONNECTED` while the local assignment is
35
+ unreconciled. Each request or broadcast can opt into bounded waiting:
36
+
37
+ ```ts
38
+ const result = await client.sharding.request(0, "exampleStats", null, {
39
+ waitForCoordinator: true,
40
+ timeoutMs: 5000,
41
+ signal: controller.signal,
42
+ });
43
+ ```
44
+
45
+ The timeout includes waiting and execution; broadcasts share one overall deadline
46
+ across all targets. The default is `limits.timeoutMs` (15 seconds). Waits are
47
+ bounded by `limits.maxPending`, respect cancellation and return `TIMEOUT` or
48
+ `CAPACITY` instead of building an unlimited queue. Already dispatched calls fail
49
+ on disconnect and are never replayed. Waiting does not guarantee a destination
50
+ is available: routing can still return `UNAVAILABLE`, or `RESHARDING` during an
51
+ automatic scaling drain. Host manager calls support the same options.
52
+
53
+ Discord IDENTIFY still requires a coordinator permit. Control loss during a
54
+ permit wait waits for reconciliation within the shard's outage lifetime;
55
+ permit queue deadlines and exhausted allowance remain explicit failures.
56
+ An existing Discord session does not authorize new IDENTIFY calls offline.
57
+
58
+ ## Leases and dormant processes
59
+
60
+ The coordinator maintains slots `0..shardCount - 1`. `workers[].shards` provide
61
+ initial placement preferences; leases determine actual ownership. `maxShards`
62
+ bounds new allocations per host, defaulting to its initial preference count
63
+ in fixed mode. Valid returning IDs are retained even if the host's configured
64
+ capacity was reduced during the outage. Allocation and lease installation are atomic, authenticated by
65
+ host credentials, supervisor instance and child generation. Duplicate sockets
66
+ for the same supervisor instance are refused. Different authenticated instances
67
+ can connect independently to reconcile their children or wait dormant.
68
+
69
+ A new/restarted process must obtain a valid assignment before opening Discord.
70
+ A returning process reports its previous ID. If valid and free, or already
71
+ reserved for that exact process, it keeps that ID. An invalid or taken ID is
72
+ refused: the child closes any old Discord session, forgets its ID
73
+ (`client.sharding.id === null`), warns clearly and becomes dormant. New processes
74
+ without capacity behave the same way.
75
+
76
+ Dormant children stay alive indefinitely with no Discord connection. They request
77
+ an assignment every `assignmentPollIntervalMs` (default 30,000), and open Discord
78
+ only after acceptance. Repeated full-capacity polls do not repeat the warning.
79
+ `client.login()` and transport-only `client.sharding.connect()` intentionally wait
80
+ for the first assignment. Ordinary coordinator RPC calls retain deadlines.
81
+
82
+ The host normally starts one child per initial placement. Optional `processCount`
83
+ sets a minimum local pool, including standby processes, within host capacity.
84
+ Scaling may require more children up to that capacity. Surviving processes are
85
+ reconciled independently, including IDs removed by a restarted coordinator.
86
+
87
+ `manager.processes` exposes a stable local `slot`, nullable leased `shard`, PID,
88
+ restart count and state. States include `maintenance` and `dormant`, alongside
89
+ `starting`, `running`, `backoff`, `failed` and `stopped`. Local slots are not
90
+ Discord shard IDs. Dormant clients remain in maintenance.
91
+
92
+ ## Gateway changes and process lifetime
93
+
94
+ Recovery with the same ID and total preserves the Discord session. If the total
95
+ changed, the child closes its old gateway and reconnects with the accepted ID
96
+ and current total, even when the numerical ID is unchanged. RiloClient, modules
97
+ and application listeners stay alive. Assignment changes reset gateway resume
98
+ data and guild/channel/user caches. Extension login hooks run once per client;
99
+ Discord ready events may repeat. The gateway adapter targets discord.js 14.
100
+
101
+ A lost connection never releases a lease during the current coordinator lifetime.
102
+ Network loss is not proof of death. The owning supervisor must confirm the child
103
+ exited, including after reconnect, or release it after graceful shutdown/scaling.
104
+ Only then can an idle process acquire the slot. Another instance or generation
105
+ cannot release it. Lost first-lease replies and confirmed-exit acknowledgements
106
+ can be retried without stealing or releasing a replacement's assignment.
107
+
108
+ An assigned child has `maxDisconnectedLifetimeMs` (default 900,000: fifteen
109
+ minutes) to reconnect and reconcile. Failed connections, welcomes and failed
110
+ reconciliations never reset that timer. Success resets it for a future outage.
111
+ Expiry closes down and terminates the **entire shard process**; the existing host
112
+ restart/backoff policy applies. The host also bounds a stalled child's shutdown.
113
+ Dormant processes are exempt once their old Discord session is closed.
114
+
115
+ ```ts
116
+ new ShardManager({
117
+ id: "local",
118
+ url,
119
+ token,
120
+ script,
121
+ assignmentPollIntervalMs: 30_000,
122
+ maxDisconnectedLifetimeMs: 15 * 60_000,
123
+ });
124
+ ```
125
+
126
+ Polling accepts 50..300,000 ms; the outage lifetime accepts 1..2,147,483,647 ms.
127
+ `startupTimeoutMs` separately bounds boot, lease and local gateway application.
128
+ A gateway that cannot close/reconfigure is a process failure. `shutdownTimeoutMs`
129
+ bounds graceful exit. `reconnect: false` explicitly opts out of recovery and
130
+ stops children on loss. Hosts may start before the coordinator and retry with
131
+ capped backoff; closing the manager cancels the wait.
132
+
133
+ Parent IPC loss still terminates a responsive child, since it cannot reconnect
134
+ to a dead parent. Supervise each host's whole process tree. A new supervisor
135
+ instance cannot prove the old children died merely by presenting the same host
136
+ credentials. Their leases remain reserved for that coordinator lifetime; a
137
+ coordinator restart rebuilds the pool. No PID discovery or disk cleanup occurs.
138
+
139
+ ## Coordinator restart tradeoff
140
+
141
+ Restart rebuilds zero-based slots from the currently required count (configured,
142
+ or the automatic scaling startup recommendation). Arrivals are admitted
143
+ independently, with **no global reconciliation grace period**.
144
+
145
+ An old partitioned Discord session may overlap a newly assigned replacement
146
+ until the old process reconnects or reaches its configured outage cutoff. If its
147
+ ID is taken on return, it closes Discord and becomes dormant. This policy cannot
148
+ promise zero duplicate processing or exactly-once delivery. A wedged process
149
+ needs host/service supervision to enforce termination. Run one coordinator per
150
+ bot; independent coordinators are not fenced from each other.
151
+
152
+ Use `botToken` in production. Each coordinator start waits 5.5 seconds before
153
+ fetching fresh `GET /gateway/bot` limits. This is an IDENTIFY cooldown, not a
154
+ reconciliation grace period. Permits are charged before sending and never refunded
155
+ on loss. An unexpired allowance cannot increase. `sessionStartLimit` is the
156
+ manual/offline alternative and needs a fresh snapshot on every start and expiry.
157
+ Restarting Rilo does not reset Discord's allowance.
158
+
159
+ Upgrade coordinator, hosts and children together: the internal protocol changed.
160
+ Restart running processes deliberately to load the new version. `statePath`,
161
+ `stateDirectory`, `releaseWorker`, `SHARD_STATE_PATH` and `SHARD_HOST_STATE_DIR`
162
+ remain removed. Legacy state files stay ignored and unused. See
163
+ [breaking changes](../BREAKING_CHANGES.md) and [examples](../examples/README.md).
@@ -0,0 +1,197 @@
1
+ # Automatic shard deployment
2
+
3
+ Automatic scaling is **off by default**. Without `scaling`, `shardCount` and
4
+ `workers[].shards` remain fixed and metadata is fetched only at startup or when
5
+ the identify allowance expires. Enable scaling on the coordinator; hosts run
6
+ the same `ShardManager` and bot entrypoint.
7
+
8
+ ## Coordinator configuration
9
+
10
+ ```ts
11
+ import { ShardCoordinator } from "rilo/sharding";
12
+
13
+ const coordinator = new ShardCoordinator({
14
+ shardCount: 2,
15
+ workers: [
16
+ {
17
+ id: "a",
18
+ token: process.env.HOST_A_SECRET!,
19
+ shards: [0],
20
+ maxShards: 4,
21
+ weight: 2,
22
+ },
23
+ {
24
+ id: "b",
25
+ token: process.env.HOST_B_SECRET!,
26
+ shards: [1],
27
+ maxShards: 2,
28
+ weight: 1,
29
+ },
30
+ ],
31
+ botToken: process.env.DISCORD_TOKEN!,
32
+ scaling: {
33
+ minShards: 2,
34
+ maxShards: 6,
35
+ targetGuildsPerShard: 1000,
36
+ pollIntervalMs: 300000,
37
+ cooldownMs: 1800000,
38
+ confirmations: 3,
39
+ allowDownscale: true,
40
+ rebalanceThreshold: 0.25,
41
+ sessionReserve: 10,
42
+ drainTimeoutMs: 30000,
43
+ readyTimeoutMs: 300000,
44
+ },
45
+ });
46
+ await coordinator.start();
47
+ ```
48
+
49
+ Keep credentials in your environment. Remote hosts need the normal TLS
50
+ configuration. This policy uses only configured hosts that are already running;
51
+ it never provisions machines, changes server settings or purchases capacity.
52
+ Every automatic host needs `maxShards`, including standby hosts with `shards: []`.
53
+ Initial assignments must cover `0..shardCount-1` exactly once and fit host capacity.
54
+
55
+ On startup, fresh Discord metadata, bounds and capacities determine the initial
56
+ assignment before hosts connect. `shardCount` is an initial configuration seed,
57
+ not a fixed count in automatic mode. No previous topology, guild counts,
58
+ confirmation history, cooldown or allowance is restored from disk. Set
59
+ `minShards` to retain an operational floor across coordinator restarts.
60
+
61
+ | Setting | Default | Meaning |
62
+ | ---------------------- | -------------- | ---------------------------------------------------------------------- |
63
+ | `maxShards` | Required | Global ceiling, 1–4096, also bounded by summed host capacity |
64
+ | `minShards` | `1` | Minimum total, at most `maxShards` |
65
+ | `targetGuildsPerShard` | Disabled (`0`) | Optional average target, 1–2500; requires accurate guild caches |
66
+ | `pollIntervalMs` | `300000` | Metadata polling interval, 60000–86400000 ms |
67
+ | `cooldownMs` | `1800000` | Minimum interval between transition attempts, 60000–604800000 ms |
68
+ | `confirmations` | `3` | Consecutive matching plans before a running deployment changes, 1–100 |
69
+ | `allowDownscale` | `true` | Allow fewer shards after confirmation and cooldown |
70
+ | `rebalanceThreshold` | `0.25` | Required improvement in peak weighted host guild load, 0.05–1 |
71
+ | `sessionReserve` | `0` | Unspent identify allowance to retain beyond the transition requirement |
72
+ | `drainTimeoutMs` | `30000` | Time for every host to confirm old process exits, 100–300000 ms |
73
+ | `readyTimeoutMs` | `300000` | Time for the new deployment to become gateway-ready, 100–3600000 ms |
74
+ | Host `maxShards` | Required | Maximum shard processes on this host, 1–4096 |
75
+ | Host `weight` | `1` | Relative resource capacity, 0.01–1000; set it from your host sizing |
76
+
77
+ ## What Discord controls
78
+
79
+ Discord does not send a push event requesting a particular scale-up or
80
+ scale-down. The coordinator polls `GET /gateway/bot` for the recommended shard
81
+ count and fresh session-start metadata. Discord assigns guilds by
82
+ `(guild_id >> 22) % num_shards`; the framework cannot choose individual guilds or
83
+ move one guild to another shard independently. See the official
84
+ [Gateway sharding and session-start documentation](https://docs.discord.com/developers/events/gateway#sharding).
85
+
86
+ The desired count is the maximum of the recommendation, configured minimum and
87
+ `ceil(totalCachedGuilds / targetGuildsPerShard)` when that target is enabled.
88
+ Counts round up to multiples of the current recommendation, a conservative
89
+ choice compatible with Discord's large-bot shard-count multiple requirement.
90
+ This can overprovision compared with using arbitrary shard totals. The largest
91
+ legal count within configured capacity is used if the guild target cannot fit;
92
+ a recommendation or minimum that cannot fit blocks the change with
93
+ `SCALING_CAPACITY`. The recommendation is a floor, not an automatic instruction
94
+ to remove a particular existing shard.
95
+
96
+ Guild targets are averages, not a guarantee that every shard has that many
97
+ guilds. Discord's per-shard limit still applies. Uneven guild sizes, unavailable
98
+ guilds and custom caches affect the usefulness of guild counts. Keep the Guilds
99
+ intent and a complete guild cache if using guild targets. This is not CPU,
100
+ memory, member-count or event-volume monitoring.
101
+
102
+ For an unchanged total, allocation greedily places entire shards using observed
103
+ guild counts and host weights, while respecting per-host process limits.
104
+ Existing owners win equal-load ties. An allocation-only change requires the
105
+ configured improvement in peak weighted load. For a new total, individual shard
106
+ guild counts are unknown until login, so allocation uses equal estimated loads.
107
+ A later poll can rebalance hosts if the measured distribution warrants it.
108
+
109
+ ## Transition and recovery
110
+
111
+ 1. Fetch fresh metadata and apply the existing conservative identify accounting.
112
+ All configured hosts must be connected, including standby hosts. Shrinking,
113
+ guild-target changes and allocation-only balancing require every shard to
114
+ report gateway readiness and metrics no older than 15 seconds. A larger
115
+ Discord recommendation may grow an unready topology to repair insufficient
116
+ sharding. A degraded committed deployment must recover before another change.
117
+ 2. Require repeated matching plans and the cooldown. Before disrupting children,
118
+ require unexpired remaining session starts of at least
119
+ `max(currentCount, proposedCount) + sessionReserve`. The larger count covers
120
+ either deployment or a pre-commit rollback. Insufficient budget defers the
121
+ change without stopping healthy children.
122
+ 3. Reject pending/new shard RPC and identify work with `RESHARDING`. Ask all hosts
123
+ to drain. Each host cancels scheduled restarts, requests graceful shutdown,
124
+ escalates only its own children if necessary, and confirms actual process
125
+ exits. This interrupts bot availability and cancels in-flight work; application
126
+ jobs must tolerate restarts. Even allocation-only changes restart all shards.
127
+ 4. If a host disconnects or draining times out before commit, retain the old
128
+ total and assignment. Still-connected hosts receive that assignment after
129
+ their drains finish; reconnecting hosts receive it in their welcome. An
130
+ unconfirmed child exit cannot authorize a replacement.
131
+ 5. Once every old process is confirmed stopped, commit the new count and
132
+ assignment in memory and start fresh children. After this point recovery
133
+ moves forward: reconnecting hosts receive the committed topology. There is
134
+ no rollback to a different total while new children are running.
135
+ 6. Wait for gateway readiness. Failed startup/readiness leaves status
136
+ `degraded`; ordinary configured process retries and host reconnection continue.
137
+ Once all shards recover, status becomes `idle` automatically. Exhausted
138
+ restart attempts, disabled restart, or application errors require correction
139
+ and replacement/restart of the affected supervisor. No state-file cleanup is
140
+ required.
141
+
142
+ Every IDENTIFY still uses the central `shardId % max_concurrency` bucket and
143
+ 5.5-second cooldown. Permits are charged before delivery and never refunded.
144
+ Fresh metadata cannot increase an unexpired in-memory allowance. RESUME remains
145
+ discord.js behavior; this feature does not bypass Discord rate limits or alter
146
+ retry policy. Crashes during startup can consume additional session starts and
147
+ leave the deployment waiting for a fresh allowance. Choose host
148
+ `identifyTimeoutMs` and coordinator `readyTimeoutMs` for your total, concurrency,
149
+ startup time and possible retries; a large serial deployment can exceed defaults.
150
+
151
+ Automatic totals must also fit `limits.maxPending` (default 256) so the control
152
+ plane has room for startup identifies. Welcome and assignment frames must fit
153
+ `limits.maxBytes`; these checks happen before draining. Increase these bounded
154
+ limits deliberately when sizing a larger deployment. Host `identifyTimeoutMs`
155
+ is capped at 300000 ms. If the serial login queue cannot fit that deadline with
156
+ the bot's Discord concurrency, this deployment model cannot start the whole
157
+ topology reliably; more machines do not increase Discord concurrency.
158
+
159
+ Closing the coordinator aborts metadata requests and transition waits, closes
160
+ connections, and cancels polling. Surviving children keep Discord open in
161
+ maintenance while their hosts reconnect and reconcile individual leases. A
162
+ changed total closes the old gateway before a new session opens, even for the
163
+ same ID. Rejected IDs become dormant. Explicit scaling transitions still confirm
164
+ child exits and release leases before committing the new topology; reservations
165
+ belonging to disconnected instances block that transition.
166
+
167
+ The [process lifetime limitations](sharding-recovery.md) still apply: run one
168
+ coordinator per bot and supervise host process trees. There is no global grace
169
+ period on coordinator restart. A partitioned old Discord session can overlap a
170
+ replacement until it reconnects or reaches the configured outage cutoff.
171
+
172
+ ## Observability and compatibility
173
+
174
+ `coordinator.shardCount` exposes the current committed total.
175
+ `coordinator.scalingStatus` is a copied snapshot with `phase`
176
+ (`disabled`, `idle`, `draining`, `starting` or `degraded`), `shardCount`, and optional
177
+ `reason`/`targetShards`. `await coordinator.checkScaling()` requests one immediate
178
+ evaluation; simultaneous calls share one promise and still respect confirmation,
179
+ cooldown, readiness and allowance checks. Periodic checks continue automatically.
180
+
181
+ Structured logs emit `scaling_status`, `scaling_failed` and host `reassigned`
182
+ events. Ordinary waiting/stable reasons are logged only when status changes.
183
+ Use `RILO_LOG_FORMAT=json` for full context. Logs contain counts and host IDs,
184
+ not guild IDs, tokens or application payloads.
185
+
186
+ Upgrade coordinator, hosts and children together. The internal transport adds
187
+ drain, assignment and bounded metrics frames; mixed framework versions are not
188
+ supported. Metrics distinguish IPC boot from actual gateway readiness.
189
+ Public logger customization, fixed totals and existing message APIs remain
190
+ available. Initial host placements are preferences; per-process leases control
191
+ ownership. In automatic mode, callers must tolerate `RESHARDING` and total-count
192
+ changes during requests/broadcasts. No ownership database, directory or lock is
193
+ introduced.
194
+
195
+ See [the runnable example configuration](../examples/README.md#automatic-scaling).
196
+ Regression tests use synthetic gateway metadata and real local Bun processes;
197
+ they never log in to Discord.
@@ -0,0 +1,121 @@
1
+ # Live shard statistics
2
+
3
+ Use `this.container.sharding.stats()` inside a command, listener or service to ask
4
+ every configured shard for its current stats. `client.sharding.stats()` and
5
+ `manager.stats()` provide the same API. No application handler registration is needed.
6
+
7
+ ```ts
8
+ const results = await this.container.sharding.stats();
9
+ for (const [shard, result] of results) {
10
+ if (result.ok) {
11
+ this.container.logger.notif(
12
+ `Shard ${shard}: ${result.value.guilds} cached guilds`,
13
+ );
14
+ } else {
15
+ this.container.logger.alert(`Shard ${shard}: ${result.error.code}`);
16
+ }
17
+ }
18
+
19
+ // A specific shard still returns a map, with exactly one entry.
20
+ const one = await this.container.sharding.stats(0, { timeoutMs: 5000 });
21
+ const shardZero = one.get(0);
22
+ ```
23
+
24
+ The return type is `Promise<ReadonlyMap<number, ShardStatsResult>>`. Import
25
+ `ShardStats`, `ShardStatsResult` and `ShardCallOptions` from `rilo` or
26
+ `rilo/sharding`. Entries follow the existing request result shape: `{ shard,
27
+ ok: true, value }` or `{ shard, ok: false, error }`. Errors are frozen `ShardError`
28
+ copies with a `code` and `message`; a failed entry has no `value` property.
29
+
30
+ ## Freshness and scope
31
+
32
+ Every call makes new requests through the coordinator, including a request to
33
+ the caller's own shard. The destination reads its client and process state only
34
+ when that request arrives. Stats never use the coordinator's periodic scaling
35
+ metrics, an earlier successful result, or a local shortcut as a fallback.
36
+ The private request name `rilo:stats` is reserved and cannot be registered with
37
+ `handle()`.
38
+
39
+ Without an ID, the target set is `0..shardCount - 1` from the caller's reconciled
40
+ assignment when collection begins. It includes unavailable IDs. Passing an ID
41
+ selects only that shard; an invalid or out-of-range ID rejects with `TARGET`.
42
+ Dormant process slots are not shard IDs. A topology change during collection can
43
+ produce failures; call again after reconciliation to sample the new topology.
44
+
45
+ Samples are fresh observations, not a simultaneous cross-process snapshot. State
46
+ can change after a shard replies. `sampledAt` is Unix milliseconds on that shard's
47
+ clock, so differences between hosts can include clock skew. Successful entries
48
+ remain useful even when other shards fail; totals computed from them are partial.
49
+
50
+ The returned map has the read methods and iteration behavior of `ReadonlyMap`,
51
+ with no `set`, `delete` or `clear` methods. The map, entries, samples, nested memory
52
+ objects and errors are frozen. They are detached from live internals and will
53
+ not change after you receive them. The read-only map is a view over private
54
+ storage, not a mutable JavaScript `Map` instance. It is iterable; use
55
+ `[...results]` when you need an array. JSON serialization of errors should copy
56
+ their `code` and `message` explicitly.
57
+
58
+ ## Deadlines and failures
59
+
60
+ The optional second argument accepts the usual `ShardCallOptions`:
61
+
62
+ ```ts
63
+ const results = await client.sharding.stats(undefined, {
64
+ timeoutMs: 5000,
65
+ waitForCoordinator: true,
66
+ signal: controller.signal,
67
+ });
68
+ ```
69
+
70
+ One deadline covers coordinator waiting and the whole collection, including
71
+ queued targets. It defaults to the coordinator's `limits.timeoutMs` (15 seconds),
72
+ and accepts 1..300000 milliseconds. At most eight requests are in flight for one
73
+ collection, also subject to the existing client, host and coordinator pending
74
+ limits. A target still queued when the budget runs out receives `TIMEOUT`
75
+ without being dispatched. Late replies are ignored and never update a completed
76
+ map. A reply received after the budget expires is a timeout, even if it has metrics.
77
+
78
+ Before collection starts, invalid options or a locally unavailable coordinator
79
+ reject the promise. By default, maintenance and unmanaged clients reject with
80
+ `DISCONNECTED`; a closed client or host rejects with `CLOSED`. Opting into
81
+ `waitForCoordinator` waits within the same deadline and can reject with `TIMEOUT`,
82
+ `CAPACITY` or the supplied abort signal's reason. No local or cached stats are
83
+ returned while waiting. A connected host can still have children reconciling;
84
+ those destinations remain unavailable until their registration completes.
85
+
86
+ Once collection starts, failures become individual map entries:
87
+
88
+ | Code | What happened |
89
+ | -------------- | ------------------------------------------------------------------------ |
90
+ | `UNAVAILABLE` | The shard has no ready route, has exited, or has no stats provider. |
91
+ | `TIMEOUT` | The overall budget ran out before a usable reply arrived. |
92
+ | `DISCONNECTED` | A required coordinator or host connection was lost. |
93
+ | `CAPACITY` | A client, host, coordinator or destination handler limit was reached. |
94
+ | `RESHARDING` | The deployment is draining for a topology change. |
95
+ | `ABORTED` | The caller cancelled collection. Already completed entries are retained. |
96
+ | `PROTOCOL` | A responding shard returned a malformed stats sample. |
97
+ | `HANDLER` | The destination's sampler threw an error. |
98
+
99
+ Other transport error codes can also appear. Failed entries contain no metrics:
100
+ an unavailable shard does not mean zero guilds, zero memory or a disconnected
101
+ Discord session. Calls already sent are never replayed after reconnection.
102
+ Collection does not change leases, maintenance, gateway sessions or dormant
103
+ process behavior. See [maintenance and recovery](sharding-recovery.md).
104
+
105
+ ## Sample fields
106
+
107
+ | Field | Meaning |
108
+ | ----------------------------- | ---------------------------------------------------------------------------------------------------------------- |
109
+ | `sampledAt` | Shard wall-clock sampling time, in Unix milliseconds. |
110
+ | `ready` | Whether the shard's Discord client is ready right now. |
111
+ | `guilds`, `users`, `channels` | Current local cache sizes. Users may appear on multiple shards. |
112
+ | `pingMs` | Most recent gateway heartbeat latency, or `null` before a measurement exists. This doesn't send a new heartbeat. |
113
+ | `uptimeMs` | Milliseconds since the client last became ready, or `null` while it isn't ready. |
114
+ | `pid` | Process ID on that shard's host. |
115
+ | `processUptimeMs` | Milliseconds since the Bun process started. |
116
+ | `memory` | Process memory usage in bytes: `rss`, `heapTotal`, `heapUsed`, `external`, `arrayBuffers`. These values overlap. |
117
+
118
+ Cache counts depend on intents, cache configuration and received events; they
119
+ aren't a fresh Discord REST census. A process can answer stats while its Discord
120
+ client is not ready. That is a successful sample with `ready: false`, distinct
121
+ from a shard that cannot answer at all.