@seedcord/core 0.1.0-next.4 → 0.1.0-next.6

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 (42) hide show
  1. package/dist/{CustomId--QizzBOn.d.mts → AutocompleteOptions-eKhIe6Qt.d.mts} +496 -163
  2. package/dist/Plugin-C2-VHrsX.cjs +114 -0
  3. package/dist/Plugin-C2-VHrsX.cjs.map +1 -0
  4. package/dist/Plugin-CNyRKDHT.d.mts +226 -0
  5. package/dist/Plugin-PcdPjAzc.mjs +97 -0
  6. package/dist/Plugin-PcdPjAzc.mjs.map +1 -0
  7. package/dist/devChannel-CQU7hq7Q.mjs +14 -0
  8. package/dist/devChannel-CQU7hq7Q.mjs.map +1 -0
  9. package/dist/devChannel-CoCmAVDx.cjs +26 -0
  10. package/dist/devChannel-CoCmAVDx.cjs.map +1 -0
  11. package/dist/index.cjs +239 -105
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.mts +182 -25
  14. package/dist/index.mjs +199 -79
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/internal.index.cjs +463 -57
  17. package/dist/internal.index.cjs.map +1 -1
  18. package/dist/internal.index.d.mts +146 -28
  19. package/dist/internal.index.mjs +415 -29
  20. package/dist/internal.index.mjs.map +1 -1
  21. package/dist/is-never-Ddaba1Su.d.mts +58 -0
  22. package/dist/node-internal.index.cjs +645 -0
  23. package/dist/node-internal.index.cjs.map +1 -0
  24. package/dist/node-internal.index.d.cts +1 -0
  25. package/dist/node-internal.index.d.mts +2352 -0
  26. package/dist/node-internal.index.mjs +636 -0
  27. package/dist/node-internal.index.mjs.map +1 -0
  28. package/dist/{CustomId-DV7daU7r.cjs → permissions-DSW_EZfN.cjs} +448 -89
  29. package/dist/permissions-DSW_EZfN.cjs.map +1 -0
  30. package/dist/{CustomId-epJayEGO.mjs → permissions-RVCBhL2n.mjs} +341 -90
  31. package/dist/permissions-RVCBhL2n.mjs.map +1 -0
  32. package/dist/phases-BfpAG6w3.mjs +31 -0
  33. package/dist/phases-BfpAG6w3.mjs.map +1 -0
  34. package/dist/phases-C_BGNyVo.cjs +43 -0
  35. package/dist/phases-C_BGNyVo.cjs.map +1 -0
  36. package/dist/plugin.index.cjs +4 -0
  37. package/dist/plugin.index.d.cts +1 -0
  38. package/dist/plugin.index.d.mts +3 -0
  39. package/dist/plugin.index.mjs +3 -0
  40. package/package.json +32 -10
  41. package/dist/CustomId-DV7daU7r.cjs.map +0 -1
  42. package/dist/CustomId-epJayEGO.mjs.map +0 -1
@@ -1,7 +1,38 @@
1
+ import { t as IsNever } from "./is-never-Ddaba1Su.mjs";
2
+ import { f as CoreBase } from "./Plugin-CNyRKDHT.mjs";
3
+ import { APIMessageTopLevelComponent, APIModalInteractionResponseCallbackData, ApplicationCommandType, ChannelType, Snowflake } from "discord-api-types/v10";
1
4
  import { ActionRowBuilder, ButtonBuilder, ChannelSelectMenuBuilder, CheckboxBuilder, CheckboxGroupBuilder, CheckboxGroupOptionBuilder, ContainerBuilder, ContextMenuCommandBuilder, EmbedBuilder, FileBuilder, FileUploadBuilder, LabelBuilder, MediaGalleryBuilder, MentionableSelectMenuBuilder, ModalBuilder, RadioGroupBuilder, RadioGroupOptionBuilder, RoleSelectMenuBuilder, SectionBuilder, SeparatorBuilder, SlashCommandBuilder, SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, TextDisplayBuilder, TextInputBuilder, UserSelectMenuBuilder } from "@discordjs/builders";
2
- import { Snowflake } from "discord-api-types/v10";
3
- import { Config, IRateLimiter, RenderContext, ReplyResponse } from "@seedcord/types";
5
+ import { DeferOpts, RenderContext, ReplyResponse, SendOpts } from "@seedcord/types";
4
6
 
7
+ //#region src/registries/SlashOptionRegistry.d.ts
8
+ /** A slash option kind as a plain string union (`string`, `channel`, ...), keyed to the registry. */
9
+ type OptionKind = 'string' | 'integer' | 'number' | 'boolean' | 'user' | 'channel' | 'role' | 'mentionable' | 'attachment';
10
+ /** The type-relevant shape of one slash option, as emitted by `seedcord codegen` into a registry row. */
11
+ interface SlashOption {
12
+ kind: OptionKind;
13
+ required: boolean;
14
+ choices?: readonly (string | number)[];
15
+ autocomplete?: true;
16
+ channelTypes?: readonly ChannelType[];
17
+ }
18
+ /**
19
+ * Maps each slash route string to its option table. Populated by `seedcord codegen`, which reads every
20
+ * command's `toJSON()` and emits a `declare module '@seedcord/gateway'` augmentation, so `keyof SlashOptionRegistry`
21
+ * is the compile-time union of every registered route. Do not augment it by hand, run `seedcord codegen`.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * // seedcord-gen.d.ts (emitted, committed)
26
+ * declare module '@seedcord/gateway' {
27
+ * interface SlashOptionRegistry {
28
+ * ban: { target: { kind: 'user'; required: true }; reason: { kind: 'string'; required: false } };
29
+ * 'demo/setup': { channel: { kind: 'channel'; required: true } };
30
+ * }
31
+ * }
32
+ * ```
33
+ */
34
+ interface SlashOptionRegistry {}
35
+ //#endregion
5
36
  //#region src/components/builderTypes.d.ts
6
37
  /**
7
38
  * Available Discord.js builder classes for use with BuilderComponent for commands, embeds, modals, etc.
@@ -189,24 +220,303 @@ declare function RegisterCommand(scope: 'global'): (ctor: CommandCtor) => void;
189
220
  */
190
221
  declare function RegisterCommand(scope: 'guild', guilds: string[]): (ctor: CommandCtor) => void;
191
222
  //#endregion
192
- //#region src/interfaces/CoreBase.d.ts
223
+ //#region src/metadataKeys.d.ts
224
+ declare enum InteractionRoutes {
225
+ Slash = "slash",
226
+ Button = "button",
227
+ Modal = "modal",
228
+ StringMenu = "stringMenu",
229
+ UserMenu = "userMenu",
230
+ RoleMenu = "roleMenu",
231
+ ChannelMenu = "channelMenu",
232
+ MentionableMenu = "mentionableMenu",
233
+ MessageContextMenu = "messageContextMenu",
234
+ UserContextMenu = "userContextMenu",
235
+ Autocomplete = "autocomplete"
236
+ }
237
+ declare const InteractionMetadataKey: unique symbol;
238
+ declare const InteractionRouteKeys: Record<InteractionRoutes, symbol>;
239
+ declare const MiddlewareMetadataKey: unique symbol;
240
+ declare const EventMetadataKey: unique symbol;
241
+ declare const CommandMetadataKey: unique symbol;
242
+ declare const GatedMetadataKey: unique symbol;
243
+ declare const SubscribeMetadataKey: unique symbol;
244
+ declare const WebhookUrlMetadataKey: unique symbol;
245
+ //#endregion
246
+ //#region src/customId/Field.d.ts
247
+ /**
248
+ * One field in a customId shape, its wire kind plus the type it decodes to.
249
+ *
250
+ * @internal
251
+ */
252
+ interface CustomIdField<Decoded> {
253
+ /** Which wire encoding this field uses. */
254
+ readonly kind: 'snowflake' | 'uuid' | 'int' | 'bool' | 'oneOf' | 'string';
255
+ /** Lower bound, for a bounded int field. */
256
+ readonly min?: number;
257
+ /** Upper bound, for a bounded int field. */
258
+ readonly max?: number;
259
+ /** The allowed values, for a oneOf field. */
260
+ readonly choices?: readonly string[];
261
+ /** Phantom only, carries the decoded type and is never set at runtime. */
262
+ readonly decoded?: Decoded;
263
+ }
264
+ /**
265
+ * The set of fields a customId carries, keyed by name.
266
+ *
267
+ * @internal
268
+ */
269
+ type CustomIdShape = Record<string, CustomIdField<unknown>>;
270
+ /**
271
+ * The decoded result, each field name mapped to its decoded type.
272
+ *
273
+ * @internal
274
+ */
275
+ type DecodedParams<Shape extends CustomIdShape> = { [Name in keyof Shape]: Shape[Name] extends CustomIdField<infer Decoded> ? Decoded : never };
276
+ //#endregion
277
+ //#region src/customId/CustomId.d.ts
278
+ /** Strip the layout hash off the routeKey to recover the stable prefix the controller routes by. @internal */
279
+ declare function prefixOf(wire: string): string;
193
280
  /**
194
- * The transport-agnostic slice of the running framework, what core code (gates, notices, plugins'
195
- * agnostic surface) accesses through `ctx.core`. Each transport's `Core` extends it, the gateway
196
- * adds `bot` and `bus`.
281
+ * A typed customId. The single source of truth shared by the component that mints it and the handler
282
+ * that reads it. This gives you typed reads on the `.customId` field in components. Values are packed into a compact wire string rather than plain stringified tokens, so the 100-char Discord limit goes further. More string per string, basically.
283
+ *
284
+ * @typeParam Prefix - The stable route prefix, e.g. 'approve'.
285
+ * @typeParam Shape - The accumulated fields, filled in by the chain.
286
+ *
287
+ * @example
288
+ * ```ts
289
+ * const ApproveId = new CustomId('approve')
290
+ * .snowflake('userId')
291
+ * .oneOf('action', ['approve', 'deny']);
292
+ *
293
+ * // Set the custom id on a button when creating it.
294
+ * new ButtonBuilder().setCustomId(ApproveId.encode({ userId: '123', action: 'approve' }));
295
+ *
296
+ * // reading in the handler: userId comes back a string
297
+ * const { userId, action } = this.params; // userId: string, action: 'approve' | 'deny'
298
+ * await this.event.guild?.members.fetch(userId);
299
+ * ```
197
300
  */
198
- interface CoreBase {
199
- /** Transports narrow this to their own config type. */
200
- readonly config: Config;
201
- /** Sliding-window rate limiting, the `Cooldown` gate's backend and a public direct-use API. */
202
- readonly rateLimiter: IRateLimiter;
301
+ declare class CustomId<Prefix extends string, Shape extends CustomIdShape = {}> {
302
+ /** The stable route prefix, e.g. 'approve'. */
303
+ readonly prefix: Prefix;
304
+ /** Like a zod shape */
305
+ readonly shape: Shape;
306
+ /** The prefix plus a short hash of the shape, the part of the wire before the colon. */
307
+ readonly routeKey: string;
308
+ constructor(prefix: Prefix, shape?: Shape);
309
+ private add;
310
+ /**
311
+ * Add a Discord ID field, decoded as a string (the `Snowflake` type from discord-api-types).
312
+ *
313
+ * @example
314
+ * ```ts
315
+ * new CustomId('ban').snowflake('userId');
316
+ * ```
317
+ */
318
+ snowflake<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<Snowflake>>>;
319
+ /**
320
+ * Add a UUID field, decoded as a lowercase uuid string.
321
+ *
322
+ * @example
323
+ * ```ts
324
+ * new CustomId('ticket').uuid('ticketId');
325
+ * ```
326
+ */
327
+ uuid<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<string>>>;
328
+ /**
329
+ * Add an integer field with no bounds, for a value up to 2^53.
330
+ *
331
+ * @example
332
+ * ```ts
333
+ * new CustomId('shop').int('amount');
334
+ * ```
335
+ */
336
+ int<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>>;
337
+ /**
338
+ * Add an integer field bounded by min and max, so it packs into fewer characters on the wire.
339
+ *
340
+ * @example
341
+ * ```ts
342
+ * new CustomId('paginate').int('page', 1, 50);
343
+ * ```
344
+ */
345
+ int<Name extends string>(name: Name, min: number, max: number): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>>;
346
+ /**
347
+ * Add a boolean flag.
348
+ *
349
+ * @example
350
+ * ```ts
351
+ * new CustomId('settings').bool('silent');
352
+ * ```
353
+ */
354
+ bool<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<boolean>>>;
355
+ /**
356
+ * Add a field that is one value from a fixed list, decoded as the literal union. No `as const` needed.
357
+ *
358
+ * @example
359
+ * ```ts
360
+ * new CustomId('poll').oneOf('choice', ['yes', 'no', 'abstain']);
361
+ * ```
362
+ */
363
+ oneOf<Name extends string, const Choices extends NonEmptyTuple<string>>(name: Name, choices: Choices): CustomId<Prefix, Shape & Record<Name, CustomIdField<Choices[number]>>>;
364
+ /**
365
+ * Add a free short text field. Avoid it where possible, it cannot be packed so it costs the most wire space.
366
+ *
367
+ * @example
368
+ * ```ts
369
+ * new CustomId('note').str('message');
370
+ * ```
371
+ */
372
+ str<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<string>>>;
373
+ /**
374
+ * Mint a wire string from values. Throws if a value is out of its field's range or the wire is over 100 chars.
375
+ *
376
+ * @param values - One value per field, typed by the chain.
377
+ * @returns The wire string to put on the component's customId.
378
+ */
379
+ encode(values: DecodedParams<Shape>): string;
380
+ /**
381
+ * Read a wire string back into values.
382
+ *
383
+ * - This will refuse with a default Notice when the shape changed since the wire was minted.
384
+ * - Or refuse with a different default Notice on a corrupt or foreign wire.
385
+ *
386
+ * @param wire - The customId string from the interaction.
387
+ * @returns The decoded values, typed by the chain.
388
+ */
389
+ decode(wire: string): DecodedParams<Shape>;
390
+ /** True if this wire was minted from this customId's prefix, ignoring the shape hash. */
391
+ owns(wire: string): boolean;
392
+ }
393
+ /**
394
+ * Any customId, for places where the exact prefix and shape do not matter.
395
+ *
396
+ * @internal
397
+ */
398
+ type AnyCustomId = CustomId<string, CustomIdShape>;
399
+ /**
400
+ * The outcome of decoding a wire against several customIds, the matched prefix paired with its values.
401
+ *
402
+ * @internal
403
+ */
404
+ type DecodedRoute<Defs extends readonly AnyCustomId[]> = { [Index in keyof Defs]: Defs[Index] extends AnyCustomId ? {
405
+ readonly prefix: Defs[Index]['prefix'];
406
+ readonly params: DecodedParams<Defs[Index]['shape']>;
407
+ } : never }[number];
408
+ /**
409
+ * Find the customId whose prefix owns this wire, decode against it, and report which one matched.
410
+ *
411
+ * @internal
412
+ */
413
+ declare function decodeFor<Defs extends readonly AnyCustomId[]>(defs: Defs, wire: string): DecodedRoute<Defs>;
414
+ //#endregion
415
+ //#region src/decorators/interactionRoutes.d.ts
416
+ /** The select menu kinds the select route decorators take. */
417
+ declare enum SelectMenuKind {
418
+ String = "string",
419
+ User = "user",
420
+ Role = "role",
421
+ Channel = "channel",
422
+ Mentionable = "mentionable"
423
+ }
424
+ type RoutableConstructor = new (...args: never[]) => unknown;
425
+ declare function areRoutes(routes: unknown): routes is string[];
426
+ /**
427
+ * Every stored route kind and its route strings on a decorated constructor. The build's manifest
428
+ * emitter reads the same pairs.
429
+ */
430
+ declare function interactionRoutesOf(constructor: RoutableConstructor): [InteractionRoutes, string[]][];
431
+ declare function storeInteractionRoute(route: InteractionRoutes, routes: string | readonly string[], constructor: RoutableConstructor): void;
432
+ declare function storeComponentRoute(route: InteractionRoutes, defs: readonly AnyCustomId[], constructor: RoutableConstructor): void;
433
+ declare function selectMenuRouteOf(kind: SelectMenuKind): InteractionRoutes;
434
+ declare function contextMenuRouteOf(kind: ApplicationCommandType.User | ApplicationCommandType.Message): InteractionRoutes;
435
+ //#endregion
436
+ //#region src/reply/AckTrace.d.ts
437
+ /** The first ack's stack, passed as the throw cause so a double-ack points to both lines. */
438
+ declare class AckTrace extends Error {
439
+ constructor(method: ReplyMethod);
440
+ }
441
+ //#endregion
442
+ //#region src/reply/ackLegality.d.ts
443
+ type AckState = 'unacked' | 'deferred-reply' | 'deferred-update' | 'replied';
444
+ type ReplyMethod = 'reply' | 'defer' | 'deferUpdate' | 'update' | 'followUp' | 'edit' | 'delete' | 'send' | 'showModal';
445
+ /** Throws before any API call. `ackedBy` becomes the throw cause, its stack points at the first ack. */
446
+ declare function checkAckLegality(method: ReplyMethod, state: AckState, routeId: string, ackedBy?: AckTrace): void;
447
+ declare function sendTarget(state: AckState): 'reply' | 'edit' | 'followUp';
448
+ //#endregion
449
+ //#region src/reply/serializeReply.d.ts
450
+ /** Serialized message data the transport wire writers consume. */
451
+ interface SerializedReply {
452
+ readonly components: APIMessageTopLevelComponent[];
453
+ readonly allowedMentions?: ReplyResponse['allowedMentions'];
454
+ readonly files?: ReplyResponse['files'];
455
+ }
456
+ /** Wraps a string in a TextDisplay component. */
457
+ declare function serializeReply(response: ReplyResponse | string, routeId: string): SerializedReply;
458
+ //#endregion
459
+ //#region src/reply/BaseReplySender.d.ts
460
+ /** The shape djs modal builders emit from `toJSON()`. */
461
+ interface ModalLike {
462
+ toJSON(): APIModalInteractionResponseCallbackData;
463
+ }
464
+ /**
465
+ * Tracks acknowledgement state and throws a translated `SeedcordError` on an illegal verb before any
466
+ * transport call. Verbs execute the legality check, control the transport wire writer, then update the
467
+ * state and ack trace. Each transport binds `TMessage` to its created-message lens and supplies the
468
+ * writers.
469
+ */
470
+ declare abstract class BaseReplySender<TMessage extends {
471
+ id: string;
472
+ }> {
473
+ protected readonly routeId: string;
474
+ private state;
475
+ private readonly sent;
476
+ private ackedBy?;
477
+ protected constructor(routeId: string, initialState?: AckState);
478
+ reply(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage>;
479
+ defer(opts?: DeferOpts): Promise<void>;
480
+ deferUpdate(): Promise<void>;
481
+ /**
482
+ * After a deferUpdate the state stays deferred-update, so the rewrite repeats. The returned message
483
+ * is the source message, editable only through a bare `update` or `edit`. A targeted `edit` or `delete`
484
+ * of it throws the foreign-target error.
485
+ */
486
+ update(response: ReplyResponse | string): Promise<TMessage>;
487
+ followUp(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage>;
488
+ edit(response: ReplyResponse | string): Promise<TMessage>;
489
+ edit(target: TMessage, response: ReplyResponse | string): Promise<TMessage>;
490
+ delete(): Promise<void>;
491
+ delete(target: TMessage): Promise<void>;
492
+ /** Routes to the verb the current ack state permits. Every state has a route, so the illegal-ack throw is unreachable. */
493
+ send(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage>;
494
+ /** Must be the initial response. */
495
+ showModal(modal: ModalLike): Promise<void>;
496
+ protected serialize(response: ReplyResponse | string): SerializedReply;
497
+ protected remember(created: TMessage): TMessage;
498
+ private requireMessage;
499
+ private editOriginal;
500
+ private checkLegality;
501
+ private transition;
502
+ protected guardModalSource(): void;
503
+ protected abstract writeReply(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage | undefined>;
504
+ protected abstract writeDefer(opts?: DeferOpts): Promise<void>;
505
+ protected abstract writeDeferUpdate(): Promise<void>;
506
+ protected abstract writeUpdate(response: ReplyResponse | string): Promise<TMessage | undefined>;
507
+ protected abstract writeFollowUp(response: ReplyResponse | string, opts?: SendOpts): Promise<TMessage>;
508
+ protected abstract writeEditOriginal(response: ReplyResponse | string): Promise<TMessage>;
509
+ protected abstract writeEditTarget(targetId: string, response: ReplyResponse | string): Promise<TMessage>;
510
+ protected abstract writeDeleteOriginal(): Promise<void>;
511
+ protected abstract writeDeleteTarget(targetId: string): Promise<void>;
512
+ protected abstract writeModal(data: APIModalInteractionResponseCallbackData): Promise<void>;
203
513
  }
204
514
  //#endregion
205
515
  //#region src/gates/Gate.d.ts
206
516
  /**
207
517
  * The transport-agnostic gate context, the scalar identity of the acting user resolvable from any
208
518
  * transport's payload. Every field except `core` is nullable, since an event or DM may carry no
209
- * guild or member. Each transport extends it with its own rich arm. For e.g., the gateway adds the djs
519
+ * guild or member. Each transport extends it with its own arm. For example, the gateway adds the djs
210
520
  * `user`/`guild`/`member` objects and the live interaction or event payload.
211
521
  *
212
522
  * @example
@@ -236,13 +546,39 @@ interface GateContextBase {
236
546
  * channel-scoped permissions the payload contains, on a gateway event the member's guild-level ones.
237
547
  */
238
548
  readonly memberPermissions: bigint | null;
549
+ /**
550
+ * The bot's permissions in the invoked channel, the wire `app_permissions` value. Null on gateway events.
551
+ */
552
+ readonly appPermissions: bigint | null;
239
553
  /**
240
554
  * The dispatched handler as `kind:route` (`slash:daily`, `button:confirm`), or null off a route (a
241
- * plain event handler, or a gate run outside a handler). `runHandlerGates` populates it from the handler's
555
+ * plain event handler, or a gate run outside a handler). `runHandlerGates` sets it from the handler's
242
556
  * metadata. `Cooldown` uses it so its window is stable across restarts and isolates.
243
557
  */
244
558
  readonly routeId: string | null;
245
559
  }
560
+ /**
561
+ * The context the guild-scoped permission gates require. It adds the base permission sets computed from
562
+ * roles alone, which only the gateway transport can provide from its cache. The http transport's context
563
+ * does not define these fields.
564
+ *
565
+ * @example
566
+ * ```ts
567
+ * // in:'guild' returns a Gate<GuildPermissionsContext>, which fits only a gateway handler
568
+ * \@Gated(RequirePermissions([PermissionFlagsBits.BanMembers], { in: 'guild' }))
569
+ * ```
570
+ */
571
+ interface GuildPermissionsContext extends GateContextBase {
572
+ /**
573
+ * The member's base permission set, roles only, matching djs `GuildMember.permissions`. Null when the
574
+ * member is unavailable.
575
+ */
576
+ readonly memberGuildPermissions: bigint | null;
577
+ /**
578
+ * The bot's base permission set from the transport's cache. Null when the cached member is unavailable.
579
+ */
580
+ readonly appGuildPermissions: bigint | null;
581
+ }
246
582
  declare const GateBrand: unique symbol;
247
583
  /**
248
584
  * A precondition attached to a handler. It refuses by throwing a `Notice` (a reply) or a `Silence`
@@ -462,10 +798,9 @@ type GateFitsWith<Provided, ProvidedLabel extends string, TGate, ReqLabel extend
462
798
  //#endregion
463
799
  //#region src/gates/catalog/options.d.ts
464
800
  /**
465
- * The override a catalog gate accepts, a one-line `message` reword or a full `notice` replacement. Accepted by
466
- * the agnostic gates ({@link OwnerOnly}, {@link GuildOnly}, {@link DmOnly}, {@link Cooldown}) and the gateway's
467
- * `RequireRole` and `Nsfw`. The gateway's `RequirePermissions` and `RequireBotPermissions` take
468
- * `RequirePermissionsOptions` instead.
801
+ * The override a catalog gate accepts. A one-line `message` reword or a full `notice` replacement. Accepted by
802
+ * the agnostic catalog gates and, nested per refusal, by {@link RequireRole}. {@link RequirePermissions} and
803
+ * {@link RequireBotPermissions} take `RequirePermissionsOptions` instead.
469
804
  *
470
805
  * @example
471
806
  * ```ts
@@ -487,174 +822,172 @@ interface GateNoticeOptions {
487
822
  }
488
823
  declare function pickNotice(options: GateNoticeOptions | undefined, makeDefault: (message?: string) => Notice): Notice;
489
824
  //#endregion
490
- //#region src/customId/Field.d.ts
825
+ //#region src/gates/catalog/permissions.d.ts
491
826
  /**
492
- * One field in a customId shape, its wire kind plus the type it decodes to.
493
- *
494
- * @internal
827
+ * The permission flag bits a caller or the bot must hold. Pass the `PermissionFlagsBits` values from
828
+ * `discord-api-types/v10` (or `discord.js`).
495
829
  */
496
- interface CustomIdField<Decoded> {
497
- /** Which wire encoding this field uses. */
498
- readonly kind: 'snowflake' | 'uuid' | 'int' | 'bool' | 'oneOf' | 'string';
499
- /** Lower bound, for a bounded int field. */
500
- readonly min?: number;
501
- /** Upper bound, for a bounded int field. */
502
- readonly max?: number;
503
- /** The allowed values, for a oneOf field. */
504
- readonly choices?: readonly string[];
505
- /** Phantom only, carries the decoded type and is never set at runtime. */
506
- readonly decoded?: Decoded;
507
- }
830
+ type PermissionScope = readonly bigint[];
831
+ /** Permission bit to its prettified human-readable name, for the missing-permission refusal. */
832
+ declare const PermissionNames: Map<bigint, string>;
508
833
  /**
509
- * The set of fields a customId carries, keyed by name.
510
- *
511
- * @internal
834
+ * Options for {@link RequirePermissions} and {@link RequireBotPermissions}.
512
835
  */
513
- type CustomIdShape = Record<string, CustomIdField<unknown>>;
836
+ interface RequirePermissionsOptions {
837
+ /**
838
+ * The set the check reads. `'channel'` reads the effective channel set the payload carries, what
839
+ * Discord enforces in the invoked channel. `'guild'` reads the base set from roles, available on the
840
+ * gateway transport only.
841
+ *
842
+ * @defaultValue `'channel'`
843
+ */
844
+ in?: 'channel' | 'guild';
845
+ /** Reword or replace the refusal shown when the set is unavailable (outside a guild, or unresolved inside one). */
846
+ notInGuild?: GateNoticeOptions;
847
+ /** Reword or replace the refusal shown when a permission is missing. */
848
+ missing?: GateNoticeOptions;
849
+ }
514
850
  /**
515
- * The decoded result, each field name mapped to its decoded type.
516
- *
517
- * @internal
851
+ * Options for {@link RequireRole}.
518
852
  */
519
- type DecodedParams<Shape extends CustomIdShape> = { [Name in keyof Shape]: Shape[Name] extends CustomIdField<infer Decoded> ? Decoded : never };
520
- //#endregion
521
- //#region src/customId/CustomId.d.ts
522
- /** Strip the layout hash off the routeKey to recover the stable prefix the controller routes by. @internal */
523
- declare function prefixOf(wire: string): string;
853
+ interface RequireRoleOptions {
854
+ /** Reword or replace the refusal shown outside a guild. */
855
+ notInGuild?: GateNoticeOptions;
856
+ /** Reword or replace the refusal shown when the caller lacks the role. */
857
+ missingRole?: GateNoticeOptions;
858
+ }
524
859
  /**
525
- * A typed customId. The single source of truth shared by the component that mints it and the handler
526
- * that reads it. This gives you typed reads on the `.customId` field in components. Values are packed into a compact wire string rather than plain stringified tokens, so the 100-char Discord limit goes further. More string per string, basically.
860
+ * Requires the caller to hold every permission in `scope`. Refuses outside a guild first, then when a
861
+ * permission is missing. The Administrator bit passes any scope.
527
862
  *
528
- * @typeParam Prefix - The stable route prefix, e.g. 'approve'.
529
- * @typeParam Shape - The accumulated fields, filled in by the chain.
863
+ * The default `'channel'` scope reads the effective channel set the payload carries, what Discord enforces
864
+ * in the invoked channel. The `'guild'` scope reads the base set from roles and requires a
865
+ * {@link GuildPermissionsContext}, so it fits a gateway handler only.
866
+ *
867
+ * @param scope - The permission flag bits the caller must all hold.
868
+ * @param options - Pick the scope with `in`, and override each refusal with `notInGuild` or `missing`.
869
+ *
870
+ * @see the `@Gated` decorator from `seedcord`
530
871
  *
531
872
  * @example
532
873
  * ```ts
533
- * const ApproveId = new CustomId('approve')
534
- * .snowflake('userId')
535
- * .oneOf('action', ['approve', 'deny']);
874
+ * import { PermissionFlagsBits } from 'discord-api-types/v10';
536
875
  *
537
- * // Set the custom id on a button when creating it.
538
- * new ButtonBuilder().setCustomId(ApproveId.encode({ userId: '123', action: 'approve' }));
876
+ * \@Gated(RequirePermissions([PermissionFlagsBits.BanMembers]))
877
+ * \@SlashRoute('ban')
878
+ * class BanHandler extends SlashHandler<'ban'> {
879
+ * async execute() {
880
+ * // ...
881
+ * }
882
+ * }
883
+ * ```
539
884
  *
540
- * // reading in the handler: userId comes back a string
541
- * const { userId, action } = this.params; // userId: string, action: 'approve' | 'deny'
542
- * await this.event.guild?.members.fetch(userId);
885
+ * @example
886
+ * ```ts
887
+ * // the base set from roles, on a gateway handler
888
+ * RequirePermissions([PermissionFlagsBits.BanMembers], { in: 'guild' });
543
889
  * ```
544
890
  */
545
- declare class CustomId<Prefix extends string, Shape extends CustomIdShape = {}> {
546
- /** The stable route prefix, e.g. 'approve'. */
547
- readonly prefix: Prefix;
548
- /** Like a zod shape */
549
- readonly shape: Shape;
550
- /** The prefix plus a short hash of the shape, the part of the wire before the colon. */
551
- readonly routeKey: string;
552
- constructor(prefix: Prefix, shape?: Shape);
553
- private add;
554
- /**
555
- * Add a Discord ID field, decoded as a string (the `Snowflake` type from discord-api-types).
556
- *
557
- * @example
558
- * ```ts
559
- * new CustomId('ban').snowflake('userId');
560
- * ```
561
- */
562
- snowflake<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<Snowflake>>>;
563
- /**
564
- * Add a UUID field, decoded as a lowercase uuid string.
565
- *
566
- * @example
567
- * ```ts
568
- * new CustomId('ticket').uuid('ticketId');
569
- * ```
570
- */
571
- uuid<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<string>>>;
572
- /**
573
- * Add an integer field with no bounds, for a value up to 2^53.
574
- *
575
- * @example
576
- * ```ts
577
- * new CustomId('shop').int('amount');
578
- * ```
579
- */
580
- int<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>>;
581
- /**
582
- * Add an integer field bounded by min and max, so it packs into fewer characters on the wire.
583
- *
584
- * @example
585
- * ```ts
586
- * new CustomId('paginate').int('page', 1, 50);
587
- * ```
588
- */
589
- int<Name extends string>(name: Name, min: number, max: number): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>>;
590
- /**
591
- * Add a boolean flag.
592
- *
593
- * @example
594
- * ```ts
595
- * new CustomId('settings').bool('silent');
596
- * ```
597
- */
598
- bool<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<boolean>>>;
599
- /**
600
- * Add a field that is one value from a fixed list, decoded as the literal union. No `as const` needed.
601
- *
602
- * @example
603
- * ```ts
604
- * new CustomId('poll').oneOf('choice', ['yes', 'no', 'abstain']);
605
- * ```
606
- */
607
- oneOf<Name extends string, const Choices extends NonEmptyTuple<string>>(name: Name, choices: Choices): CustomId<Prefix, Shape & Record<Name, CustomIdField<Choices[number]>>>;
608
- /**
609
- * Add a free short text field. Avoid it where possible, it cannot be packed so it costs the most wire space.
610
- *
611
- * @example
612
- * ```ts
613
- * new CustomId('note').str('message');
614
- * ```
615
- */
616
- str<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<string>>>;
617
- /**
618
- * Mint a wire string from values. Throws if a value is out of its field's range or the wire is over 100 chars.
619
- *
620
- * @param values - One value per field, typed by the chain.
621
- * @returns The wire string to put on the component's customId.
622
- */
623
- encode(values: DecodedParams<Shape>): string;
624
- /**
625
- * Read a wire string back into values.
626
- *
627
- * - This will refuse with a default Notice when the shape changed since the wire was minted.
628
- * - Or refuse with a different default Notice on a corrupt or foreign wire.
629
- *
630
- * @param wire - The customId string from the interaction.
631
- * @returns The decoded values, typed by the chain.
632
- */
633
- decode(wire: string): DecodedParams<Shape>;
634
- /** True if this wire was minted from this customId's prefix, ignoring the shape hash. */
635
- owns(wire: string): boolean;
636
- }
891
+ declare function RequirePermissions(scope: PermissionScope, options: RequirePermissionsOptions & {
892
+ in: 'guild';
893
+ }): Gate<GuildPermissionsContext, 'RequirePermissions'>;
894
+ declare function RequirePermissions(scope: PermissionScope, options?: RequirePermissionsOptions & {
895
+ in?: 'channel';
896
+ }): Gate<GateContextBase, 'RequirePermissions'>;
637
897
  /**
638
- * Any customId, for places where the exact prefix and shape do not matter.
898
+ * Requires the bot to hold every permission in `scope`. Refuses outside a guild first, then when a
899
+ * permission is missing. The Administrator bit passes any scope.
639
900
  *
640
- * @internal
901
+ * The default `'channel'` scope reads the bot's effective channel set (wire `app_permissions`), what
902
+ * Discord enforces in the invoked channel. The `'guild'` scope reads the bot's base set from roles and
903
+ * requires a {@link GuildPermissionsContext}, so it fits a gateway handler only. `app_permissions` is
904
+ * absent on gateway events, the channel scope refuses there as unresolved, use `in: 'guild'` on an
905
+ * event handler.
906
+ *
907
+ * @param scope - The permission flag bits the bot must all hold.
908
+ * @param options - Pick the scope with `in`, and override each refusal with `notInGuild` or `missing`.
909
+ *
910
+ * @see the `@Gated` decorator from `seedcord`
911
+ *
912
+ * @example
913
+ * ```ts
914
+ * import { PermissionFlagsBits } from 'discord-api-types/v10';
915
+ *
916
+ * \@Gated(RequireBotPermissions([PermissionFlagsBits.ManageMessages]))
917
+ * \@SlashRoute('purge')
918
+ * class PurgeHandler extends SlashHandler<'purge'> {
919
+ * async execute() {
920
+ * // ...
921
+ * }
922
+ * }
923
+ * ```
641
924
  */
642
- type AnyCustomId = CustomId<string, CustomIdShape>;
925
+ declare function RequireBotPermissions(scope: PermissionScope, options: RequirePermissionsOptions & {
926
+ in: 'guild';
927
+ }): Gate<GuildPermissionsContext, 'RequireBotPermissions'>;
928
+ declare function RequireBotPermissions(scope: PermissionScope, options?: RequirePermissionsOptions & {
929
+ in?: 'channel';
930
+ }): Gate<GateContextBase, 'RequireBotPermissions'>;
643
931
  /**
644
- * The outcome of decoding a wire against several customIds, the matched prefix paired with its values.
932
+ * Requires the caller to hold `roleId`, read from the member's role ids. Refuses outside a guild first,
933
+ * then when the role is missing. Roles are guild-global, so there is no scope dimension.
645
934
  *
646
- * @internal
935
+ * @param roleId - The role snowflake the caller must hold.
936
+ * @param options - Override each refusal, the outside-guild one with `notInGuild` and the missing-role one with `missingRole`.
937
+ *
938
+ * @see the `@Gated` decorator from `seedcord`
939
+ *
940
+ * @example
941
+ * ```ts
942
+ * \@Gated(RequireRole('123456789012345678'))
943
+ * \@SlashRoute('vip')
944
+ * class VipHandler extends SlashHandler<'vip'> {
945
+ * async execute() {
946
+ * // ...
947
+ * }
948
+ * }
949
+ * ```
647
950
  */
648
- type DecodedRoute<Defs extends readonly AnyCustomId[]> = { [Index in keyof Defs]: Defs[Index] extends AnyCustomId ? {
649
- readonly prefix: Defs[Index]['prefix'];
650
- readonly params: DecodedParams<Defs[Index]['shape']>;
651
- } : never }[number];
951
+ declare function RequireRole(roleId: string, options?: RequireRoleOptions): Gate<GateContextBase, 'RequireRole'>;
952
+ //#endregion
953
+ //#region src/inputs/AutocompleteOptions.d.ts
954
+ type Row<Route extends keyof SlashOptionRegistry> = SlashOptionRegistry[Route];
955
+ type EntryFor<Route extends keyof SlashOptionRegistry, Name extends PropertyKey> = Route extends unknown ? Name extends keyof Row<Route> ? Row<Route>[Name] : never : never;
956
+ type AutocompletableNames<Route extends keyof SlashOptionRegistry> = Route extends unknown ? { [Name in keyof Row<Route>]: Row<Route>[Name] extends {
957
+ autocomplete: true;
958
+ } ? Name : never }[keyof Row<Route>] : never;
959
+ type ChoiceValueOf<Entry> = Entry extends {
960
+ kind: 'string';
961
+ } ? string : Entry extends {
962
+ kind: 'integer' | 'number';
963
+ } ? number : never;
964
+ /** The focused option. `value` is the raw partial Discord delivers mid-type, always a string regardless of kind. */
965
+ interface FocusedField<Route extends keyof SlashOptionRegistry> {
966
+ name: AutocompletableNames<Route>;
967
+ value: string;
968
+ }
969
+ type NamesOfKind<Route extends keyof SlashOptionRegistry, Kind extends OptionKind> = Route extends unknown ? { [Name in keyof Row<Route>]: Row<Route>[Name] extends {
970
+ kind: Kind;
971
+ } ? Name : never }[keyof Row<Route>] : never;
972
+ type ResolvedValue<Entry> = Entry extends {
973
+ choices: readonly (infer Choice)[];
974
+ } ? Choice : Entry extends {
975
+ kind: 'string';
976
+ } ? string : Entry extends {
977
+ kind: 'integer' | 'number';
978
+ } ? number : Entry extends {
979
+ kind: 'boolean';
980
+ } ? boolean : never;
981
+ type Getter<Route extends keyof SlashOptionRegistry, Kind extends OptionKind, Method extends string> = IsNever<NamesOfKind<Route, Kind>> extends true ? unknown : Record<Method, <Name extends NamesOfKind<Route, Kind>>(name: Name) => ResolvedValue<EntryFor<Route, Name>> | null>;
652
982
  /**
653
- * Find the customId whose prefix owns this wire, decode against it, and report which one matched.
983
+ * The sibling-option view for an autocomplete handler. Only the four kinds Discord resolves during
984
+ * autocomplete appear (string, integer, number, boolean), every read is `T | null` because a sibling is
985
+ * partial while the user types the focused field, and a getter appears only when a registered command has
986
+ * an option of that kind.
654
987
  *
655
- * @internal
988
+ * @typeParam Route - One or more route keys from {@link SlashOptionRegistry}.
656
989
  */
657
- declare function decodeFor<Defs extends readonly AnyCustomId[]>(defs: Defs, wire: string): DecodedRoute<Defs>;
990
+ type AutocompleteOptions<Route extends keyof SlashOptionRegistry> = Getter<Route, 'string', 'getString'> & Getter<Route, 'integer', 'getInteger'> & Getter<Route, 'number', 'getNumber'> & Getter<Route, 'boolean', 'getBoolean'>;
658
991
  //#endregion
659
- export { BuilderComponent as C, RowType as E, RegisterCommand as S, BuilderType as T, RequiredOf as _, CustomIdField as a, CoreBase as b, pickNotice as c, JoinNames as d, TwoOrMore as f, GateContextBase as g, Gate as h, prefixOf as i, GateFitsWith as l, EffectGate as m, CustomId as n, DecodedParams as o, Notice as p, decodeFor as r, GateNoticeOptions as s, AnyCustomId as t, IntersectRequired as u, defineEffectGate as v, RowComponent as w, CommandMeta as x, defineGate as y };
660
- //# sourceMappingURL=CustomId--QizzBOn.d.mts.map
992
+ export { InteractionMetadataKey as $, serializeReply as A, interactionRoutesOf as B, GuildPermissionsContext as C, BaseReplySender as D, defineGate as E, AckTrace as F, CustomId as G, storeComponentRoute as H, RoutableConstructor as I, CustomIdField as J, decodeFor as K, SelectMenuKind as L, ReplyMethod as M, checkAckLegality as N, ModalLike as O, sendTarget as P, GatedMetadataKey as Q, areRoutes as R, GateContextBase as S, defineEffectGate as T, storeInteractionRoute as U, selectMenuRouteOf as V, AnyCustomId as W, CommandMetadataKey as X, DecodedParams as Y, EventMetadataKey as Z, JoinNames as _, FocusedField as a, CommandMeta as at, EffectGate as b, RequireBotPermissions as c, BuilderComponent as ct, RequireRole as d, RowType as dt, InteractionRouteKeys as et, RequireRoleOptions as f, OptionKind as ft, IntersectRequired as g, GateFitsWith as h, EntryFor as i, WebhookUrlMetadataKey as it, AckState as j, SerializedReply as k, RequirePermissions as l, RowComponent as lt, pickNotice as m, SlashOptionRegistry as mt, AutocompleteOptions as n, MiddlewareMetadataKey as nt, PermissionNames as o, RegisterCommand as ot, GateNoticeOptions as p, SlashOption as pt, prefixOf as q, ChoiceValueOf as r, SubscribeMetadataKey as rt, PermissionScope as s, Constructor as st, AutocompletableNames as t, InteractionRoutes as tt, RequirePermissionsOptions as u, BuilderType as ut, TwoOrMore as v, RequiredOf as w, Gate as x, Notice as y, contextMenuRouteOf as z };
993
+ //# sourceMappingURL=AutocompleteOptions-eKhIe6Qt.d.mts.map