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