@seedcord/core 0.1.0-next.7 → 0.1.0-next.8
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/{Plugin-3rlH0uxH.d.mts → Plugin-BZit5HUI.d.mts} +52 -117
- package/dist/{Plugin-Cgp1a0uQ.cjs → Plugin-BlkhHNRm.cjs} +6 -34
- package/dist/Plugin-BlkhHNRm.cjs.map +1 -0
- package/dist/{Plugin-j9GYdroS.mjs → Plugin-CDAV7P9l.mjs} +7 -29
- package/dist/Plugin-CDAV7P9l.mjs.map +1 -0
- package/dist/basic-1hebYVcN.d.mts +22 -0
- package/dist/contextMenuLeaves-f2rbyo83.d.mts +19 -0
- package/dist/{Silence-DiP95iwD.cjs → cursor-BMkFAwO2.cjs} +293 -16
- package/dist/cursor-BMkFAwO2.cjs.map +1 -0
- package/dist/{Silence-dbC2slOB.mjs → cursor-BvSH8tgw.mjs} +222 -17
- package/dist/cursor-BvSH8tgw.mjs.map +1 -0
- package/dist/{AutocompleteOptions-DLp_B8as.d.mts → cursor-D6nBjwaE.d.mts} +150 -8
- package/dist/{index-Dueqztyy.d.mts → index-Cr4-VV4u.d.mts} +3 -3
- package/dist/index.cjs +361 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +237 -38
- package/dist/index.mjs +321 -7
- package/dist/index.mjs.map +1 -1
- package/dist/internal.index.cjs +50 -43
- package/dist/internal.index.cjs.map +1 -1
- package/dist/internal.index.d.mts +46 -41
- package/dist/internal.index.mjs +13 -14
- package/dist/internal.index.mjs.map +1 -1
- package/dist/node-internal.index.cjs +196 -29
- package/dist/node-internal.index.cjs.map +1 -1
- package/dist/node-internal.index.d.mts +59 -9
- package/dist/node-internal.index.mjs +196 -30
- package/dist/node-internal.index.mjs.map +1 -1
- package/dist/{phases-BfpAG6w3.mjs → phases-BauKJOTT.mjs} +2 -2
- package/dist/phases-BauKJOTT.mjs.map +1 -0
- package/dist/{phases-C_BGNyVo.cjs → phases-DcuDHoQl.cjs} +2 -2
- package/dist/phases-DcuDHoQl.cjs.map +1 -0
- package/dist/plugin.index.cjs +1 -1
- package/dist/plugin.index.d.mts +2 -2
- package/dist/plugin.index.mjs +1 -1
- package/dist/{publishDefault-l0NQ-SHo.cjs → publishDefault-CVlwYUS5.cjs} +32 -3
- package/dist/publishDefault-CVlwYUS5.cjs.map +1 -0
- package/dist/{publishDefault-CCf1azzW.mjs → publishDefault-CldnxcT2.mjs} +27 -4
- package/dist/publishDefault-CldnxcT2.mjs.map +1 -0
- package/dist/slashRouteLeaves-BANDtPFm.mjs +23 -0
- package/dist/slashRouteLeaves-BANDtPFm.mjs.map +1 -0
- package/dist/slashRouteLeaves-nfxOAM7Q.cjs +28 -0
- package/dist/slashRouteLeaves-nfxOAM7Q.cjs.map +1 -0
- package/dist/{subscribers-B1G6_LlK.cjs → subscribers-BSJoyKNN.cjs} +4 -4
- package/dist/{subscribers-B1G6_LlK.cjs.map → subscribers-BSJoyKNN.cjs.map} +1 -1
- package/dist/{subscribers-DYqFVP1X.mjs → subscribers-DuxdM2cS.mjs} +4 -4
- package/dist/{subscribers-DYqFVP1X.mjs.map → subscribers-DuxdM2cS.mjs.map} +1 -1
- package/package.json +4 -4
- package/dist/Plugin-Cgp1a0uQ.cjs.map +0 -1
- package/dist/Plugin-j9GYdroS.mjs.map +0 -1
- package/dist/Silence-DiP95iwD.cjs.map +0 -1
- package/dist/Silence-dbC2slOB.mjs.map +0 -1
- package/dist/basic-D7bDlgSP.d.mts +0 -10
- package/dist/phases-BfpAG6w3.mjs.map +0 -1
- package/dist/phases-C_BGNyVo.cjs.map +0 -1
- package/dist/publishDefault-CCf1azzW.mjs.map +0 -1
- package/dist/publishDefault-l0NQ-SHo.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const require_publishDefault = require('./publishDefault-
|
|
3
|
-
const
|
|
4
|
-
const require_phases = require('./phases-
|
|
5
|
-
const require_subscribers = require('./subscribers-
|
|
2
|
+
const require_publishDefault = require('./publishDefault-CVlwYUS5.cjs');
|
|
3
|
+
const require_cursor = require('./cursor-BMkFAwO2.cjs');
|
|
4
|
+
const require_phases = require('./phases-DcuDHoQl.cjs');
|
|
5
|
+
const require_subscribers = require('./subscribers-BSJoyKNN.cjs');
|
|
6
6
|
require("reflect-metadata");
|
|
7
|
+
let _discordjs_builders = require("@discordjs/builders");
|
|
8
|
+
let _seedcord_logger = require("@seedcord/logger");
|
|
9
|
+
let discord_api_types_v10 = require("discord-api-types/v10");
|
|
7
10
|
let _seedcord_errors = require("@seedcord/errors");
|
|
8
11
|
let _seedcord_errors_internal = require("@seedcord/errors/internal");
|
|
9
|
-
let _seedcord_logger = require("@seedcord/logger");
|
|
10
12
|
let _seedcord_utils = require("@seedcord/utils");
|
|
11
13
|
|
|
12
14
|
//#region src/decorators/Command.ts
|
|
@@ -51,7 +53,7 @@ function RegisterCommand(scope, guilds = []) {
|
|
|
51
53
|
*/
|
|
52
54
|
function SlashRoute(...routes) {
|
|
53
55
|
return function(constructor) {
|
|
54
|
-
|
|
56
|
+
require_cursor.storeInteractionRoute("slash", routes, constructor);
|
|
55
57
|
};
|
|
56
58
|
}
|
|
57
59
|
/**
|
|
@@ -76,7 +78,7 @@ function SlashRoute(...routes) {
|
|
|
76
78
|
*/
|
|
77
79
|
function AutocompleteRoute(...routes) {
|
|
78
80
|
return function(constructor) {
|
|
79
|
-
|
|
81
|
+
require_cursor.storeInteractionRoute("autocomplete", routes, constructor);
|
|
80
82
|
};
|
|
81
83
|
}
|
|
82
84
|
/**
|
|
@@ -102,7 +104,7 @@ function AutocompleteRoute(...routes) {
|
|
|
102
104
|
*/
|
|
103
105
|
function ContextMenuRoute(kind, ...names) {
|
|
104
106
|
return function(constructor) {
|
|
105
|
-
|
|
107
|
+
require_cursor.storeInteractionRoute(require_cursor.contextMenuRouteOf(kind), names, constructor);
|
|
106
108
|
};
|
|
107
109
|
}
|
|
108
110
|
/**
|
|
@@ -118,7 +120,7 @@ function ContextMenuRoute(kind, ...names) {
|
|
|
118
120
|
*/
|
|
119
121
|
function ButtonRoute(...defs) {
|
|
120
122
|
return function(constructor) {
|
|
121
|
-
|
|
123
|
+
require_cursor.storeComponentRoute("button", defs, constructor);
|
|
122
124
|
};
|
|
123
125
|
}
|
|
124
126
|
/**
|
|
@@ -134,7 +136,7 @@ function ButtonRoute(...defs) {
|
|
|
134
136
|
*/
|
|
135
137
|
function ModalRoute(...defs) {
|
|
136
138
|
return function(constructor) {
|
|
137
|
-
|
|
139
|
+
require_cursor.storeComponentRoute("modal", defs, constructor);
|
|
138
140
|
};
|
|
139
141
|
}
|
|
140
142
|
/**
|
|
@@ -155,7 +157,7 @@ function ModalRoute(...defs) {
|
|
|
155
157
|
*/
|
|
156
158
|
function SelectMenuRoute(type, ...defs) {
|
|
157
159
|
return function(constructor) {
|
|
158
|
-
|
|
160
|
+
require_cursor.storeComponentRoute(require_cursor.selectMenuRouteOf(type), defs, constructor);
|
|
159
161
|
};
|
|
160
162
|
}
|
|
161
163
|
|
|
@@ -280,21 +282,21 @@ var RepliableHandler = class extends BaseHandler {
|
|
|
280
282
|
* }
|
|
281
283
|
* ```
|
|
282
284
|
*/
|
|
283
|
-
var Fault = class extends
|
|
285
|
+
var Fault = class extends require_cursor.Notice {
|
|
284
286
|
constructor(options) {
|
|
285
287
|
super("A fault occurred", options?.cause === void 0 ? void 0 : { cause: options.cause });
|
|
286
288
|
this.report = options?.report ?? true;
|
|
287
289
|
}
|
|
288
290
|
render(ctx) {
|
|
289
|
-
return { components: [new
|
|
291
|
+
return { components: [new require_cursor.NoticeCard(`Something went wrong. Please reach out to ${ctx.developerUsername ?? "the developer"} with a way to reproduce the error and the following:\n### UUID: \`${ctx.uuid}\``, "Error").component] };
|
|
290
292
|
}
|
|
291
293
|
};
|
|
292
294
|
|
|
293
295
|
//#endregion
|
|
294
296
|
//#region src/gates/combinators.ts
|
|
295
297
|
function and(...gates) {
|
|
296
|
-
return
|
|
297
|
-
for (const gate of gates) await
|
|
298
|
+
return require_cursor.defineGate(gates.map((gate) => gate.name).join(" & "), async (ctx) => {
|
|
299
|
+
for (const gate of gates) await require_cursor.runCheck(gate, ctx);
|
|
298
300
|
});
|
|
299
301
|
}
|
|
300
302
|
function isOrOptions(arg) {
|
|
@@ -304,17 +306,17 @@ function or(...args) {
|
|
|
304
306
|
const last = args.at(-1);
|
|
305
307
|
const options = last !== void 0 && isOrOptions(last) ? last : void 0;
|
|
306
308
|
const gates = options ? args.slice(0, -1) : args;
|
|
307
|
-
return
|
|
309
|
+
return require_cursor.defineGate(gates.map((gate) => gate.name).join(" | "), async (ctx) => {
|
|
308
310
|
const summaries = [];
|
|
309
311
|
let everyArmHasSummary = true;
|
|
310
312
|
for (const gate of gates) {
|
|
311
|
-
const mark =
|
|
313
|
+
const mark = require_cursor.markCommits(ctx);
|
|
312
314
|
try {
|
|
313
|
-
await
|
|
315
|
+
await require_cursor.runCheck(gate, ctx);
|
|
314
316
|
return;
|
|
315
317
|
} catch (error) {
|
|
316
|
-
if (error instanceof
|
|
317
|
-
|
|
318
|
+
if (error instanceof require_cursor.Notice && !(error instanceof Fault) && !error.report) {
|
|
319
|
+
require_cursor.rollbackCommits(ctx, mark);
|
|
318
320
|
if (error.summary === void 0) everyArmHasSummary = false;
|
|
319
321
|
else summaries.push(error.summary);
|
|
320
322
|
continue;
|
|
@@ -323,8 +325,8 @@ function or(...args) {
|
|
|
323
325
|
}
|
|
324
326
|
}
|
|
325
327
|
if (options) throw typeof options.fail === "function" ? options.fail(ctx) : options.fail;
|
|
326
|
-
if (everyArmHasSummary && summaries.length > 0) throw new
|
|
327
|
-
throw new
|
|
328
|
+
if (everyArmHasSummary && summaries.length > 0) throw new require_cursor.NeedsAny(summaries);
|
|
329
|
+
throw new require_cursor.NotAllowed();
|
|
328
330
|
});
|
|
329
331
|
}
|
|
330
332
|
|
|
@@ -357,10 +359,10 @@ function or(...args) {
|
|
|
357
359
|
* ```
|
|
358
360
|
*/
|
|
359
361
|
function OwnerOnly(options) {
|
|
360
|
-
return
|
|
362
|
+
return require_cursor.defineGate("OwnerOnly", (ctx) => {
|
|
361
363
|
const owners = ctx.core.config.ownerIds ?? [];
|
|
362
364
|
if (ctx.userId !== null && owners.includes(ctx.userId)) return;
|
|
363
|
-
throw
|
|
365
|
+
throw require_cursor.pickNotice(options, (message) => new require_cursor.NotOwner(message));
|
|
364
366
|
});
|
|
365
367
|
}
|
|
366
368
|
/**
|
|
@@ -386,9 +388,9 @@ function OwnerOnly(options) {
|
|
|
386
388
|
* ```
|
|
387
389
|
*/
|
|
388
390
|
function GuildOnly(options) {
|
|
389
|
-
return
|
|
391
|
+
return require_cursor.defineGate("GuildOnly", (ctx) => {
|
|
390
392
|
if (ctx.guildId) return;
|
|
391
|
-
throw
|
|
393
|
+
throw require_cursor.pickNotice(options, (message) => new require_cursor.NotInGuild(message));
|
|
392
394
|
});
|
|
393
395
|
}
|
|
394
396
|
/**
|
|
@@ -412,9 +414,9 @@ function GuildOnly(options) {
|
|
|
412
414
|
* ```
|
|
413
415
|
*/
|
|
414
416
|
function DmOnly(options) {
|
|
415
|
-
return
|
|
417
|
+
return require_cursor.defineGate("DmOnly", (ctx) => {
|
|
416
418
|
if (!ctx.guildId) return;
|
|
417
|
-
throw
|
|
419
|
+
throw require_cursor.pickNotice(options, (message) => new require_cursor.NotInDm(message));
|
|
418
420
|
});
|
|
419
421
|
}
|
|
420
422
|
|
|
@@ -486,16 +488,124 @@ function Cooldown(duration, options) {
|
|
|
486
488
|
};
|
|
487
489
|
const anonId = anonSeq++;
|
|
488
490
|
const keyOf = (ctx) => `cooldown:${ctx.routeId ?? `anon${anonId}`}:${per}:w${windowMs}:l${options?.limit ?? 1}:${scopeValue(ctx, per)}`;
|
|
489
|
-
return
|
|
491
|
+
return require_cursor.defineEffectGate("Cooldown", async (ctx) => {
|
|
490
492
|
const result = await ctx.core.rateLimiter.peek(keyOf(ctx), window);
|
|
491
493
|
if (!result.limited) return;
|
|
492
494
|
if (options?.notice) throw options.notice(result.resetAt);
|
|
493
|
-
throw new
|
|
495
|
+
throw new require_cursor.OnCooldown(result.resetAt, options?.message?.(result.resetAt));
|
|
494
496
|
}, async (ctx) => {
|
|
495
497
|
await ctx.core.rateLimiter.charge(keyOf(ctx), window);
|
|
496
498
|
});
|
|
497
499
|
}
|
|
498
500
|
|
|
501
|
+
//#endregion
|
|
502
|
+
//#region src/permissions/assert.ts
|
|
503
|
+
/**
|
|
504
|
+
* Refuses when the subject is missing a permission in `scope`, or with `inverse` when it holds one.
|
|
505
|
+
* The Administrator bit passes any scope, and on the inverse arm it reports every bit in `scope`.
|
|
506
|
+
*
|
|
507
|
+
* The caller computes `permissions`, gateway off a discord.js role, member, or channel, and HTTP off the
|
|
508
|
+
* bitfield the interaction payload carries.
|
|
509
|
+
*
|
|
510
|
+
* @throws A {@link Notice} listing the missing or present permissions.
|
|
511
|
+
*
|
|
512
|
+
* @example
|
|
513
|
+
* ```ts
|
|
514
|
+
* import { assertPermissions } from '@seedcord/core';
|
|
515
|
+
* import { PermissionFlagsBits } from 'discord-api-types/v10';
|
|
516
|
+
*
|
|
517
|
+
* // gateway, the bits come off a discord.js member
|
|
518
|
+
* assertPermissions({
|
|
519
|
+
* subject: `<@${member.id}>`,
|
|
520
|
+
* permissions: member.permissions.bitfield,
|
|
521
|
+
* scope: [PermissionFlagsBits.BanMembers]
|
|
522
|
+
* });
|
|
523
|
+
* ```
|
|
524
|
+
*
|
|
525
|
+
* @example
|
|
526
|
+
* ```ts
|
|
527
|
+
* // HTTP, the payload carries the member's bits as a string
|
|
528
|
+
* assertPermissions({
|
|
529
|
+
* subject: `<@${this.event.member.user.id}>`,
|
|
530
|
+
* permissions: BigInt(this.event.member.permissions),
|
|
531
|
+
* scope: [PermissionFlagsBits.ManageMessages]
|
|
532
|
+
* });
|
|
533
|
+
* ```
|
|
534
|
+
*
|
|
535
|
+
* @example
|
|
536
|
+
* ```ts
|
|
537
|
+
* // inverse, refuse a role that carries Administrator
|
|
538
|
+
* assertPermissions({
|
|
539
|
+
* subject: `<@&${role.id}>`,
|
|
540
|
+
* permissions: role.permissions.bitfield,
|
|
541
|
+
* scope: [PermissionFlagsBits.Administrator],
|
|
542
|
+
* inverse: true
|
|
543
|
+
* });
|
|
544
|
+
* ```
|
|
545
|
+
*
|
|
546
|
+
* @example
|
|
547
|
+
* ```ts
|
|
548
|
+
* import { Notice } from '@seedcord/core';
|
|
549
|
+
*
|
|
550
|
+
* // a replacement notice takes the same three arguments the default one does
|
|
551
|
+
* class CannotBan extends Notice {
|
|
552
|
+
* public constructor(
|
|
553
|
+
* message: string | undefined,
|
|
554
|
+
* private readonly subject: string,
|
|
555
|
+
* private readonly missing: readonly string[]
|
|
556
|
+
* ) {
|
|
557
|
+
* super(message ?? 'You cannot ban here.');
|
|
558
|
+
* }
|
|
559
|
+
*
|
|
560
|
+
* public render(): ReplyResponse {
|
|
561
|
+
* return { components: [new BanDenied(this.subject, this.missing).component] };
|
|
562
|
+
* }
|
|
563
|
+
* }
|
|
564
|
+
*
|
|
565
|
+
* assertPermissions({
|
|
566
|
+
* subject: `<@${member.id}>`,
|
|
567
|
+
* permissions: member.permissions.bitfield,
|
|
568
|
+
* scope: [PermissionFlagsBits.BanMembers],
|
|
569
|
+
* missingNotice: CannotBan
|
|
570
|
+
* });
|
|
571
|
+
* ```
|
|
572
|
+
*/
|
|
573
|
+
function assertPermissions(check) {
|
|
574
|
+
const { subject, permissions, scope, inverse = false, missingNotice, dangerousNotice } = check;
|
|
575
|
+
if (inverse) {
|
|
576
|
+
const present = require_cursor.presentNames(permissions, scope);
|
|
577
|
+
if (present.length === 0) return;
|
|
578
|
+
throw new (dangerousNotice ?? require_cursor.HasDangerousPermissions)(void 0, subject, present);
|
|
579
|
+
}
|
|
580
|
+
if (require_cursor.hasAll(permissions, scope)) return;
|
|
581
|
+
throw new (missingNotice ?? require_cursor.MissingPermissions)(void 0, subject, require_cursor.missingNames(permissions, scope));
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
//#endregion
|
|
585
|
+
//#region src/permissions/mergeRoles.ts
|
|
586
|
+
/**
|
|
587
|
+
* The role ids a member holds after adding and removing the given sets. Removals win over additions.
|
|
588
|
+
*
|
|
589
|
+
* This does not write the roles. Apply the result with `member.roles.set()` on gateway, or PATCH the member over HTTP.
|
|
590
|
+
*
|
|
591
|
+
* @param current - The role ids the member holds.
|
|
592
|
+
* @param add - The role ids to add.
|
|
593
|
+
* @param remove - The role ids to remove.
|
|
594
|
+
* @returns The merged role ids.
|
|
595
|
+
*
|
|
596
|
+
* @example
|
|
597
|
+
* ```ts
|
|
598
|
+
* import { mergeRoles } from '@seedcord/core';
|
|
599
|
+
*
|
|
600
|
+
* // gateway
|
|
601
|
+
* const ids = mergeRoles(member.roles.cache.map((role) => role.id), ['123'], ['456']);
|
|
602
|
+
* await member.roles.set(ids);
|
|
603
|
+
* ```
|
|
604
|
+
*/
|
|
605
|
+
function mergeRoles(current, add, remove) {
|
|
606
|
+
return [...new Set(current).union(new Set(add)).difference(new Set(remove))];
|
|
607
|
+
}
|
|
608
|
+
|
|
499
609
|
//#endregion
|
|
500
610
|
//#region src/pagination/paginate.ts
|
|
501
611
|
/**
|
|
@@ -522,37 +632,246 @@ function paginate(items, page, perPage) {
|
|
|
522
632
|
};
|
|
523
633
|
}
|
|
524
634
|
|
|
635
|
+
//#endregion
|
|
636
|
+
//#region src/pagination/controls.ts
|
|
637
|
+
const DEFAULT_LABEL = {
|
|
638
|
+
first: "First",
|
|
639
|
+
prev: "Prev",
|
|
640
|
+
indicator: "",
|
|
641
|
+
next: "Next",
|
|
642
|
+
last: "Last"
|
|
643
|
+
};
|
|
644
|
+
const CONTROL_SLOT = {
|
|
645
|
+
first: 0,
|
|
646
|
+
prev: 1,
|
|
647
|
+
indicator: 2,
|
|
648
|
+
next: 3,
|
|
649
|
+
last: 4
|
|
650
|
+
};
|
|
651
|
+
const MAX_BUTTONS_PER_ROW = 5;
|
|
652
|
+
var Controls = class {
|
|
653
|
+
cursor;
|
|
654
|
+
view;
|
|
655
|
+
constructor(cursor, view) {
|
|
656
|
+
this.cursor = cursor;
|
|
657
|
+
this.view = view;
|
|
658
|
+
}
|
|
659
|
+
button(key, cosmetics) {
|
|
660
|
+
const { target, disabled } = this.navState(key);
|
|
661
|
+
const defaultLabel = key === "indicator" ? this.indicatorText() : DEFAULT_LABEL[key];
|
|
662
|
+
const label = cosmetics?.label ?? (key === "indicator" || !cosmetics?.emoji ? defaultLabel : void 0);
|
|
663
|
+
const button = new _discordjs_builders.ButtonBuilder().setCustomId(this.cursor.encode({
|
|
664
|
+
page: Math.min(Math.max(0, target), require_cursor.PAGE_MAX),
|
|
665
|
+
slot: CONTROL_SLOT[key]
|
|
666
|
+
})).setStyle(cosmetics?.style ?? discord_api_types_v10.ButtonStyle.Secondary).setDisabled(disabled);
|
|
667
|
+
if (label !== void 0) button.setLabel(label);
|
|
668
|
+
if (cosmetics?.emoji) button.setEmoji(cosmetics.emoji);
|
|
669
|
+
return button;
|
|
670
|
+
}
|
|
671
|
+
navState(key) {
|
|
672
|
+
const { page, totalPages, hasPrev, hasNext } = this.view;
|
|
673
|
+
const knownTotal = totalPages !== void 0;
|
|
674
|
+
return {
|
|
675
|
+
target: {
|
|
676
|
+
first: 0,
|
|
677
|
+
prev: page - 1,
|
|
678
|
+
indicator: page,
|
|
679
|
+
next: page + 1,
|
|
680
|
+
last: knownTotal ? totalPages - 1 : page
|
|
681
|
+
}[key],
|
|
682
|
+
disabled: {
|
|
683
|
+
first: !hasPrev,
|
|
684
|
+
prev: !hasPrev,
|
|
685
|
+
indicator: true,
|
|
686
|
+
next: !hasNext || page + 1 > 1e6,
|
|
687
|
+
last: !hasNext || !knownTotal || totalPages - 1 > 1e6
|
|
688
|
+
}[key]
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
row(...keys) {
|
|
692
|
+
if (keys.length === 0) throw new _seedcord_errors_internal.SeedcordRangeError(_seedcord_errors.SeedcordErrorCode.PaginationEmptyControls);
|
|
693
|
+
if (keys.length > MAX_BUTTONS_PER_ROW) throw new _seedcord_errors_internal.SeedcordRangeError(_seedcord_errors.SeedcordErrorCode.PaginationTooManyControls, [keys.length]);
|
|
694
|
+
const seen = /* @__PURE__ */ new Set();
|
|
695
|
+
for (const key of keys) {
|
|
696
|
+
if (seen.has(key)) throw new _seedcord_errors_internal.SeedcordTypeError(_seedcord_errors.SeedcordErrorCode.PaginationDuplicateControls, [key]);
|
|
697
|
+
seen.add(key);
|
|
698
|
+
}
|
|
699
|
+
return new _discordjs_builders.ActionRowBuilder().addComponents(keys.map((key) => this.button(key)));
|
|
700
|
+
}
|
|
701
|
+
indicatorText() {
|
|
702
|
+
const { page, totalPages } = this.view;
|
|
703
|
+
return totalPages === void 0 ? `Page ${page + 1}` : `Page ${page + 1} of ${totalPages}`;
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
//#endregion
|
|
708
|
+
//#region src/pagination/render.ts
|
|
709
|
+
var PageContainer = class extends require_publishDefault.BuilderComponent {
|
|
710
|
+
constructor(view, renderItem, controlRow) {
|
|
711
|
+
super("container");
|
|
712
|
+
const base = view.page * view.perPage;
|
|
713
|
+
let lines = [];
|
|
714
|
+
const flush = () => {
|
|
715
|
+
if (lines.length === 0) return;
|
|
716
|
+
this.instance.addTextDisplayComponents(new _discordjs_builders.TextDisplayBuilder().setContent(lines.join("\n")));
|
|
717
|
+
lines = [];
|
|
718
|
+
};
|
|
719
|
+
view.items.forEach((item, offset) => {
|
|
720
|
+
const rendered = renderItem(item, base + offset);
|
|
721
|
+
if (typeof rendered === "string") {
|
|
722
|
+
lines.push(rendered);
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
flush();
|
|
726
|
+
this.instance.addSectionComponents(rendered.component);
|
|
727
|
+
});
|
|
728
|
+
flush();
|
|
729
|
+
this.instance.addActionRowComponents(controlRow);
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
function toReplyResponse(renderable) {
|
|
733
|
+
if (typeof renderable === "string") return { components: [new _discordjs_builders.TextDisplayBuilder().setContent(renderable)] };
|
|
734
|
+
if (Array.isArray(renderable)) return { components: renderable };
|
|
735
|
+
return renderable;
|
|
736
|
+
}
|
|
737
|
+
const ARRAY_KEYS = [
|
|
738
|
+
"first",
|
|
739
|
+
"prev",
|
|
740
|
+
"indicator",
|
|
741
|
+
"next",
|
|
742
|
+
"last"
|
|
743
|
+
];
|
|
744
|
+
const CURSOR_KEYS = [
|
|
745
|
+
"prev",
|
|
746
|
+
"indicator",
|
|
747
|
+
"next"
|
|
748
|
+
];
|
|
749
|
+
/**
|
|
750
|
+
* A `render` override builds the whole tree, otherwise the default container lists the items and appends
|
|
751
|
+
* the controls (all five for a known total, prev/indicator/next for a cursor source).
|
|
752
|
+
*/
|
|
753
|
+
function renderPage(view, cursor, config) {
|
|
754
|
+
const controls = new Controls(cursor, view);
|
|
755
|
+
if (config.render) return toReplyResponse(config.render(view, controls));
|
|
756
|
+
return { components: [new PageContainer(view, config.renderItem ?? String, controls.row(...view.totalPages === void 0 ? CURSOR_KEYS : ARRAY_KEYS)).component] };
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
//#endregion
|
|
760
|
+
//#region src/pagination/PaginatorBase.ts
|
|
761
|
+
/**
|
|
762
|
+
* Holds a paginator's cursor and renders one page. Each transport extends this to add the nav handler and
|
|
763
|
+
* the method that sends the first page.
|
|
764
|
+
*
|
|
765
|
+
* @typeParam Item - The item type, inferred from the source.
|
|
766
|
+
* @typeParam Prefix - The route prefix, inferred from `config.prefix`.
|
|
767
|
+
* @typeParam Ctx - The transport's page context.
|
|
768
|
+
*/
|
|
769
|
+
var PaginatorBase = class {
|
|
770
|
+
/** The page cursor, pass it to your `@ButtonRoute`. */
|
|
771
|
+
cursor;
|
|
772
|
+
config;
|
|
773
|
+
constructor(config) {
|
|
774
|
+
this.cursor = require_cursor.pageCursor(config.prefix);
|
|
775
|
+
this.config = config;
|
|
776
|
+
}
|
|
777
|
+
/** Render a page as a {@link ReplyResponse}. To post it elsewhere, add `flags: MessageFlags.IsComponentsV2`. */
|
|
778
|
+
async page(ctx, n) {
|
|
779
|
+
return renderPage(await this.config.source.page(ctx, n), this.cursor, this.config);
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
|
|
783
|
+
//#endregion
|
|
784
|
+
//#region src/pagination/sources.ts
|
|
785
|
+
const DEFAULT_PER_PAGE = 10;
|
|
786
|
+
function perPageOf(opts) {
|
|
787
|
+
const perPage = opts?.perPage ?? DEFAULT_PER_PAGE;
|
|
788
|
+
if (!Number.isSafeInteger(perPage) || perPage <= 0) throw new _seedcord_errors_internal.SeedcordRangeError(_seedcord_errors.SeedcordErrorCode.PaginationInvalidPerPage, [perPage]);
|
|
789
|
+
return perPage;
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* A source for a bounded list you can load whole. It loads the full list on every click, then slices the
|
|
793
|
+
* page via {@link paginate}, so the real total is known (a real last button, "Page X of Y"). Cache inside
|
|
794
|
+
* your loader if the load is expensive.
|
|
795
|
+
*
|
|
796
|
+
* @typeParam Item - The item type, inferred from the loader's return.
|
|
797
|
+
* @typeParam Ctx - The transport's page context. Each transport exports a subclass that fixes it.
|
|
798
|
+
*/
|
|
799
|
+
var ArraySource = class {
|
|
800
|
+
load;
|
|
801
|
+
perPage;
|
|
802
|
+
constructor(load, opts) {
|
|
803
|
+
this.load = load;
|
|
804
|
+
this.perPage = perPageOf(opts);
|
|
805
|
+
}
|
|
806
|
+
async page(ctx, n) {
|
|
807
|
+
return paginate(await this.load(ctx), n, this.perPage);
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
/**
|
|
811
|
+
* A source for a large or unknown-length set you fetch one page at a time (SQL LIMIT/OFFSET, a paged API).
|
|
812
|
+
* The fetcher receives the page index and the page size and reports whether a next page exists. A cursor
|
|
813
|
+
* source has no cheap total, so `totalPages` is undefined, the last button is omitted, and the indicator
|
|
814
|
+
* reads "Page X".
|
|
815
|
+
*
|
|
816
|
+
* @typeParam Item - The item type, inferred from the fetcher's slice.
|
|
817
|
+
* @typeParam Ctx - The transport's page context. Each transport exports a subclass that fixes it.
|
|
818
|
+
*/
|
|
819
|
+
var CursorSource = class {
|
|
820
|
+
fetch;
|
|
821
|
+
perPage;
|
|
822
|
+
constructor(fetch, opts) {
|
|
823
|
+
this.fetch = fetch;
|
|
824
|
+
this.perPage = perPageOf(opts);
|
|
825
|
+
}
|
|
826
|
+
async page(ctx, n) {
|
|
827
|
+
const page = Math.max(0, Math.trunc(n));
|
|
828
|
+
const { items, hasNext } = await this.fetch(ctx, page, this.perPage);
|
|
829
|
+
return {
|
|
830
|
+
items: [...items],
|
|
831
|
+
page,
|
|
832
|
+
perPage: this.perPage,
|
|
833
|
+
hasPrev: page > 0,
|
|
834
|
+
hasNext
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
|
|
525
839
|
//#endregion
|
|
526
840
|
//#region src/index.ts
|
|
527
841
|
/** Package version */
|
|
528
|
-
const version = "0.1.0-next.
|
|
842
|
+
const version = "0.1.0-next.8";
|
|
529
843
|
|
|
530
844
|
//#endregion
|
|
845
|
+
exports.ArraySource = ArraySource;
|
|
531
846
|
exports.AutocompleteRoute = AutocompleteRoute;
|
|
532
847
|
exports.BaseHandler = BaseHandler;
|
|
533
848
|
exports.BuilderComponent = require_publishDefault.BuilderComponent;
|
|
534
849
|
exports.Bus = require_subscribers.Bus;
|
|
535
850
|
exports.ButtonRoute = ButtonRoute;
|
|
851
|
+
exports.Commands = require_cursor.Commands;
|
|
536
852
|
exports.ContextMenuRoute = ContextMenuRoute;
|
|
853
|
+
exports.ContextMenus = require_cursor.ContextMenus;
|
|
537
854
|
exports.Cooldown = Cooldown;
|
|
538
|
-
exports.
|
|
855
|
+
exports.CursorSource = CursorSource;
|
|
856
|
+
exports.CustomId = require_cursor.CustomId;
|
|
539
857
|
exports.DispatchContext = DispatchContext;
|
|
540
858
|
exports.DmOnly = DmOnly;
|
|
541
859
|
exports.Fault = Fault;
|
|
542
860
|
exports.GuildOnly = GuildOnly;
|
|
543
861
|
exports.ModalRoute = ModalRoute;
|
|
544
|
-
exports.Notice =
|
|
862
|
+
exports.Notice = require_cursor.Notice;
|
|
545
863
|
exports.OwnerOnly = OwnerOnly;
|
|
864
|
+
exports.PaginatorBase = PaginatorBase;
|
|
546
865
|
exports.RegisterCommand = RegisterCommand;
|
|
547
866
|
exports.RepliableHandler = RepliableHandler;
|
|
548
|
-
exports.RequireBotPermissions =
|
|
549
|
-
exports.RequirePermissions =
|
|
550
|
-
exports.RequireRole =
|
|
867
|
+
exports.RequireBotPermissions = require_cursor.RequireBotPermissions;
|
|
868
|
+
exports.RequirePermissions = require_cursor.RequirePermissions;
|
|
869
|
+
exports.RequireRole = require_cursor.RequireRole;
|
|
551
870
|
exports.RowComponent = require_publishDefault.RowComponent;
|
|
552
|
-
exports.SelectMenuKind =
|
|
871
|
+
exports.SelectMenuKind = require_cursor.SelectMenuKind;
|
|
553
872
|
exports.SelectMenuRoute = SelectMenuRoute;
|
|
554
873
|
exports.ShutdownPhase = require_phases.ShutdownPhase;
|
|
555
|
-
exports.Silence =
|
|
874
|
+
exports.Silence = require_cursor.Silence;
|
|
556
875
|
exports.SlashRoute = SlashRoute;
|
|
557
876
|
exports.StartupPhase = require_phases.StartupPhase;
|
|
558
877
|
exports.Subscribe = require_subscribers.Subscribe;
|
|
@@ -560,8 +879,10 @@ exports.Subscriber = require_subscribers.Subscriber;
|
|
|
560
879
|
exports.WebhookLog = require_subscribers.WebhookLog;
|
|
561
880
|
exports.WebhookUrl = require_subscribers.WebhookUrl;
|
|
562
881
|
exports.and = and;
|
|
563
|
-
exports.
|
|
564
|
-
exports.
|
|
882
|
+
exports.assertPermissions = assertPermissions;
|
|
883
|
+
exports.defineEffectGate = require_cursor.defineEffectGate;
|
|
884
|
+
exports.defineGate = require_cursor.defineGate;
|
|
885
|
+
exports.mergeRoles = mergeRoles;
|
|
565
886
|
exports.or = or;
|
|
566
887
|
exports.paginate = paginate;
|
|
567
888
|
exports.version = version;
|