@seedcord/core 0.1.0-next.0 → 0.1.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,3 +1,7 @@
1
+ import { C as BuilderComponent, E as RowType, S as RegisterCommand, T as BuilderType, _ as RequiredOf, b as CoreBase, d as JoinNames, f as TwoOrMore, g as GateContextBase, h as Gate, m as EffectGate, n as CustomId, p as Notice, s as GateNoticeOptions, u as IntersectRequired, v as defineEffectGate, w as RowComponent, y as defineGate } from "./CustomId-Ddwg48VY.mjs";
2
+ import { ValidDuration } from "@seedcord/utils";
3
+ import { EpochMs, RenderContext, ReplyResponse } from "@seedcord/types";
4
+
1
5
  //#region src/registries/ContextMenuRegistry.d.ts
2
6
  /**
3
7
  * Maps each user context-menu command name to a presence marker. Populated by `seedcord codegen`, which
@@ -56,9 +60,323 @@ interface SlashOption {
56
60
  */
57
61
  interface SlashOptionRegistry {}
58
62
  //#endregion
63
+ //#region src/gates/combinators.d.ts
64
+ /**
65
+ * Runs each gate in order and refuses on the first refusal. Takes two or more arms. The required
66
+ * context is the intersection of the arms, so an event-only and an interaction-only gate cannot be
67
+ * combined.
68
+ *
69
+ * @typeParam Gates - The tuple of two or more gate arms, run left to right.
70
+ * @param gates - The gate arms to run in order, all refused on the first refusal.
71
+ *
72
+ * @see {@link or}
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * import { PermissionFlagsBits } from 'discord.js';
77
+ *
78
+ * \@Gated(and(GuildOnly(), RequirePermissions([PermissionFlagsBits.BanMembers])))
79
+ * \@SlashRoute('ban')
80
+ * class BanHandler extends SlashHandler<'ban'> {
81
+ * async execute() {
82
+ * // ...
83
+ * }
84
+ * }
85
+ * ```
86
+ */
87
+ declare function and<Gates extends TwoOrMore<Gate<GateContextBase>>>(...gates: Gates): Gate<IntersectRequired<Gates> & GateContextBase, JoinNames<Gates, ' & '>>;
88
+ interface OrOptions {
89
+ fail: Notice | ((ctx: GateContextBase) => Notice);
90
+ }
91
+ /**
92
+ * Runs each gate in order and passes on the first arm that passes. Takes two or more arms. The
93
+ * required context is the union of the arms, so a handler that matches any one arm fits. When every
94
+ * arm refuses it throws the trailing {@link OrOptions} `fail` if given, else an auto list of the
95
+ * arms derived from the summary field, else a default refusal. The trailing options object does not
96
+ * count as an arm.
97
+ *
98
+ * @typeParam Gates - The tuple of two or more gate arms, tried left to right.
99
+ * @param gates - The gate arms to try in order, with an optional trailing {@link OrOptions} object.
100
+ *
101
+ * @see {@link and}
102
+ *
103
+ * @example
104
+ * ```ts
105
+ * \@Gated(or(OwnerOnly(), RequireRole('123456789012345678')))
106
+ * \@SlashRoute('admin')
107
+ * class AdminHandler extends SlashHandler<'admin'> {
108
+ * async execute() {
109
+ * // ...
110
+ * }
111
+ * }
112
+ * ```
113
+ */
114
+ declare function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(...gates: Gates): Gate<RequiredOf<Gates[number]>, JoinNames<Gates, ' | '>>;
115
+ /**
116
+ * @example
117
+ * ```ts
118
+ * // custom refusal when every arm refuses
119
+ * or(OwnerOnly(), RequireRole('123456789012345678'), { fail: new NotAllowedNotice() });
120
+ * ```
121
+ */
122
+ declare function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(...args: [...Gates, OrOptions]): Gate<RequiredOf<Gates[number]>, JoinNames<Gates, ' | '>>;
123
+ //#endregion
124
+ //#region src/gates/catalog/access.d.ts
125
+ /**
126
+ * Passes only for a user id listed in `config.ownerIds`, else refuses.
127
+ *
128
+ * Agnostic, so it attaches to interaction and event handlers alike. With no `ownerIds` configured it refuses every caller. Pass {@link GateNoticeOptions} to reword or replace the refusal.
129
+ *
130
+ * @param options - Reword the default refusal with `message`, or replace it with `notice`.
131
+ *
132
+ * @see the `@Gated` decorator from `seedcord`
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * \@Gated(OwnerOnly())
137
+ * \@SlashRoute('shutdown')
138
+ * class ShutdownHandler extends SlashHandler<'shutdown'> {
139
+ * async execute() {
140
+ * // ...
141
+ * }
142
+ * }
143
+ * ```
144
+ *
145
+ * @example
146
+ * ```ts
147
+ * // reword the refusal, keeping the embed styling
148
+ * OwnerOnly({ message: 'Owners only.' });
149
+ * ```
150
+ */
151
+ declare function OwnerOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'OwnerOnly'>;
152
+ /**
153
+ * Passes inside a guild, else refuses.
154
+ *
155
+ * Agnostic, so it attaches to any handler kind. Often paired with `RequirePermissions` in an {@link and}.
156
+ *
157
+ * @param options - Reword the default refusal with `message`, or replace it with `notice`.
158
+ *
159
+ * @see the `@Gated` decorator from `seedcord`
160
+ *
161
+ * @example
162
+ * ```ts
163
+ * import { PermissionFlagsBits } from 'discord.js';
164
+ *
165
+ * \@Gated(GuildOnly(), RequirePermissions([PermissionFlagsBits.Administrator]))
166
+ * \@SlashRoute('maintenance')
167
+ * class Maintenance extends SlashHandler<'maintenance'> {
168
+ * async execute() {
169
+ * // ...
170
+ * }
171
+ * }
172
+ * ```
173
+ */
174
+ declare function GuildOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'GuildOnly'>;
175
+ /**
176
+ * Passes in a direct message, else refuses.
177
+ *
178
+ * Agnostic, so it attaches to any handler kind. The inverse of {@link GuildOnly}, so combining the two in an {@link and} can never pass.
179
+ *
180
+ * @param options - Reword the default refusal with `message`, or replace it with `notice`.
181
+ *
182
+ * @see the `@Gated` decorator from `seedcord`
183
+ *
184
+ * @example
185
+ * ```ts
186
+ * \@Gated(DmOnly())
187
+ * \@SlashRoute('verify')
188
+ * class VerifyHandler extends SlashHandler<'verify'> {
189
+ * async execute() {
190
+ * // ...
191
+ * }
192
+ * }
193
+ * ```
194
+ */
195
+ declare function DmOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'DmOnly'>;
196
+ //#endregion
197
+ //#region src/gates/catalog/Cooldown.d.ts
198
+ /**
199
+ * Options for {@link Cooldown}. `per` sets the bucket the window applies to and `limit` the uses allowed per
200
+ * window. `message` rewords the refusal and `notice` replaces it, both receiving the epoch ms the key frees
201
+ * up so the refusal can show the retry time.
202
+ *
203
+ * @example
204
+ * ```ts
205
+ * // one use per channel, rewording the refusal with the retry time
206
+ * Cooldown('10s', {
207
+ * per: 'channel',
208
+ * message: (resetAt) => `Slow down. Try again <t:${Math.round(resetAt / 1000)}:R>.`
209
+ * });
210
+ * ```
211
+ *
212
+ * @example
213
+ * ```ts
214
+ * // five uses per minute, per user
215
+ * Cooldown('1m', { limit: 5 });
216
+ * ```
217
+ */
218
+ interface CooldownOptions {
219
+ /**
220
+ * The bucket the cooldown window applies to. 'user' scopes by user ID, falls back to global when the source carries no user id. 'guild' scopes by guild ID (falls back to global if no guild), and 'channel' scopes by channel ID (falls back to global if no channel).
221
+ *
222
+ * @defaultValue `'user'`
223
+ */
224
+ per?: 'user' | 'guild' | 'channel';
225
+ /**
226
+ * Uses allowed inside one window before the gate refuses.
227
+ *
228
+ * @defaultValue `1`
229
+ */
230
+ limit?: number;
231
+ /**
232
+ * Reword the refusal, keeping the standard notice card. Receives the epoch ms the key frees up, so the
233
+ * text can include the retry time with `<t:${Math.round(resetAt / 1000)}:R>`.
234
+ */
235
+ message?: (resetAt: EpochMs) => string;
236
+ /**
237
+ * Replace the refusal Notice entirely, for full control or a translated copy. Receives the epoch ms the
238
+ * key frees up.
239
+ */
240
+ notice?: (resetAt: EpochMs) => Notice;
241
+ }
242
+ /**
243
+ * Allows `limit` uses per window, scoped by `per`. A number `duration` is **seconds**, a string is
244
+ * a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError** at construction. The
245
+ * slot is charged in commit, only after the whole gate set passes, so a later refusal never burns the cooldown.
246
+ * That split also means two requests racing the same key can both pass before either charges the slot.
247
+ * Each call gets its own bucket, so two handlers never share a window. Reword the refusal with {@link CooldownOptions.message}
248
+ * or replace it with {@link CooldownOptions.notice}.
249
+ *
250
+ * @param duration - A number is seconds, a string is a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError**.
251
+ * @param options - Sets the scope with `per`, the uses per window with `limit`, and the refusal text with `message` or `notice`.
252
+ *
253
+ * @see the `@Gated` decorator from `seedcord`
254
+ * @see {@link IRateLimiter}
255
+ *
256
+ * @example
257
+ * ```ts
258
+ * // a number argument is SECONDS
259
+ * \@Gated(Cooldown(5))
260
+ * \@SlashRoute('daily')
261
+ * class DailyHandler extends SlashHandler<'daily'> {
262
+ * async execute() {
263
+ * // ...
264
+ * }
265
+ * }
266
+ * ```
267
+ *
268
+ * @example
269
+ * ```ts
270
+ * // a string is a duration, here scoped per guild (the default is per user)
271
+ * Cooldown('30m', { per: 'guild' });
272
+ * ```
273
+ *
274
+ * @example
275
+ * ```ts
276
+ * // a burst, 3 uses per 10 minutes per user, then it refuses until a slot frees
277
+ * \@Gated(Cooldown('10m', { limit: 3 }))
278
+ * \@SlashRoute('report')
279
+ * class ReportHandler extends SlashHandler<'report'> {
280
+ * async execute() {
281
+ * // ...
282
+ * }
283
+ * }
284
+ * ```
285
+ */
286
+ declare function Cooldown(duration: number | ValidDuration, options?: CooldownOptions): EffectGate<GateContextBase, 'Cooldown'>;
287
+ //#endregion
288
+ //#region src/stops/Fault.d.ts
289
+ /**
290
+ * A generic fault you throw after catching an error you do not have a specific message for.
291
+ *
292
+ * The user sees a fixed generic reply with the tracking uuid, never the cause. `report` defaults to
293
+ * `true`, so the framework logs it and publishes it to the `handledException` bus. Pass `report: false`
294
+ * to show the generic reply without the bus publish. The original error is stored as the standard
295
+ * `cause`, so the real stack reaches the webhook. For a fault the user should see a real message,
296
+ * subclass {@link Notice} and write your own `render` instead.
297
+ *
298
+ * The framework also renders this for an unhandled throw, where it points the user at
299
+ * `ctx.developerUsername`.
300
+ *
301
+ * @example
302
+ * ```ts
303
+ * import { Fault } from 'seedcord';
304
+ *
305
+ * try {
306
+ * await db.write(record);
307
+ * } catch (cause) {
308
+ * // user sees the generic reply with the uuid, the real error rides along as cause for the webhook
309
+ * throw new Fault({ cause });
310
+ *
311
+ * // pass report: false to show the same reply without publishing to the handledException bus
312
+ * // throw new Fault({ cause, report: false });
313
+ * }
314
+ * ```
315
+ */
316
+ declare class Fault extends Notice {
317
+ constructor(options?: {
318
+ cause?: unknown;
319
+ report?: boolean;
320
+ });
321
+ render(ctx: RenderContext): ReplyResponse;
322
+ }
323
+ //#endregion
324
+ //#region src/stops/Silence.d.ts
325
+ /**
326
+ * Throw to stop a handler with no reply and no report.
327
+ *
328
+ * The framework boundary catches `Silence` before {@link Notice}, makes zero Discord calls, and stops.
329
+ * Ideally you'd only throw this in `EventHandlers` (or `Gates` for those), because it doesn't make sense to
330
+ * leave the user with no reply for an interaction.
331
+ *
332
+ * @example
333
+ * ```ts
334
+ * import { Silence } from 'seedcord';
335
+ *
336
+ * // before any reply or defer, drop the interaction with no reply and no report
337
+ * if (await isBlacklisted(interaction.user.id)) throw new Silence('blacklisted user');
338
+ * ```
339
+ */
340
+ declare class Silence extends Error {
341
+ readonly reason?: string | undefined;
342
+ /**
343
+ * @param reason - Optional note written only to a debug log, never shown to the user or reported.
344
+ */
345
+ constructor(reason?: string | undefined);
346
+ }
347
+ //#endregion
348
+ //#region src/pagination/PageView.d.ts
349
+ /**
350
+ * One rendered page of a paginated list.
351
+ *
352
+ * @typeParam Item - The item type.
353
+ */
354
+ interface PageView<Item> {
355
+ items: Item[];
356
+ /** Zero-based, already clamped into range. */
357
+ page: number;
358
+ perPage: number;
359
+ /** The total page count, or `undefined` for a cursor source that has no cheap total. */
360
+ totalPages?: number;
361
+ hasPrev: boolean;
362
+ hasNext: boolean;
363
+ }
364
+ //#endregion
365
+ //#region src/pagination/paginate.d.ts
366
+ /**
367
+ * Pure page math, usable headless. Clamps `page` into range and slices the window.
368
+ *
369
+ * @param items - The full list to page over.
370
+ * @param page - The requested zero-based page, clamped into `[0, totalPages - 1]`.
371
+ * @param perPage - The page size. Must be a positive integer.
372
+ * @returns The sliced {@link PageView}, with `totalPages` always known.
373
+ * @throws SeedcordRangeError when `perPage` is not a positive integer.
374
+ */
375
+ declare function paginate<Item>(items: readonly Item[], page: number, perPage: number): PageView<Item>;
376
+ //#endregion
59
377
  //#region src/index.d.ts
60
378
  /** Package version */
61
379
  declare const version: string;
62
380
  //#endregion
63
- export { type MessageContextMenuRegistry, type OptionKind, type SlashOption, type SlashOptionRegistry, type UserContextMenuRegistry, version };
381
+ export { BuilderComponent, type BuilderType, Cooldown, type CooldownOptions, type CoreBase, CustomId, DmOnly, type EffectGate, Fault, type Gate, type GateContextBase, type GateNoticeOptions, GuildOnly, type MessageContextMenuRegistry, Notice, type OptionKind, OwnerOnly, type PageView, RegisterCommand, type RequiredOf, RowComponent, type RowType, Silence, type SlashOption, type SlashOptionRegistry, type UserContextMenuRegistry, and, defineEffectGate, defineGate, or, paginate, version };
64
382
  //# sourceMappingURL=index.d.mts.map