chapterjs 0.1.2 → 0.2.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 (318) hide show
  1. package/dist/assets/asset.d.ts +46 -0
  2. package/dist/assets/asset.js +86 -0
  3. package/dist/assets/public.d.ts +19 -0
  4. package/dist/assets/public.js +120 -0
  5. package/dist/cache/cache.d.ts +62 -0
  6. package/dist/cache/cache.js +80 -0
  7. package/dist/cache/store.d.ts +45 -0
  8. package/dist/cache/store.js +53 -0
  9. package/dist/cli/build.d.ts +41 -0
  10. package/dist/cli/build.js +205 -0
  11. package/dist/cli/cli.js +108 -25
  12. package/dist/cli/cluster.d.ts +70 -0
  13. package/dist/cli/cluster.js +213 -0
  14. package/dist/cli/dev.d.ts +18 -1
  15. package/dist/cli/dev.js +253 -198
  16. package/dist/cli/env.d.ts +31 -0
  17. package/dist/cli/env.js +93 -0
  18. package/dist/cli/log.d.ts +13 -0
  19. package/dist/cli/log.js +17 -0
  20. package/dist/cli/node-version.d.ts +8 -0
  21. package/dist/cli/node-version.js +13 -0
  22. package/dist/cli/preflight.d.ts +36 -0
  23. package/dist/cli/preflight.js +122 -0
  24. package/dist/cli/project.d.ts +135 -0
  25. package/dist/cli/project.js +517 -0
  26. package/dist/cli/start.d.ts +25 -0
  27. package/dist/cli/start.js +225 -0
  28. package/dist/commands/autocomplete.d.ts +13 -0
  29. package/dist/commands/autocomplete.js +159 -0
  30. package/dist/commands/command.d.ts +360 -0
  31. package/dist/commands/command.js +28 -0
  32. package/dist/commands/declaration.d.ts +77 -0
  33. package/dist/commands/declaration.js +492 -0
  34. package/dist/commands/register.d.ts +18 -0
  35. package/dist/commands/register.js +42 -0
  36. package/dist/commands/router.d.ts +20 -0
  37. package/dist/commands/router.js +228 -0
  38. package/dist/commands/tree.d.ts +47 -0
  39. package/dist/commands/tree.js +216 -0
  40. package/dist/commands/twins.d.ts +15 -0
  41. package/dist/commands/twins.js +78 -0
  42. package/dist/components/button.d.ts +79 -0
  43. package/dist/components/button.js +106 -0
  44. package/dist/components/component.d.ts +140 -0
  45. package/dist/components/component.js +39 -0
  46. package/dist/components/custom-id.d.ts +72 -0
  47. package/dist/components/custom-id.js +128 -0
  48. package/dist/components/declaration.d.ts +42 -0
  49. package/dist/components/declaration.js +342 -0
  50. package/dist/components/declared.d.ts +29 -0
  51. package/dist/components/declared.js +49 -0
  52. package/dist/components/embed.d.ts +29 -0
  53. package/dist/components/embed.js +11 -0
  54. package/dist/components/instance.d.ts +100 -0
  55. package/dist/components/instance.js +86 -0
  56. package/dist/components/layout.d.ts +103 -0
  57. package/dist/components/layout.js +279 -0
  58. package/dist/components/modal.d.ts +245 -0
  59. package/dist/components/modal.js +398 -0
  60. package/dist/components/options.d.ts +41 -0
  61. package/dist/components/options.js +101 -0
  62. package/dist/components/render.d.ts +12 -0
  63. package/dist/components/render.js +58 -0
  64. package/dist/components/router.d.ts +19 -0
  65. package/dist/components/router.js +251 -0
  66. package/dist/components/select.d.ts +146 -0
  67. package/dist/components/select.js +179 -0
  68. package/dist/core/bot.d.ts +99 -0
  69. package/dist/core/bot.js +174 -0
  70. package/dist/core/memory.d.ts +66 -0
  71. package/dist/core/memory.js +115 -0
  72. package/dist/discord/api.d.ts +112 -0
  73. package/dist/discord/api.js +115 -0
  74. package/dist/discord/cdn.d.ts +67 -0
  75. package/dist/discord/cdn.js +100 -0
  76. package/dist/discord/codes.d.ts +171 -0
  77. package/dist/discord/codes.js +421 -0
  78. package/dist/discord/endpoint.d.ts +56 -0
  79. package/dist/discord/endpoint.js +53 -0
  80. package/dist/discord/endpoints.d.ts +1529 -0
  81. package/dist/discord/endpoints.js +1139 -0
  82. package/dist/discord/formatting.d.ts +67 -0
  83. package/dist/discord/formatting.js +87 -0
  84. package/dist/discord/index.d.ts +10 -0
  85. package/dist/discord/index.js +13 -0
  86. package/dist/discord/intents.d.ts +48 -0
  87. package/dist/discord/intents.js +128 -0
  88. package/dist/discord/permissions.d.ts +94 -0
  89. package/dist/discord/permissions.js +185 -0
  90. package/dist/discord/snowflake.d.ts +21 -0
  91. package/dist/discord/snowflake.js +36 -0
  92. package/dist/discord/types/application-command.d.ts +332 -0
  93. package/dist/discord/types/application-command.js +48 -0
  94. package/dist/discord/types/application-role-connection-metadata.d.ts +42 -0
  95. package/dist/discord/types/application-role-connection-metadata.js +22 -0
  96. package/dist/discord/types/application.d.ts +208 -0
  97. package/dist/discord/types/application.js +48 -0
  98. package/dist/discord/types/audit-log.d.ts +255 -0
  99. package/dist/discord/types/audit-log.js +144 -0
  100. package/dist/discord/types/auto-moderation.d.ts +167 -0
  101. package/dist/discord/types/auto-moderation.js +52 -0
  102. package/dist/discord/types/channel.d.ts +557 -0
  103. package/dist/discord/types/channel.js +88 -0
  104. package/dist/discord/types/common.d.ts +54 -0
  105. package/dist/discord/types/common.js +38 -0
  106. package/dist/discord/types/component.d.ts +775 -0
  107. package/dist/discord/types/component.js +76 -0
  108. package/dist/discord/types/emoji.d.ts +74 -0
  109. package/dist/discord/types/emoji.js +1 -0
  110. package/dist/discord/types/entitlement.d.ts +84 -0
  111. package/dist/discord/types/entitlement.js +22 -0
  112. package/dist/discord/types/gateway-events.d.ts +1148 -0
  113. package/dist/discord/types/gateway-events.js +54 -0
  114. package/dist/discord/types/gateway.d.ts +38 -0
  115. package/dist/discord/types/gateway.js +1 -0
  116. package/dist/discord/types/guild-scheduled-event.d.ts +257 -0
  117. package/dist/discord/types/guild-scheduled-event.js +68 -0
  118. package/dist/discord/types/guild-template.d.ts +51 -0
  119. package/dist/discord/types/guild-template.js +1 -0
  120. package/dist/discord/types/guild.d.ts +910 -0
  121. package/dist/discord/types/guild.js +153 -0
  122. package/dist/discord/types/index.d.ts +31 -0
  123. package/dist/discord/types/index.js +31 -0
  124. package/dist/discord/types/interaction.d.ts +321 -0
  125. package/dist/discord/types/interaction.js +47 -0
  126. package/dist/discord/types/invite.d.ts +158 -0
  127. package/dist/discord/types/invite.js +39 -0
  128. package/dist/discord/types/message.d.ts +834 -0
  129. package/dist/discord/types/message.js +159 -0
  130. package/dist/discord/types/oauth2.d.ts +22 -0
  131. package/dist/discord/types/oauth2.js +1 -0
  132. package/dist/discord/types/permissions.d.ts +183 -0
  133. package/dist/discord/types/permissions.js +118 -0
  134. package/dist/discord/types/poll.d.ts +106 -0
  135. package/dist/discord/types/poll.js +8 -0
  136. package/dist/discord/types/sku.d.ts +47 -0
  137. package/dist/discord/types/sku.js +26 -0
  138. package/dist/discord/types/soundboard.d.ts +71 -0
  139. package/dist/discord/types/soundboard.js +1 -0
  140. package/dist/discord/types/stage-instance.d.ts +58 -0
  141. package/dist/discord/types/stage-instance.js +10 -0
  142. package/dist/discord/types/sticker.d.ts +115 -0
  143. package/dist/discord/types/sticker.js +20 -0
  144. package/dist/discord/types/subscription.d.ts +54 -0
  145. package/dist/discord/types/subscription.js +12 -0
  146. package/dist/discord/types/team.d.ts +55 -0
  147. package/dist/discord/types/team.js +21 -0
  148. package/dist/discord/types/user.d.ts +273 -0
  149. package/dist/discord/types/user.js +83 -0
  150. package/dist/discord/types/voice.d.ts +72 -0
  151. package/dist/discord/types/voice.js +1 -0
  152. package/dist/discord/types/webhook.d.ts +184 -0
  153. package/dist/discord/types/webhook.js +12 -0
  154. package/dist/events/declaration.d.ts +16 -0
  155. package/dist/events/declaration.js +80 -0
  156. package/dist/events/event.d.ts +45 -0
  157. package/dist/events/event.js +34 -0
  158. package/dist/events/registry.d.ts +697 -0
  159. package/dist/events/registry.js +839 -0
  160. package/dist/events/router.d.ts +46 -0
  161. package/dist/events/router.js +133 -0
  162. package/dist/gateway/errors.d.ts +18 -0
  163. package/dist/gateway/errors.js +47 -0
  164. package/dist/gateway/gateway.d.ts +64 -0
  165. package/dist/gateway/gateway.js +117 -0
  166. package/dist/gateway/identify-queue.d.ts +25 -0
  167. package/dist/gateway/identify-queue.js +29 -0
  168. package/dist/gateway/shard.d.ts +94 -0
  169. package/dist/gateway/shard.js +414 -0
  170. package/dist/gateway/state.d.ts +11 -0
  171. package/dist/gateway/state.js +184 -0
  172. package/dist/index.d.ts +57 -18
  173. package/dist/index.js +40 -12
  174. package/dist/interactions/cooldown.d.ts +33 -0
  175. package/dist/interactions/cooldown.js +74 -0
  176. package/dist/interactions/dispatch.d.ts +91 -0
  177. package/dist/interactions/dispatch.js +110 -0
  178. package/dist/loader/generated.d.ts +10 -0
  179. package/dist/loader/generated.js +80 -0
  180. package/dist/loader/hot.d.ts +13 -0
  181. package/dist/loader/hot.js +85 -0
  182. package/dist/loader/loader.d.ts +85 -0
  183. package/dist/loader/loader.js +119 -0
  184. package/dist/loader/locate.d.ts +10 -0
  185. package/dist/loader/locate.js +36 -0
  186. package/dist/loader/watch.d.ts +17 -0
  187. package/dist/loader/watch.js +66 -0
  188. package/dist/main.d.ts +2 -0
  189. package/dist/main.js +5 -0
  190. package/dist/messages/commands.d.ts +23 -0
  191. package/dist/messages/commands.js +142 -0
  192. package/dist/messages/declaration.d.ts +89 -0
  193. package/dist/messages/declaration.js +455 -0
  194. package/dist/messages/messages.d.ts +241 -0
  195. package/dist/messages/messages.js +31 -0
  196. package/dist/messages/phrases.d.ts +23 -0
  197. package/dist/messages/phrases.js +44 -0
  198. package/dist/messages/translate.d.ts +100 -0
  199. package/dist/messages/translate.js +249 -0
  200. package/dist/presence/declaration.d.ts +19 -0
  201. package/dist/presence/declaration.js +118 -0
  202. package/dist/presence/presence.d.ts +57 -0
  203. package/dist/presence/presence.js +27 -0
  204. package/dist/rest/errors.d.ts +55 -0
  205. package/dist/rest/errors.js +92 -0
  206. package/dist/rest/rate-limiter.d.ts +46 -0
  207. package/dist/rest/rate-limiter.js +153 -0
  208. package/dist/rest/rest.d.ts +63 -0
  209. package/dist/rest/rest.js +194 -0
  210. package/dist/structures/base.d.ts +48 -0
  211. package/dist/structures/base.js +84 -0
  212. package/dist/structures/channel.d.ts +380 -0
  213. package/dist/structures/channel.js +627 -0
  214. package/dist/structures/context.d.ts +30 -0
  215. package/dist/structures/context.js +7 -0
  216. package/dist/structures/emoji.d.ts +46 -0
  217. package/dist/structures/emoji.js +65 -0
  218. package/dist/structures/entities.d.ts +62 -0
  219. package/dist/structures/entities.js +226 -0
  220. package/dist/structures/guild.d.ts +348 -0
  221. package/dist/structures/guild.js +466 -0
  222. package/dist/structures/interaction.d.ts +197 -0
  223. package/dist/structures/interaction.js +396 -0
  224. package/dist/structures/invite.d.ts +38 -0
  225. package/dist/structures/invite.js +57 -0
  226. package/dist/structures/known.d.ts +28 -0
  227. package/dist/structures/known.js +58 -0
  228. package/dist/structures/member.d.ts +140 -0
  229. package/dist/structures/member.js +260 -0
  230. package/dist/structures/message.d.ts +197 -0
  231. package/dist/structures/message.js +268 -0
  232. package/dist/structures/payload.d.ts +91 -0
  233. package/dist/structures/payload.js +184 -0
  234. package/dist/structures/role.d.ts +69 -0
  235. package/dist/structures/role.js +112 -0
  236. package/dist/structures/user.d.ts +59 -0
  237. package/dist/structures/user.js +94 -0
  238. package/dist/structures/webhook.d.ts +46 -0
  239. package/dist/structures/webhook.js +79 -0
  240. package/dist/tasks/declaration.d.ts +16 -0
  241. package/dist/tasks/declaration.js +56 -0
  242. package/dist/tasks/schedule.d.ts +54 -0
  243. package/dist/tasks/schedule.js +236 -0
  244. package/dist/tasks/scheduler.d.ts +35 -0
  245. package/dist/tasks/scheduler.js +107 -0
  246. package/dist/tasks/task.d.ts +75 -0
  247. package/dist/tasks/task.js +27 -0
  248. package/dist/util/case.d.ts +13 -0
  249. package/dist/util/case.js +54 -0
  250. package/dist/util/duration.d.ts +8 -0
  251. package/dist/util/duration.js +29 -0
  252. package/dist/util/websocket.d.ts +9 -0
  253. package/dist/util/websocket.js +31 -0
  254. package/dist/voice/connection.d.ts +90 -0
  255. package/dist/voice/connection.js +494 -0
  256. package/dist/voice/dave.d.ts +109 -0
  257. package/dist/voice/dave.js +245 -0
  258. package/dist/voice/opus.d.ts +19 -0
  259. package/dist/voice/opus.js +273 -0
  260. package/dist/voice/session.d.ts +55 -0
  261. package/dist/voice/session.js +405 -0
  262. package/dist/voice/source.d.ts +22 -0
  263. package/dist/voice/source.js +195 -0
  264. package/dist/voice/transport.d.ts +43 -0
  265. package/dist/voice/transport.js +140 -0
  266. package/dist/voice/usage.d.ts +4 -0
  267. package/dist/voice/usage.js +33 -0
  268. package/package.json +26 -7
  269. package/vendor/dave/LICENSE +231 -0
  270. package/vendor/dave/libdave.d.mts +99 -0
  271. package/vendor/dave/libdave.mjs +2 -0
  272. package/vendor/dave/libdave.wasm +0 -0
  273. package/dist/components.d.ts +0 -97
  274. package/dist/components.js +0 -260
  275. package/dist/context.d.ts +0 -72
  276. package/dist/context.js +0 -273
  277. package/dist/discord/client.d.ts +0 -35
  278. package/dist/discord/client.js +0 -66
  279. package/dist/discord/constants.d.ts +0 -49
  280. package/dist/discord/constants.js +0 -61
  281. package/dist/discord/events.d.ts +0 -129
  282. package/dist/discord/events.js +0 -102
  283. package/dist/discord/gateway.d.ts +0 -61
  284. package/dist/discord/gateway.js +0 -320
  285. package/dist/discord/payloads.d.ts +0 -275
  286. package/dist/discord/payloads.js +0 -3
  287. package/dist/discord/presence.d.ts +0 -42
  288. package/dist/discord/presence.js +0 -51
  289. package/dist/discord/rest.d.ts +0 -49
  290. package/dist/discord/rest.js +0 -271
  291. package/dist/discord/types.d.ts +0 -334
  292. package/dist/discord/types.js +0 -4
  293. package/dist/events.d.ts +0 -94
  294. package/dist/events.js +0 -255
  295. package/dist/presence.d.ts +0 -92
  296. package/dist/presence.js +0 -250
  297. package/dist/structures/Channel.d.ts +0 -110
  298. package/dist/structures/Channel.js +0 -171
  299. package/dist/structures/Guild.d.ts +0 -70
  300. package/dist/structures/Guild.js +0 -105
  301. package/dist/structures/Interaction.d.ts +0 -113
  302. package/dist/structures/Interaction.js +0 -274
  303. package/dist/structures/Member.d.ts +0 -70
  304. package/dist/structures/Member.js +0 -124
  305. package/dist/structures/Message.d.ts +0 -87
  306. package/dist/structures/Message.js +0 -182
  307. package/dist/structures/Reaction.d.ts +0 -38
  308. package/dist/structures/Reaction.js +0 -64
  309. package/dist/structures/Role.d.ts +0 -43
  310. package/dist/structures/Role.js +0 -77
  311. package/dist/structures/User.d.ts +0 -41
  312. package/dist/structures/User.js +0 -79
  313. package/dist/structures/utils.d.ts +0 -72
  314. package/dist/structures/utils.js +0 -59
  315. package/dist/utils/errors.d.ts +0 -5
  316. package/dist/utils/errors.js +0 -28
  317. package/dist/utils/modules.d.ts +0 -39
  318. package/dist/utils/modules.js +0 -156
package/dist/index.d.ts CHANGED
@@ -1,18 +1,57 @@
1
- export type { Client } from './discord/client.js';
2
- export type { Activity, Presence, PresenceStatus } from './discord/presence.js';
3
- export { definePresence, refreshPresence, type PresenceContext, type PresenceDefinition, type PresenceFunction, type PresenceInput, type PresenceSourceFunction, type PresenceStep, type PresenceWatchCleanup, } from './presence.js';
4
- export type { EventData, EventName } from './discord/events.js';
5
- export type * from './discord/types.js';
6
- export type { EventContext } from './context.js';
7
- export { defineEvent, type Event, type EventDefinition, type EventHandler, type IntentName, } from './events.js';
8
- export { DiscordAPIError, type FileUpload, type RequestOptions, } from './discord/rest.js';
9
- export { Channel, ChannelType, type CreateThreadOptions, type FetchMessagesOptions, } from './structures/Channel.js';
10
- export { type BanOptions, Guild } from './structures/Guild.js';
11
- export { type AutocompleteChoice, Interaction, type InteractionReplyOptions, InteractionType, type ModalOptions, } from './structures/Interaction.js';
12
- export { Member } from './structures/Member.js';
13
- export { type EmojiResolvable, Message } from './structures/Message.js';
14
- export { Reaction } from './structures/Reaction.js';
15
- export { Role } from './structures/Role.js';
16
- export { User } from './structures/User.js';
17
- export type { AllowedMentions, ImageOptions, MessageOptions, ReplyOptions, } from './structures/utils.js';
18
- export { type ButtonAppearance, type ButtonClass, type ButtonComponent, type ButtonContext, type ButtonDefinition, type ButtonOptions, type ButtonStyle, type ComponentData, type ComponentInput, defineButton, } from './components.js';
1
+ export { command } from './commands/command.js';
2
+ export type { AutocompleteContext, ChannelOption, CommandAutocomplete, CommandConfig, CommandContext, CommandInDm, CommandInGuild, CommandInPrivate, CommandWhere, CommandDeclaration, CommandLocales, CommandName, CommandOption, CommandOptions, CommandTranslation, Cooldown, Duration, NumberOption, OptionsSoFar, OptionTranslation, OptionValuesOf, SimpleOption, StringOption, Suggestion, } from './commands/command.js';
3
+ export type { CommandInteraction, ComponentInteraction, DmCommandInteraction, GuildCommandInteraction, PrivateCommandInteraction, Interaction, InteractionReply, InteractionReplyOptions, ModalInteraction, } from './structures/interaction.js';
4
+ export type { DynamicText, TextContext } from './components/component.js';
5
+ export { button } from './components/button.js';
6
+ export type { ButtonConfig, ButtonContext, ButtonDeclaration, ButtonLook, ButtonStyleName, } from './components/button.js';
7
+ export { select } from './components/select.js';
8
+ export type { EntitySelectConfig, EntitySelectType, SelectConfig, SelectContext, SelectDeclaration, SelectInstanceOptions, SelectLook, SelectType, StringSelectConfig, } from './components/select.js';
9
+ export { modal } from './components/modal.js';
10
+ export type { CheckboxField, CheckboxesField, EntityField, FieldValue, FieldValuesOf, FilesField, ModalConfig, ModalContext, ModalField, ModalFields, ModalDeclaration, ModalInstanceOptions, ModalPrefill, NoteField, RadioField, SelectField, TextField, } from './components/modal.js';
11
+ export { embed } from './components/embed.js';
12
+ export type { EmbedDeclaration } from './components/embed.js';
13
+ export type { ComponentWhere, ComponentWho, InDm, InGuild, InPrivate, InteractiveConfig, InteractiveContext, PlaceInDm, PlaceInGuild, PlaceInPrivate, PlaceOf, } from './components/component.js';
14
+ export type { DataField, DataInputOf, DataKind, DataShape, DataValuesOf, } from './components/custom-id.js';
15
+ export type { OptionValue, RichOption, SelectOptions, } from './components/options.js';
16
+ export { container, file, gallery, linkButton, premiumButton, row, section, separator, text, thumbnail, } from './components/layout.js';
17
+ export type { ContainerOptions, LinkButtonOptions, MediaOptions, SeparatorOptions, } from './components/layout.js';
18
+ export type { ActionRowComponent, ButtonComponent, ContainerChild, ContainerComponent, FileComponent, GalleryComponent, MessageComponent, ModalComponent, Piece, SectionComponent, SelectComponent, SeparatorComponent, TextComponent, ThumbnailComponent, } from './components/instance.js';
19
+ export { event } from './events/event.js';
20
+ export type { EventConfig, EventDeclaration } from './events/event.js';
21
+ export type { ContextOf, EventWhere, WhereEventOptions, EventContexts, EventName, EventOptions, MessageEventOptions, ReactionEventOptions, } from './events/registry.js';
22
+ export type { CategoryChannel, Channel, DMChannel, FetchMessagesOptions, ForumChannel, ForumPostOptions, ForumTag, GuildChannel, GuildChannelEditOptions, InviteCreateOptions, PermissionOverwrite, TextBasedChannel, GuildTextBasedChannel, TextChannel, ThreadChannel, ThreadCreateOptions, ThreadEditOptions, ThreadMember, VoiceChannel, } from './structures/channel.js';
23
+ export type { GuildEmoji } from './structures/emoji.js';
24
+ export type { AuditLog, AuditLogEntry, AutoModerationRule, Ban, ChannelCreateOptions, Guild, GuildEditOptions, RoleCreateOptions, ScheduledEvent, Sticker, VoiceState, } from './structures/guild.js';
25
+ export type { Invite } from './structures/invite.js';
26
+ export type { BanOptions, GuildMember, MemberEditOptions, } from './structures/member.js';
27
+ export type { Attachment, EmojiInput, DmMessage, GuildMessage, MemberMessage, Message, PrivateMessage, MessageFlagName, Reaction, ReactionEmoji, } from './structures/message.js';
28
+ export { language } from './messages/messages.js';
29
+ export type { CommandsTranslations, FrameworkTexts, LanguageConfig, LanguageDeclaration, MergedMessages, MessagesOf, MessageText, MessageTexts, PluralText, ProjectCommands, ProjectLanguageDefaults, ParamsArgs, ParamsOf, Placeholders, ProjectLocale, ProjectLocales, LocaleGiven, ProjectMessages, TranslationContext, Translator, } from './messages/messages.js';
30
+ export { presence } from './presence/presence.js';
31
+ export type { Activity, ActivityKind, PlainActivity, PresenceConfig, PresenceDeclaration, PresenceStatusName, StreamingActivity, } from './presence/presence.js';
32
+ export { task } from './tasks/task.js';
33
+ export type { CronTaskConfig, EveryTaskConfig, TaskConfig, TaskContext, TaskDeclaration, } from './tasks/task.js';
34
+ export type { AssetFile, AssetOptions } from './assets/asset.js';
35
+ export type { AllowedMentions, Embed, FileInput, MessageEditOptions, MessageInput, MessageOptions, PollInput, } from './structures/payload.js';
36
+ export type { Role, RoleEditOptions } from './structures/role.js';
37
+ export type { User, UserFlagName, UserPresence } from './structures/user.js';
38
+ export type { Webhook, WebhookMessageOptions } from './structures/webhook.js';
39
+ export type { JoinOptions, VoiceConnection } from './voice/connection.js';
40
+ export type { AudioSource } from './voice/source.js';
41
+ export { DiscordApiError, DiscordUnavailableError, InvalidTokenError, } from './rest/errors.js';
42
+ export type { DiscordFieldError } from './rest/errors.js';
43
+ export { Permissions } from './discord/permissions.js';
44
+ export type { PermissionName, PermissionResolvable, } from './discord/permissions.js';
45
+ export { PermissionFlags } from './discord/types/permissions.js';
46
+ export { channelMention, commandMention, emojiMention, GuildNavigation, roleMention, timestamp, TimestampStyle, userMention, } from './discord/formatting.js';
47
+ export type { ImageFormat, ImageOptions, ImageSize } from './discord/cdn.js';
48
+ export { isSnowflake, snowflakeFromTimestamp, snowflakeTimestamp, } from './discord/snowflake.js';
49
+ export { ChannelType, ForumLayoutType, ForumSortOrderType, VideoQualityMode, } from './discord/types/channel.js';
50
+ export { Locale } from './discord/types/common.js';
51
+ export type { Snowflake } from './discord/types/common.js';
52
+ export { ButtonStyle, ComponentType, TextInputStyle, } from './discord/types/component.js';
53
+ export { DefaultMessageNotificationLevel, ExplicitContentFilterLevel, PremiumTier, VerificationLevel, } from './discord/types/guild.js';
54
+ export type { GuildFeature } from './discord/types/guild.js';
55
+ export { AuditLogEvent } from './discord/types/audit-log.js';
56
+ export { MessageFlags, MessageType } from './discord/types/message.js';
57
+ export { UserFlags } from './discord/types/user.js';
package/dist/index.js CHANGED
@@ -1,12 +1,40 @@
1
- export { definePresence, refreshPresence, } from './presence.js';
2
- export { defineEvent, } from './events.js';
3
- export { DiscordAPIError, } from './discord/rest.js';
4
- export { Channel, ChannelType, } from './structures/Channel.js';
5
- export { Guild } from './structures/Guild.js';
6
- export { Interaction, InteractionType, } from './structures/Interaction.js';
7
- export { Member } from './structures/Member.js';
8
- export { Message } from './structures/Message.js';
9
- export { Reaction } from './structures/Reaction.js';
10
- export { Role } from './structures/Role.js';
11
- export { User } from './structures/User.js';
12
- export { defineButton, } from './components.js';
1
+ // The public types of ChapterJS, and everything in its API that is the same
2
+ // wherever it is imported. What depends on the folder of the importing file
3
+ // (`event`...) is exported at runtime by `main.ts`, and typed for each
4
+ // folder of a project by the generated `.chapterjs/` (see
5
+ // `loader/generated.ts`): declaring it here too would make editors offer
6
+ // two imports of the same name.
7
+ //
8
+ // The public API of ChapterJS. User code gets structures from the framework
9
+ // (in events, commands...) and never creates them: classes are exported as
10
+ // types only, and nothing here lets user code connect to Discord or send
11
+ // requests by itself.
12
+ // Slash commands: what the files of src/commands/ are written with.
13
+ export { command } from './commands/command.js';
14
+ export { button } from './components/button.js';
15
+ export { select } from './components/select.js';
16
+ export { modal } from './components/modal.js';
17
+ export { embed } from './components/embed.js';
18
+ export { container, file, gallery, linkButton, premiumButton, row, section, separator, text, thumbnail, } from './components/layout.js';
19
+ // What the functions of src/events/ receive, by event.
20
+ export { event } from './events/event.js';
21
+ // Tasks: what the files of src/tasks/ are written with.
22
+ export { language } from './messages/messages.js';
23
+ export { presence } from './presence/presence.js';
24
+ export { task } from './tasks/task.js';
25
+ // Errors handlers can catch.
26
+ export { DiscordApiError, DiscordUnavailableError, InvalidTokenError, } from './rest/errors.js';
27
+ // Permissions.
28
+ export { Permissions } from './discord/permissions.js';
29
+ export { PermissionFlags } from './discord/types/permissions.js';
30
+ // Helpers to write messages.
31
+ export { channelMention, commandMention, emojiMention, GuildNavigation, roleMention, timestamp, TimestampStyle, userMention, } from './discord/formatting.js';
32
+ export { isSnowflake, snowflakeFromTimestamp, snowflakeTimestamp, } from './discord/snowflake.js';
33
+ // The values Discord uses, by name.
34
+ export { ChannelType, ForumLayoutType, ForumSortOrderType, VideoQualityMode, } from './discord/types/channel.js';
35
+ export { Locale } from './discord/types/common.js';
36
+ export { ButtonStyle, ComponentType, TextInputStyle, } from './discord/types/component.js';
37
+ export { DefaultMessageNotificationLevel, ExplicitContentFilterLevel, PremiumTier, VerificationLevel, } from './discord/types/guild.js';
38
+ export { AuditLogEvent } from './discord/types/audit-log.js';
39
+ export { MessageFlags, MessageType } from './discord/types/message.js';
40
+ export { UserFlags } from './discord/types/user.js';
@@ -0,0 +1,33 @@
1
+ /** What a cooldown applies to: the person, the channel or the server. */
2
+ export type CooldownScope = 'user' | 'channel' | 'guild';
3
+ export declare const COOLDOWN_SCOPES: readonly CooldownScope[];
4
+ /** How long each scope waits, in milliseconds; `0` when it does not. */
5
+ export type CooldownLimits = Readonly<Record<CooldownScope, number>>;
6
+ /** No cooldown at all. */
7
+ export declare const NO_COOLDOWN: CooldownLimits;
8
+ /** Where the last uses are kept. */
9
+ export interface CooldownStore {
10
+ /** When `key` may be used again, as a timestamp; `0` when it may now. */
11
+ until(key: string, now: number): number;
12
+ /** Remembers that `key` may not be used again before `until`. */
13
+ set(key: string, until: number): void;
14
+ }
15
+ /**
16
+ * The default store: a `Map` in the memory of the process. It forgets
17
+ * what expired on its own, so it never grows with the uses of the past.
18
+ */
19
+ export declare class MemoryCooldowns implements CooldownStore {
20
+ #private;
21
+ until(key: string, now: number): number;
22
+ set(key: string, until: number): void;
23
+ /** How many keys are remembered. */
24
+ get size(): number;
25
+ }
26
+ /** The ids a use is counted against, when they exist. */
27
+ export type CooldownIds = Readonly<Partial<Record<CooldownScope, string>>>;
28
+ /**
29
+ * Whether `name` may be used now by these ids, given its limits. Returns
30
+ * `0` and counts the use, or the time it may be used again (the latest
31
+ * of the scopes still waiting) and counts nothing.
32
+ */
33
+ export declare function checkCooldown(store: CooldownStore, name: string, limits: CooldownLimits, ids: CooldownIds, now?: number): number;
@@ -0,0 +1,74 @@
1
+ // Cooldowns: refusing something to a person, a channel or a server that
2
+ // used it a moment ago. Written once for every interaction that can have
3
+ // one (a command today). Where the last uses are kept is behind
4
+ // `CooldownStore`, with a store in memory as default: one shared between
5
+ // processes or machines is another implementation, and nothing else.
6
+ export const COOLDOWN_SCOPES = [
7
+ 'user',
8
+ 'channel',
9
+ 'guild',
10
+ ];
11
+ /** No cooldown at all. */
12
+ export const NO_COOLDOWN = Object.freeze({
13
+ user: 0,
14
+ channel: 0,
15
+ guild: 0,
16
+ });
17
+ /**
18
+ * The default store: a `Map` in the memory of the process. It forgets
19
+ * what expired on its own, so it never grows with the uses of the past.
20
+ */
21
+ export class MemoryCooldowns {
22
+ #until = new Map();
23
+ #sweepAt = 1000;
24
+ until(key, now) {
25
+ const until = this.#until.get(key);
26
+ if (until === undefined)
27
+ return 0;
28
+ if (until <= now) {
29
+ this.#until.delete(key);
30
+ return 0;
31
+ }
32
+ return until;
33
+ }
34
+ set(key, until) {
35
+ this.#until.set(key, until);
36
+ if (this.#until.size >= this.#sweepAt)
37
+ this.#sweep(Date.now());
38
+ }
39
+ /** How many keys are remembered. */
40
+ get size() {
41
+ return this.#until.size;
42
+ }
43
+ /** Forgets what expired, and sweeps again when the rest doubled. */
44
+ #sweep(now) {
45
+ for (const [key, until] of this.#until) {
46
+ if (until <= now)
47
+ this.#until.delete(key);
48
+ }
49
+ this.#sweepAt = Math.max(1000, this.#until.size * 2);
50
+ }
51
+ }
52
+ /**
53
+ * Whether `name` may be used now by these ids, given its limits. Returns
54
+ * `0` and counts the use, or the time it may be used again (the latest
55
+ * of the scopes still waiting) and counts nothing.
56
+ */
57
+ export function checkCooldown(store, name, limits, ids, now = Date.now()) {
58
+ const keys = [];
59
+ let until = 0;
60
+ for (const scope of COOLDOWN_SCOPES) {
61
+ const limit = limits[scope];
62
+ const id = ids[scope];
63
+ if (limit <= 0 || id === undefined)
64
+ continue;
65
+ const key = `${name}\0${scope}\0${id}`;
66
+ until = Math.max(until, store.until(key, now));
67
+ keys.push([key, now + limit]);
68
+ }
69
+ if (until > 0)
70
+ return until;
71
+ for (const [key, expires] of keys)
72
+ store.set(key, expires);
73
+ return 0;
74
+ }
@@ -0,0 +1,91 @@
1
+ import type { RawGuildMember } from '../discord/types/guild.js';
2
+ import type { RawInteraction } from '../discord/types/interaction.js';
3
+ import type { RawUser } from '../discord/types/user.js';
4
+ import { type FrameworkKey, type What } from '../messages/phrases.js';
5
+ import type { TextBasedChannel } from '../structures/channel.js';
6
+ import type { Context } from '../structures/context.js';
7
+ import type { Guild } from '../structures/guild.js';
8
+ import { type Interaction } from '../structures/interaction.js';
9
+ import type { GuildMember } from '../structures/member.js';
10
+ import type { User } from '../structures/user.js';
11
+ /** Where something can be used: the same word for commands and components. */
12
+ export type Where = 'guild' | 'dm' | 'both';
13
+ /** What the developer is told. */
14
+ export interface Reporter {
15
+ /** A `run` threw: reported with the file it comes from. */
16
+ onError: (file: string, error: unknown) => void;
17
+ /** Something the developer should know, that is not an error of theirs. */
18
+ onWarning: (file: string, message: string) => void;
19
+ /**
20
+ * After how long without an answer the framework defers, in milliseconds.
21
+ * Discord gives 3 seconds: the default leaves room for the request.
22
+ */
23
+ deferAfter?: number;
24
+ }
25
+ /** Who did it, as Discord sent it: the member in a server, the user elsewhere. */
26
+ export declare function authorOf(raw: RawInteraction): {
27
+ user: RawUser;
28
+ member: RawGuildMember | undefined;
29
+ } | null;
30
+ /** Where an interaction happened, as its `run` receives it. */
31
+ export interface Place {
32
+ user: User;
33
+ guild: Guild | null;
34
+ member: GuildMember | null;
35
+ channel: TextBasedChannel;
36
+ /** In a server the bot is in, with the member. */
37
+ inGuild: boolean;
38
+ }
39
+ export type Placed = {
40
+ place: Place;
41
+ refusal?: undefined;
42
+ } | {
43
+ place?: undefined;
44
+ refusal: 'guildOnly' | 'dmOnly' | 'notHere';
45
+ };
46
+ /**
47
+ * Where the interaction was used, checked against where `what` works.
48
+ * Returns the place, or what to tell the person when it can't run there.
49
+ */
50
+ export declare function resolvePlace(ctx: Context, raw: RawInteraction, user: User, rawMember: RawGuildMember | undefined, where: Where, warn: (message: string) => void): Placed;
51
+ /** What `run` receives about the place, following `where`. */
52
+ export declare function placeContext(place: Place, where: Where): Record<string, unknown>;
53
+ /** A phrase of the framework, in the language of the person. */
54
+ export declare function says(interaction: Interaction, key: FrameworkKey, params?: {
55
+ what?: What;
56
+ permissions?: string;
57
+ count?: number;
58
+ when?: string;
59
+ }): string;
60
+ /**
61
+ * Answers with a private message, in the language of the person, and
62
+ * never fails.
63
+ */
64
+ export declare function refuse(interaction: Interaction, key: FrameworkKey, params?: {
65
+ what?: What;
66
+ permissions?: string;
67
+ count?: number;
68
+ when?: string;
69
+ }): Promise<void>;
70
+ export interface RunOptions {
71
+ interaction: Interaction;
72
+ /** The file the function comes from. */
73
+ file: string;
74
+ /** How the thing is named in messages to the developer: `/ping`, `buttons/ban`. */
75
+ name: string;
76
+ /** What it is, for the person: "command", "button", "menu", "form". */
77
+ what: What;
78
+ reporter: Reporter;
79
+ /** What to tell Discord when the answer takes long. */
80
+ defer: () => Promise<void>;
81
+ /** What to tell the developer when `run` finishes without answering. */
82
+ unanswered: string;
83
+ run: () => unknown;
84
+ }
85
+ /**
86
+ * Runs the function of an interaction. Discord wants an answer within 3
87
+ * seconds: when `run` takes longer, the framework says the answer is
88
+ * coming. When `run` throws, the person gets a plain answer and the
89
+ * developer the error with its file and line.
90
+ */
91
+ export declare function runInteraction(options: RunOptions): void;
@@ -0,0 +1,110 @@
1
+ // What every interaction shares, whatever runs for it (a command, a
2
+ // button, a menu, a form): who did it and where, whether it is allowed
3
+ // there, and how its function is run so that the person always gets an
4
+ // answer and the developer always gets the error. Written once here;
5
+ // `commands/router.ts` and `components/router.ts` add what is theirs.
6
+ import { setTimeout as sleep } from 'node:timers/promises';
7
+ import { phrase } from '../messages/phrases.js';
8
+ import { DiscordApiError } from '../rest/errors.js';
9
+ import { ctxOf } from '../structures/base.js';
10
+ import { isUpdating } from '../structures/interaction.js';
11
+ /** Who did it, as Discord sent it: the member in a server, the user elsewhere. */
12
+ export function authorOf(raw) {
13
+ const user = raw.member?.user ?? raw.user;
14
+ return user ? { user, member: raw.member } : null;
15
+ }
16
+ /**
17
+ * Where the interaction was used, checked against where `what` works.
18
+ * Returns the place, or what to tell the person when it can't run there.
19
+ */
20
+ export function resolvePlace(ctx, raw, user, rawMember, where, warn) {
21
+ // In a server Discord sends the member, in a private message the user.
22
+ const guild = raw.guild_id
23
+ ? (ctx.cache.guilds.get(raw.guild_id) ?? null)
24
+ : null;
25
+ const member = raw.guild_id && rawMember
26
+ ? ctx.entities.member(raw.guild_id, rawMember)
27
+ : null;
28
+ const inGuild = guild !== null && member !== null;
29
+ if (where === 'guild' && !inGuild) {
30
+ return { refusal: 'guildOnly' };
31
+ }
32
+ if (where === 'dm' && raw.guild_id) {
33
+ return { refusal: 'dmOnly' };
34
+ }
35
+ if (raw.guild_id && !inGuild) {
36
+ // A server the bot is not in: nothing of it is known.
37
+ return { refusal: 'notHere' };
38
+ }
39
+ // Discord sends the channel with the interaction: known without asking.
40
+ const channel = (raw.channel_id ? ctx.cache.channels.get(raw.channel_id) : undefined) ??
41
+ (raw.channel?.id
42
+ ? ctx.entities.channel(raw.channel, raw.guild_id)
43
+ : undefined);
44
+ if (!channel?.isTextBased() || (!inGuild && !channel.isDM())) {
45
+ warn(`was used in a channel the bot can't answer in (${channel ? `type ${channel.type}` : 'Discord did not say which'}): it did not run.`);
46
+ return { refusal: 'notHere' };
47
+ }
48
+ return { place: { user, guild, member, channel, inGuild } };
49
+ }
50
+ /** What `run` receives about the place, following `where`. */
51
+ export function placeContext(place, where) {
52
+ // What a `run` receives follows where it works: nothing about a server
53
+ // exists for what only works in private messages.
54
+ return {
55
+ channel: place.channel,
56
+ ...(where === 'dm' ? {} : { guild: place.guild, member: place.member }),
57
+ };
58
+ }
59
+ /** A phrase of the framework, in the language of the person. */
60
+ export function says(interaction, key, params) {
61
+ return phrase(ctxOf(interaction), interaction.locale, key, params);
62
+ }
63
+ /**
64
+ * Answers with a private message, in the language of the person, and
65
+ * never fails.
66
+ */
67
+ export function refuse(interaction, key, params) {
68
+ return interaction
69
+ .reply({ content: says(interaction, key, params), ephemeral: true })
70
+ .then(() => { }, () => { });
71
+ }
72
+ /**
73
+ * Runs the function of an interaction. Discord wants an answer within 3
74
+ * seconds: when `run` takes longer, the framework says the answer is
75
+ * coming. When `run` throws, the person gets a plain answer and the
76
+ * developer the error with its file and line.
77
+ */
78
+ export function runInteraction(options) {
79
+ const { interaction, file, name, reporter } = options;
80
+ const stop = new AbortController();
81
+ sleep(reporter.deferAfter ?? 2000, undefined, { signal: stop.signal })
82
+ .then(() => options.defer())
83
+ .catch(() => { });
84
+ new Promise(resolve => resolve(options.run()))
85
+ .then(() => {
86
+ if (!interaction.answered) {
87
+ reporter.onWarning(file, `${name} ${options.unanswered}`);
88
+ }
89
+ })
90
+ .catch((error) => {
91
+ reporter.onError(file, error);
92
+ // The person gets a plain answer, never the technical details.
93
+ const missingPermission = error instanceof DiscordApiError &&
94
+ (error.code === 50013 || error.code === 50001);
95
+ const content = missingPermission
96
+ ? says(interaction, 'missingPermission')
97
+ : says(interaction, 'failed', { what: options.what });
98
+ const tell = isUpdating(interaction)
99
+ ? // The pending answer is a change of a message: the bad news must
100
+ // not replace that message.
101
+ interaction.followUp({ content, ephemeral: true })
102
+ : interaction.deferred
103
+ ? interaction.edit(content)
104
+ : interaction.answered
105
+ ? interaction.followUp({ content, ephemeral: true })
106
+ : interaction.reply({ content, ephemeral: true });
107
+ tell.catch(() => { });
108
+ })
109
+ .finally(() => stop.abort());
110
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Writes the `.chapterjs/` folder of a project. A file whose content did
3
+ * not change is left alone, so editors don't reload for nothing; what an
4
+ * older version wrote and this one does not is removed. `declarations` is
5
+ * what 'chapterjs' has in this project on top of the package: `declare
6
+ * module 'chapterjs'` augmentations, importing the package from
7
+ * `'#chapterjs'`.
8
+ * @returns how many files were written
9
+ */
10
+ export declare function writeGenerated(projectDir: string, declarations: string): Promise<number>;
@@ -0,0 +1,80 @@
1
+ // The `.chapterjs/` folder of a project: what the framework writes so that
2
+ // the files of the project are typed from the project itself, with nothing
3
+ // to write. Everything 'chapterjs' gives is typed by the package; what only
4
+ // the project knows (the files of `public/`, its languages, its commands)
5
+ // is written here as an augmentation of 'chapterjs', in one TypeScript
6
+ // project that covers every file of `src/`. The tsconfig of the user
7
+ // project only references this folder; editors and `tsc -b` find it by
8
+ // themselves.
9
+ import { existsSync } from 'node:fs';
10
+ import { mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises';
11
+ import { dirname, join, relative, sep } from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+ const HEADER = '// Written by ChapterJS: do not edit, it is overwritten.\n';
14
+ const json = (value) => `${JSON.stringify(value, null, 2)}\n`;
15
+ /** How a file of `.chapterjs/types/` imports the real package. */
16
+ function packageSpecifier(projectDir) {
17
+ const installed = join(projectDir, 'node_modules', 'chapterjs');
18
+ const target = existsSync(installed)
19
+ ? installed
20
+ : // No node_modules (some package managers): where this code runs from.
21
+ fileURLToPath(new URL('../..', import.meta.url));
22
+ const path = relative(join(projectDir, '.chapterjs', 'types'), target);
23
+ return `${path.split(sep).join('/')}/dist/index.js`;
24
+ }
25
+ /** Every file of `.chapterjs/`, by its path inside it. */
26
+ function generatedFiles(projectDir, declarations) {
27
+ const files = new Map();
28
+ const specifier = packageSpecifier(projectDir);
29
+ // The folder ignores itself: nothing to add to the project's .gitignore.
30
+ files.set('.gitignore', '*\n');
31
+ // What the project adds to 'chapterjs': written as an augmentation, so
32
+ // the editor offers one 'chapterjs' and not a second copy of it.
33
+ files.set('types/project.d.ts', `${HEADER}${declarations.replaceAll("'#chapterjs'", `'${specifier}'`)}`);
34
+ files.set('tsconfig.json', json({
35
+ extends: '../tsconfig.json',
36
+ // The declaration file is listed too: a project without a src folder
37
+ // yet is then a valid, empty project.
38
+ include: ['../src', './types/project.d.ts'],
39
+ }));
40
+ return files;
41
+ }
42
+ /**
43
+ * Writes the `.chapterjs/` folder of a project. A file whose content did
44
+ * not change is left alone, so editors don't reload for nothing; what an
45
+ * older version wrote and this one does not is removed. `declarations` is
46
+ * what 'chapterjs' has in this project on top of the package: `declare
47
+ * module 'chapterjs'` augmentations, importing the package from
48
+ * `'#chapterjs'`.
49
+ * @returns how many files were written
50
+ */
51
+ export async function writeGenerated(projectDir, declarations) {
52
+ const root = join(projectDir, '.chapterjs');
53
+ const files = generatedFiles(projectDir, declarations);
54
+ const existing = await readdir(root, {
55
+ recursive: true,
56
+ withFileTypes: true,
57
+ }).catch(() => []);
58
+ await Promise.all(existing
59
+ .filter(entry => entry.isFile())
60
+ .map(entry => join(entry.parentPath, entry.name))
61
+ .filter(path => !files.has(relative(root, path).split(sep).join('/')) &&
62
+ // What TypeScript itself leaves there to check faster next time,
63
+ // and what features remember between two runs.
64
+ !path.endsWith('.tsbuildinfo') &&
65
+ !relative(root, path).startsWith(`cache${sep}`) &&
66
+ // What `chapterjs build` made is not ours to remove.
67
+ !relative(root, path).startsWith(`build${sep}`))
68
+ .map(path => rm(path, { force: true })));
69
+ let written = 0;
70
+ await Promise.all([...files].map(async ([path, content]) => {
71
+ const target = join(root, path);
72
+ if ((await readFile(target, 'utf8').catch(() => null)) === content) {
73
+ return;
74
+ }
75
+ await mkdir(dirname(target), { recursive: true });
76
+ await writeFile(target, content);
77
+ written++;
78
+ }));
79
+ return written;
80
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Takes over how the files under `dir` are loaded. Called once, before
3
+ * loading. With `reload`, `nextGeneration()` makes them load again.
4
+ */
5
+ export declare function enableProjectLoader(dir: string, { reload }: {
6
+ reload: boolean;
7
+ }): void;
8
+ /** Makes the next imports load the files again. */
9
+ export declare function nextGeneration(): void;
10
+ /** Imports a file of the project, in its current version. */
11
+ export declare function importFile(path: string): Promise<Record<string, unknown>>;
12
+ /** Removes what hot reload adds to the paths shown in errors. */
13
+ export declare function cleanPath(text: string): string;
@@ -0,0 +1,85 @@
1
+ // How Node loads the files of a project.
2
+ //
3
+ // Imports without extension: `import { greet } from '../lib/greet'` finds
4
+ // `greet.ts` (or `greet/index.ts`), as people expect. Node alone asks for
5
+ // the extension; writing it still works.
6
+ //
7
+ // Hot reload: Node keeps every imported module forever, by URL. Each reload
8
+ // gets a new "generation" number, added to the URL of every file of the
9
+ // project (and only of the project: packages keep their single copy). A
10
+ // file and everything it imports from the project are then loaded again.
11
+ import { registerHooks } from 'node:module';
12
+ import { pathToFileURL } from 'node:url';
13
+ const PARAM = 'chapter';
14
+ let generation = 0;
15
+ let root = null;
16
+ let hot = false;
17
+ /** What an import without extension may be, in the order it is tried. */
18
+ const CANDIDATES = [
19
+ '.ts',
20
+ '.mts',
21
+ '.js',
22
+ '.mjs',
23
+ '/index.ts',
24
+ '/index.mts',
25
+ '/index.js',
26
+ '/index.mjs',
27
+ ];
28
+ const EXTENSION = /\.(?:m?ts|m?js)$/;
29
+ /**
30
+ * Takes over how the files under `dir` are loaded. Called once, before
31
+ * loading. With `reload`, `nextGeneration()` makes them load again.
32
+ */
33
+ export function enableProjectLoader(dir, { reload }) {
34
+ if (root !== null)
35
+ throw new Error('The project loader is already enabled.');
36
+ root = pathToFileURL(dir).href.replace(/\/?$/, '/');
37
+ hot = reload;
38
+ registerHooks({
39
+ resolve(specifier, context, nextResolve) {
40
+ const fromProject = root !== null &&
41
+ context.parentURL?.startsWith(root) === true &&
42
+ specifier.startsWith('.');
43
+ let result;
44
+ try {
45
+ result = nextResolve(specifier, context);
46
+ }
47
+ catch (error) {
48
+ if (!fromProject || EXTENSION.test(specifier))
49
+ throw error;
50
+ // No extension: look for the file people mean.
51
+ for (const candidate of CANDIDATES) {
52
+ try {
53
+ result = nextResolve(specifier.replace(/\/$/, '') + candidate, context);
54
+ break;
55
+ }
56
+ catch {
57
+ // Try the next one.
58
+ }
59
+ }
60
+ if (!result)
61
+ throw error;
62
+ }
63
+ if (hot && root !== null && result.url.startsWith(root)) {
64
+ return {
65
+ ...result,
66
+ url: `${result.url.split('?')[0]}?${PARAM}=${generation}`,
67
+ };
68
+ }
69
+ return result;
70
+ },
71
+ });
72
+ }
73
+ /** Makes the next imports load the files again. */
74
+ export function nextGeneration() {
75
+ generation++;
76
+ }
77
+ /** Imports a file of the project, in its current version. */
78
+ export function importFile(path) {
79
+ const url = pathToFileURL(path).href;
80
+ return import(hot ? `${url}?${PARAM}=${generation}` : url);
81
+ }
82
+ /** Removes what hot reload adds to the paths shown in errors. */
83
+ export function cleanPath(text) {
84
+ return text.replace(new RegExp(`\\?${PARAM}=\\d+`, 'g'), '');
85
+ }