@seedcord/core 0.1.0-next.6 → 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/HmrModuleHandler-3sNgKHdf.mjs +163 -0
- package/dist/HmrModuleHandler-3sNgKHdf.mjs.map +1 -0
- package/dist/HmrModuleHandler-CTBng7wV.cjs +170 -0
- package/dist/HmrModuleHandler-CTBng7wV.cjs.map +1 -0
- package/dist/Plugin-BZit5HUI.d.mts +555 -0
- package/dist/{Plugin-C2-VHrsX.cjs → Plugin-BlkhHNRm.cjs} +15 -34
- package/dist/Plugin-BlkhHNRm.cjs.map +1 -0
- package/dist/{Plugin-PcdPjAzc.mjs → Plugin-CDAV7P9l.mjs} +16 -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/{permissions-DSW_EZfN.cjs → cursor-BMkFAwO2.cjs} +308 -300
- package/dist/cursor-BMkFAwO2.cjs.map +1 -0
- package/dist/{permissions-RVCBhL2n.mjs → cursor-BvSH8tgw.mjs} +249 -247
- package/dist/cursor-BvSH8tgw.mjs.map +1 -0
- package/dist/{AutocompleteOptions-eKhIe6Qt.d.mts → cursor-D6nBjwaE.d.mts} +207 -116
- package/dist/hmr.index.cjs +2 -164
- package/dist/hmr.index.mjs +2 -162
- package/dist/index-Cr4-VV4u.d.mts +142 -0
- package/dist/index.cjs +362 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +239 -38
- package/dist/index.mjs +313 -26
- package/dist/index.mjs.map +1 -1
- package/dist/internal.index.cjs +278 -83
- package/dist/internal.index.cjs.map +1 -1
- package/dist/internal.index.d.mts +111 -42
- package/dist/internal.index.mjs +223 -43
- package/dist/internal.index.mjs.map +1 -1
- package/dist/node-internal.index.cjs +314 -76
- package/dist/node-internal.index.cjs.map +1 -1
- package/dist/node-internal.index.d.mts +123 -2164
- package/dist/node-internal.index.mjs +313 -77
- 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-CVlwYUS5.cjs +382 -0
- package/dist/publishDefault-CVlwYUS5.cjs.map +1 -0
- package/dist/publishDefault-CldnxcT2.mjs +287 -0
- 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-BSJoyKNN.cjs +517 -0
- package/dist/subscribers-BSJoyKNN.cjs.map +1 -0
- package/dist/subscribers-DuxdM2cS.mjs +480 -0
- package/dist/subscribers-DuxdM2cS.mjs.map +1 -0
- package/package.json +7 -6
- package/dist/Plugin-C2-VHrsX.cjs.map +0 -1
- package/dist/Plugin-CNyRKDHT.d.mts +0 -226
- package/dist/Plugin-PcdPjAzc.mjs.map +0 -1
- package/dist/hmr.index.cjs.map +0 -1
- package/dist/hmr.index.mjs.map +0 -1
- package/dist/is-never-Ddaba1Su.d.mts +0 -58
- package/dist/permissions-DSW_EZfN.cjs.map +0 -1
- package/dist/permissions-RVCBhL2n.mjs.map +0 -1
- package/dist/phases-BfpAG6w3.mjs.map +0 -1
- package/dist/phases-C_BGNyVo.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const
|
|
3
|
-
const
|
|
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');
|
|
4
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");
|
|
5
10
|
let _seedcord_errors = require("@seedcord/errors");
|
|
6
11
|
let _seedcord_errors_internal = require("@seedcord/errors/internal");
|
|
7
|
-
let _seedcord_logger = require("@seedcord/logger");
|
|
8
12
|
let _seedcord_utils = require("@seedcord/utils");
|
|
9
13
|
|
|
10
14
|
//#region src/decorators/Command.ts
|
|
11
15
|
function RegisterCommand(scope, guilds = []) {
|
|
12
16
|
return (ctor) => {
|
|
13
|
-
const existingMeta = Reflect.getOwnMetadata(
|
|
17
|
+
const existingMeta = Reflect.getOwnMetadata(require_publishDefault.CommandMetadataKey, ctor);
|
|
14
18
|
if (existingMeta) throw new _seedcord_errors_internal.SeedcordError(_seedcord_errors.SeedcordErrorCode.DecoratorCommandAlreadyRegistered, [
|
|
15
19
|
ctor.name,
|
|
16
20
|
existingMeta.scope,
|
|
@@ -22,7 +26,7 @@ function RegisterCommand(scope, guilds = []) {
|
|
|
22
26
|
scope,
|
|
23
27
|
guilds
|
|
24
28
|
};
|
|
25
|
-
Reflect.defineMetadata(
|
|
29
|
+
Reflect.defineMetadata(require_publishDefault.CommandMetadataKey, meta, ctor);
|
|
26
30
|
};
|
|
27
31
|
}
|
|
28
32
|
|
|
@@ -49,7 +53,7 @@ function RegisterCommand(scope, guilds = []) {
|
|
|
49
53
|
*/
|
|
50
54
|
function SlashRoute(...routes) {
|
|
51
55
|
return function(constructor) {
|
|
52
|
-
|
|
56
|
+
require_cursor.storeInteractionRoute("slash", routes, constructor);
|
|
53
57
|
};
|
|
54
58
|
}
|
|
55
59
|
/**
|
|
@@ -74,7 +78,7 @@ function SlashRoute(...routes) {
|
|
|
74
78
|
*/
|
|
75
79
|
function AutocompleteRoute(...routes) {
|
|
76
80
|
return function(constructor) {
|
|
77
|
-
|
|
81
|
+
require_cursor.storeInteractionRoute("autocomplete", routes, constructor);
|
|
78
82
|
};
|
|
79
83
|
}
|
|
80
84
|
/**
|
|
@@ -100,7 +104,7 @@ function AutocompleteRoute(...routes) {
|
|
|
100
104
|
*/
|
|
101
105
|
function ContextMenuRoute(kind, ...names) {
|
|
102
106
|
return function(constructor) {
|
|
103
|
-
|
|
107
|
+
require_cursor.storeInteractionRoute(require_cursor.contextMenuRouteOf(kind), names, constructor);
|
|
104
108
|
};
|
|
105
109
|
}
|
|
106
110
|
/**
|
|
@@ -116,7 +120,7 @@ function ContextMenuRoute(kind, ...names) {
|
|
|
116
120
|
*/
|
|
117
121
|
function ButtonRoute(...defs) {
|
|
118
122
|
return function(constructor) {
|
|
119
|
-
|
|
123
|
+
require_cursor.storeComponentRoute("button", defs, constructor);
|
|
120
124
|
};
|
|
121
125
|
}
|
|
122
126
|
/**
|
|
@@ -132,7 +136,7 @@ function ButtonRoute(...defs) {
|
|
|
132
136
|
*/
|
|
133
137
|
function ModalRoute(...defs) {
|
|
134
138
|
return function(constructor) {
|
|
135
|
-
|
|
139
|
+
require_cursor.storeComponentRoute("modal", defs, constructor);
|
|
136
140
|
};
|
|
137
141
|
}
|
|
138
142
|
/**
|
|
@@ -153,7 +157,7 @@ function ModalRoute(...defs) {
|
|
|
153
157
|
*/
|
|
154
158
|
function SelectMenuRoute(type, ...defs) {
|
|
155
159
|
return function(constructor) {
|
|
156
|
-
|
|
160
|
+
require_cursor.storeComponentRoute(require_cursor.selectMenuRouteOf(type), defs, constructor);
|
|
157
161
|
};
|
|
158
162
|
}
|
|
159
163
|
|
|
@@ -192,10 +196,10 @@ var BaseHandler = class {
|
|
|
192
196
|
event;
|
|
193
197
|
logger;
|
|
194
198
|
dispatch;
|
|
195
|
-
constructor(event, core, dispatch) {
|
|
199
|
+
constructor(event, core, dispatch, channel) {
|
|
196
200
|
this.core = core;
|
|
197
201
|
this.event = event;
|
|
198
|
-
this.logger = new _seedcord_logger.Logger(this.constructor.name);
|
|
202
|
+
this.logger = new _seedcord_logger.Logger(this.constructor.name, { channel });
|
|
199
203
|
this.dispatch = dispatch;
|
|
200
204
|
}
|
|
201
205
|
};
|
|
@@ -215,7 +219,7 @@ var RepliableHandler = class extends BaseHandler {
|
|
|
215
219
|
sender;
|
|
216
220
|
routeId;
|
|
217
221
|
constructor(event, core, dispatch) {
|
|
218
|
-
super(event, core, dispatch);
|
|
222
|
+
super(event, core, dispatch, "interactions");
|
|
219
223
|
this.routeId = dispatch?.routeId ?? this.constructor.name;
|
|
220
224
|
this.sender = this.buildSender(event, core, this.routeId);
|
|
221
225
|
}
|
|
@@ -278,21 +282,21 @@ var RepliableHandler = class extends BaseHandler {
|
|
|
278
282
|
* }
|
|
279
283
|
* ```
|
|
280
284
|
*/
|
|
281
|
-
var Fault = class extends
|
|
285
|
+
var Fault = class extends require_cursor.Notice {
|
|
282
286
|
constructor(options) {
|
|
283
287
|
super("A fault occurred", options?.cause === void 0 ? void 0 : { cause: options.cause });
|
|
284
288
|
this.report = options?.report ?? true;
|
|
285
289
|
}
|
|
286
290
|
render(ctx) {
|
|
287
|
-
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] };
|
|
288
292
|
}
|
|
289
293
|
};
|
|
290
294
|
|
|
291
295
|
//#endregion
|
|
292
296
|
//#region src/gates/combinators.ts
|
|
293
297
|
function and(...gates) {
|
|
294
|
-
return
|
|
295
|
-
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);
|
|
296
300
|
});
|
|
297
301
|
}
|
|
298
302
|
function isOrOptions(arg) {
|
|
@@ -302,17 +306,17 @@ function or(...args) {
|
|
|
302
306
|
const last = args.at(-1);
|
|
303
307
|
const options = last !== void 0 && isOrOptions(last) ? last : void 0;
|
|
304
308
|
const gates = options ? args.slice(0, -1) : args;
|
|
305
|
-
return
|
|
309
|
+
return require_cursor.defineGate(gates.map((gate) => gate.name).join(" | "), async (ctx) => {
|
|
306
310
|
const summaries = [];
|
|
307
311
|
let everyArmHasSummary = true;
|
|
308
312
|
for (const gate of gates) {
|
|
309
|
-
const mark =
|
|
313
|
+
const mark = require_cursor.markCommits(ctx);
|
|
310
314
|
try {
|
|
311
|
-
await
|
|
315
|
+
await require_cursor.runCheck(gate, ctx);
|
|
312
316
|
return;
|
|
313
317
|
} catch (error) {
|
|
314
|
-
if (error instanceof
|
|
315
|
-
|
|
318
|
+
if (error instanceof require_cursor.Notice && !(error instanceof Fault) && !error.report) {
|
|
319
|
+
require_cursor.rollbackCommits(ctx, mark);
|
|
316
320
|
if (error.summary === void 0) everyArmHasSummary = false;
|
|
317
321
|
else summaries.push(error.summary);
|
|
318
322
|
continue;
|
|
@@ -321,8 +325,8 @@ function or(...args) {
|
|
|
321
325
|
}
|
|
322
326
|
}
|
|
323
327
|
if (options) throw typeof options.fail === "function" ? options.fail(ctx) : options.fail;
|
|
324
|
-
if (everyArmHasSummary && summaries.length > 0) throw new
|
|
325
|
-
throw new
|
|
328
|
+
if (everyArmHasSummary && summaries.length > 0) throw new require_cursor.NeedsAny(summaries);
|
|
329
|
+
throw new require_cursor.NotAllowed();
|
|
326
330
|
});
|
|
327
331
|
}
|
|
328
332
|
|
|
@@ -355,10 +359,10 @@ function or(...args) {
|
|
|
355
359
|
* ```
|
|
356
360
|
*/
|
|
357
361
|
function OwnerOnly(options) {
|
|
358
|
-
return
|
|
362
|
+
return require_cursor.defineGate("OwnerOnly", (ctx) => {
|
|
359
363
|
const owners = ctx.core.config.ownerIds ?? [];
|
|
360
364
|
if (ctx.userId !== null && owners.includes(ctx.userId)) return;
|
|
361
|
-
throw
|
|
365
|
+
throw require_cursor.pickNotice(options, (message) => new require_cursor.NotOwner(message));
|
|
362
366
|
});
|
|
363
367
|
}
|
|
364
368
|
/**
|
|
@@ -384,9 +388,9 @@ function OwnerOnly(options) {
|
|
|
384
388
|
* ```
|
|
385
389
|
*/
|
|
386
390
|
function GuildOnly(options) {
|
|
387
|
-
return
|
|
391
|
+
return require_cursor.defineGate("GuildOnly", (ctx) => {
|
|
388
392
|
if (ctx.guildId) return;
|
|
389
|
-
throw
|
|
393
|
+
throw require_cursor.pickNotice(options, (message) => new require_cursor.NotInGuild(message));
|
|
390
394
|
});
|
|
391
395
|
}
|
|
392
396
|
/**
|
|
@@ -410,9 +414,9 @@ function GuildOnly(options) {
|
|
|
410
414
|
* ```
|
|
411
415
|
*/
|
|
412
416
|
function DmOnly(options) {
|
|
413
|
-
return
|
|
417
|
+
return require_cursor.defineGate("DmOnly", (ctx) => {
|
|
414
418
|
if (!ctx.guildId) return;
|
|
415
|
-
throw
|
|
419
|
+
throw require_cursor.pickNotice(options, (message) => new require_cursor.NotInDm(message));
|
|
416
420
|
});
|
|
417
421
|
}
|
|
418
422
|
|
|
@@ -484,44 +488,123 @@ function Cooldown(duration, options) {
|
|
|
484
488
|
};
|
|
485
489
|
const anonId = anonSeq++;
|
|
486
490
|
const keyOf = (ctx) => `cooldown:${ctx.routeId ?? `anon${anonId}`}:${per}:w${windowMs}:l${options?.limit ?? 1}:${scopeValue(ctx, per)}`;
|
|
487
|
-
return
|
|
491
|
+
return require_cursor.defineEffectGate("Cooldown", async (ctx) => {
|
|
488
492
|
const result = await ctx.core.rateLimiter.peek(keyOf(ctx), window);
|
|
489
493
|
if (!result.limited) return;
|
|
490
494
|
if (options?.notice) throw options.notice(result.resetAt);
|
|
491
|
-
throw new
|
|
495
|
+
throw new require_cursor.OnCooldown(result.resetAt, options?.message?.(result.resetAt));
|
|
492
496
|
}, async (ctx) => {
|
|
493
497
|
await ctx.core.rateLimiter.charge(keyOf(ctx), window);
|
|
494
498
|
});
|
|
495
499
|
}
|
|
496
500
|
|
|
497
501
|
//#endregion
|
|
498
|
-
//#region src/
|
|
502
|
+
//#region src/permissions/assert.ts
|
|
499
503
|
/**
|
|
500
|
-
*
|
|
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`.
|
|
501
506
|
*
|
|
502
|
-
* The
|
|
503
|
-
*
|
|
504
|
-
*
|
|
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.
|
|
505
511
|
*
|
|
506
512
|
* @example
|
|
507
513
|
* ```ts
|
|
508
|
-
* import {
|
|
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
|
+
* ```
|
|
509
524
|
*
|
|
510
|
-
*
|
|
511
|
-
*
|
|
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
|
+
* });
|
|
512
571
|
* ```
|
|
513
572
|
*/
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
super(reason ?? "Silence");
|
|
521
|
-
this.reason = reason;
|
|
522
|
-
Error.captureStackTrace(this, this.constructor);
|
|
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);
|
|
523
579
|
}
|
|
524
|
-
|
|
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
|
+
}
|
|
525
608
|
|
|
526
609
|
//#endregion
|
|
527
610
|
//#region src/pagination/paginate.ts
|
|
@@ -549,41 +632,257 @@ function paginate(items, page, perPage) {
|
|
|
549
632
|
};
|
|
550
633
|
}
|
|
551
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
|
+
|
|
552
839
|
//#endregion
|
|
553
840
|
//#region src/index.ts
|
|
554
841
|
/** Package version */
|
|
555
|
-
const version = "0.1.0-next.
|
|
842
|
+
const version = "0.1.0-next.8";
|
|
556
843
|
|
|
557
844
|
//#endregion
|
|
845
|
+
exports.ArraySource = ArraySource;
|
|
558
846
|
exports.AutocompleteRoute = AutocompleteRoute;
|
|
559
847
|
exports.BaseHandler = BaseHandler;
|
|
560
|
-
exports.BuilderComponent =
|
|
848
|
+
exports.BuilderComponent = require_publishDefault.BuilderComponent;
|
|
849
|
+
exports.Bus = require_subscribers.Bus;
|
|
561
850
|
exports.ButtonRoute = ButtonRoute;
|
|
851
|
+
exports.Commands = require_cursor.Commands;
|
|
562
852
|
exports.ContextMenuRoute = ContextMenuRoute;
|
|
853
|
+
exports.ContextMenus = require_cursor.ContextMenus;
|
|
563
854
|
exports.Cooldown = Cooldown;
|
|
564
|
-
exports.
|
|
855
|
+
exports.CursorSource = CursorSource;
|
|
856
|
+
exports.CustomId = require_cursor.CustomId;
|
|
565
857
|
exports.DispatchContext = DispatchContext;
|
|
566
858
|
exports.DmOnly = DmOnly;
|
|
567
859
|
exports.Fault = Fault;
|
|
568
860
|
exports.GuildOnly = GuildOnly;
|
|
569
861
|
exports.ModalRoute = ModalRoute;
|
|
570
|
-
exports.Notice =
|
|
862
|
+
exports.Notice = require_cursor.Notice;
|
|
571
863
|
exports.OwnerOnly = OwnerOnly;
|
|
864
|
+
exports.PaginatorBase = PaginatorBase;
|
|
572
865
|
exports.RegisterCommand = RegisterCommand;
|
|
573
866
|
exports.RepliableHandler = RepliableHandler;
|
|
574
|
-
exports.RequireBotPermissions =
|
|
575
|
-
exports.RequirePermissions =
|
|
576
|
-
exports.RequireRole =
|
|
577
|
-
exports.RowComponent =
|
|
578
|
-
exports.SelectMenuKind =
|
|
867
|
+
exports.RequireBotPermissions = require_cursor.RequireBotPermissions;
|
|
868
|
+
exports.RequirePermissions = require_cursor.RequirePermissions;
|
|
869
|
+
exports.RequireRole = require_cursor.RequireRole;
|
|
870
|
+
exports.RowComponent = require_publishDefault.RowComponent;
|
|
871
|
+
exports.SelectMenuKind = require_cursor.SelectMenuKind;
|
|
579
872
|
exports.SelectMenuRoute = SelectMenuRoute;
|
|
580
873
|
exports.ShutdownPhase = require_phases.ShutdownPhase;
|
|
581
|
-
exports.Silence = Silence;
|
|
874
|
+
exports.Silence = require_cursor.Silence;
|
|
582
875
|
exports.SlashRoute = SlashRoute;
|
|
583
876
|
exports.StartupPhase = require_phases.StartupPhase;
|
|
877
|
+
exports.Subscribe = require_subscribers.Subscribe;
|
|
878
|
+
exports.Subscriber = require_subscribers.Subscriber;
|
|
879
|
+
exports.WebhookLog = require_subscribers.WebhookLog;
|
|
880
|
+
exports.WebhookUrl = require_subscribers.WebhookUrl;
|
|
584
881
|
exports.and = and;
|
|
585
|
-
exports.
|
|
586
|
-
exports.
|
|
882
|
+
exports.assertPermissions = assertPermissions;
|
|
883
|
+
exports.defineEffectGate = require_cursor.defineEffectGate;
|
|
884
|
+
exports.defineGate = require_cursor.defineGate;
|
|
885
|
+
exports.mergeRoles = mergeRoles;
|
|
587
886
|
exports.or = or;
|
|
588
887
|
exports.paginate = paginate;
|
|
589
888
|
exports.version = version;
|