@seedcord/core 0.3.1 → 0.4.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/{Bus-BvF4VShN.mjs → Bus-BVwmKc-A.mjs} +36 -17
- package/dist/Bus-BVwmKc-A.mjs.map +1 -0
- package/dist/Pluggable-Cf5-WWmW.mjs +280 -0
- package/dist/Pluggable-Cf5-WWmW.mjs.map +1 -0
- package/dist/Pluggable-DFNUIlJM.d.mts +148 -0
- package/dist/{Plugin-D9ykXA5g.mjs → Plugin-C6oMqWf8.mjs} +7 -3
- package/dist/Plugin-C6oMqWf8.mjs.map +1 -0
- package/dist/{Plugin-CQ9IEj5X.d.mts → Plugin-CG9pWbPF.d.mts} +2 -2
- package/dist/{cursor-BANzac53.d.mts → cursor-BcRfmTSo.d.mts} +26 -72
- package/dist/{cursor-CuoA9cRh.mjs → cursor-GBUYz3jk.mjs} +378 -30
- package/dist/cursor-GBUYz3jk.mjs.map +1 -0
- package/dist/{index-rt8rZg4d.d.mts → index-ZzdQafFv.d.mts} +2 -2
- package/dist/index.d.mts +77 -19
- package/dist/index.mjs +186 -19
- package/dist/index.mjs.map +1 -1
- package/dist/internal.index.d.mts +11 -5
- package/dist/internal.index.mjs +8 -455
- package/dist/internal.index.mjs.map +1 -1
- package/dist/node-internal.index.d.mts +6 -133
- package/dist/node-internal.index.mjs +15 -472
- package/dist/node-internal.index.mjs.map +1 -1
- package/dist/node.index.d.mts +2 -0
- package/dist/node.index.mjs +256 -0
- package/dist/node.index.mjs.map +1 -0
- package/dist/{phases-hBxMCD2V.d.mts → phases-F8yvPd60.d.mts} +104 -72
- package/dist/plugin.index.d.mts +1 -1
- package/dist/plugin.index.mjs +1 -1
- package/dist/publishDefault-D826XXDQ.mjs +14 -0
- package/dist/publishDefault-D826XXDQ.mjs.map +1 -0
- package/dist/{slashRouteLeaves-De1SxqnX.mjs → slashRouteLeaves-CbYRwqMY.mjs} +10 -2
- package/dist/slashRouteLeaves-CbYRwqMY.mjs.map +1 -0
- package/dist/{subscribers-wnMyNYZd.mjs → subscribers-CGGQkUfM.mjs} +2 -2
- package/dist/{subscribers-wnMyNYZd.mjs.map → subscribers-CGGQkUfM.mjs.map} +1 -1
- package/package.json +14 -8
- package/dist/Bus-BvF4VShN.mjs.map +0 -1
- package/dist/Plugin-D9ykXA5g.mjs.map +0 -1
- package/dist/cursor-CuoA9cRh.mjs.map +0 -1
- package/dist/slashRouteLeaves-De1SxqnX.mjs.map +0 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as InteractionMetadataKey, T as InteractionRoutes, g as BuilderComponent, w as InteractionRouteKeys } from "./Bus-BVwmKc-A.mjs";
|
|
2
|
+
import { n as asError, t as PublishDefault } from "./publishDefault-D826XXDQ.mjs";
|
|
2
3
|
import "reflect-metadata";
|
|
3
4
|
import { TextDisplayBuilder } from "@discordjs/builders";
|
|
4
|
-
import { SeedcordErrorCode } from "@seedcord/errors";
|
|
5
|
+
import { SeedcordErrorCode, paint } from "@seedcord/errors";
|
|
6
|
+
import { Logger } from "@seedcord/logger";
|
|
5
7
|
import { ApplicationCommandType, PermissionFlagsBits } from "discord-api-types/v10";
|
|
6
|
-
import { SeedcordError, SeedcordRangeError } from "@seedcord/errors/internal";
|
|
8
|
+
import { SeedcordError, SeedcordRangeError, SeedcordTypeError } from "@seedcord/errors/internal";
|
|
7
9
|
import { prettify, toEpochSeconds } from "@seedcord/utils";
|
|
8
10
|
|
|
9
11
|
//#region src/stops/Notice.ts
|
|
@@ -60,8 +62,9 @@ var Notice = class extends Error {
|
|
|
60
62
|
*/
|
|
61
63
|
ephemeral = true;
|
|
62
64
|
/**
|
|
63
|
-
* A short one-line reason. When every arm of an
|
|
64
|
-
*
|
|
65
|
+
* A short one-line reason. When every arm of an {@link or} gate refuses and each one sets this, `or`
|
|
66
|
+
* throws a refusal listing them under `You need to meet at least one of these:`. Write a verb phrase that
|
|
67
|
+
* finishes that line, for example, "be the bot owner".
|
|
65
68
|
*/
|
|
66
69
|
summary;
|
|
67
70
|
constructor(message, options) {
|
|
@@ -181,6 +184,9 @@ function isBounded(field) {
|
|
|
181
184
|
return field.kind === "snowflake" || field.kind === "uuid" || field.kind === "bool" || field.kind === "oneOf";
|
|
182
185
|
}
|
|
183
186
|
function radixOf(field) {
|
|
187
|
+
return kindRadix(field) + (field.nullable === true ? 1n : 0n);
|
|
188
|
+
}
|
|
189
|
+
function kindRadix(field) {
|
|
184
190
|
switch (field.kind) {
|
|
185
191
|
case "snowflake": return 1n << 64n;
|
|
186
192
|
case "uuid": return 1n << 128n;
|
|
@@ -195,6 +201,13 @@ function radixOf(field) {
|
|
|
195
201
|
}
|
|
196
202
|
}
|
|
197
203
|
function boundedToBigint(field, name, value) {
|
|
204
|
+
if (field.nullable === true) {
|
|
205
|
+
if (value === null) return 0n;
|
|
206
|
+
return boundedToBigint({
|
|
207
|
+
...field,
|
|
208
|
+
nullable: false
|
|
209
|
+
}, name, value) + 1n;
|
|
210
|
+
}
|
|
198
211
|
const slot = boundedSlot(field, name, value);
|
|
199
212
|
if (slot < 0n || slot >= radixOf(field)) outOfRange(name, value);
|
|
200
213
|
return slot;
|
|
@@ -225,6 +238,13 @@ function outOfRange(name, value) {
|
|
|
225
238
|
throw new SeedcordRangeError(SeedcordErrorCode.CustomIdValueOutOfRange, [name, String(value)]);
|
|
226
239
|
}
|
|
227
240
|
function bigintToBoundedValue(field, slot) {
|
|
241
|
+
if (field.nullable === true) return slot === 0n ? null : bigintToBoundedValue({
|
|
242
|
+
...field,
|
|
243
|
+
nullable: false
|
|
244
|
+
}, slot - 1n);
|
|
245
|
+
return kindValue(field, slot);
|
|
246
|
+
}
|
|
247
|
+
function kindValue(field, slot) {
|
|
228
248
|
switch (field.kind) {
|
|
229
249
|
case "snowflake": return slot.toString();
|
|
230
250
|
case "uuid": return bigintToUuid(slot);
|
|
@@ -238,7 +258,16 @@ function bigintToUuid(value) {
|
|
|
238
258
|
const hex = value.toString(16).padStart(32, "0");
|
|
239
259
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
240
260
|
}
|
|
261
|
+
const ABSENT = "0";
|
|
262
|
+
const PRESENT = "1";
|
|
241
263
|
function encodeUnboundedToken(field, name, value) {
|
|
264
|
+
if (field.nullable === true) {
|
|
265
|
+
if (value === null) return ABSENT;
|
|
266
|
+
return PRESENT + encodeUnboundedToken({
|
|
267
|
+
...field,
|
|
268
|
+
nullable: false
|
|
269
|
+
}, name, value);
|
|
270
|
+
}
|
|
242
271
|
if (field.kind === "int") {
|
|
243
272
|
if (!Number.isSafeInteger(value)) outOfRange(name, value);
|
|
244
273
|
return bigintToBase64(zigzagEncode(value));
|
|
@@ -246,6 +275,15 @@ function encodeUnboundedToken(field, name, value) {
|
|
|
246
275
|
return escapeToken(value);
|
|
247
276
|
}
|
|
248
277
|
function decodeUnboundedToken(field, piece) {
|
|
278
|
+
if (field.nullable === true) {
|
|
279
|
+
const marker = piece.charAt(0);
|
|
280
|
+
if (marker === ABSENT && piece.length === 1) return null;
|
|
281
|
+
if (marker !== PRESENT) throw new InvalidCustomId(`bad presence marker ${JSON.stringify(marker)}`);
|
|
282
|
+
return decodeUnboundedToken({
|
|
283
|
+
...field,
|
|
284
|
+
nullable: false
|
|
285
|
+
}, piece.slice(1));
|
|
286
|
+
}
|
|
249
287
|
if (field.kind !== "int") return unescapeToken(piece);
|
|
250
288
|
if (piece === "") throw new InvalidCustomId("empty integer token");
|
|
251
289
|
const decoded = zigzagDecode(base64ToBigint(piece));
|
|
@@ -258,6 +296,7 @@ function computeLayoutHash(shape) {
|
|
|
258
296
|
name,
|
|
259
297
|
field.kind,
|
|
260
298
|
isBounded(field),
|
|
299
|
+
field.nullable === true,
|
|
261
300
|
field.kind === "oneOf" ? field.choices ?? [] : null,
|
|
262
301
|
field.kind === "int" ? [field.min ?? null, field.max ?? null] : null
|
|
263
302
|
]));
|
|
@@ -363,14 +402,14 @@ var CustomId = class CustomId {
|
|
|
363
402
|
/** The prefix plus a short hash of the shape, the part of the wire before the colon. */
|
|
364
403
|
routeKey;
|
|
365
404
|
constructor(prefix, shape = {}) {
|
|
366
|
-
if (!prefix || /[:\x1B\x1F]/.test(prefix)) throw new
|
|
405
|
+
if (!prefix || /[:\x1B\x1F]/.test(prefix)) throw new SeedcordTypeError(SeedcordErrorCode.CustomIdInvalidPrefix, [prefix]);
|
|
367
406
|
this.prefix = prefix;
|
|
368
407
|
this.shape = shape;
|
|
369
408
|
this.routeKey = prefix + computeLayoutHash(shape);
|
|
370
409
|
}
|
|
371
410
|
add(name, field) {
|
|
372
|
-
if (/^(?:0|[1-9]\d*)$/.test(name)) throw new
|
|
373
|
-
if (name in this.shape) throw new
|
|
411
|
+
if (/^(?:0|[1-9]\d*)$/.test(name)) throw new SeedcordTypeError(SeedcordErrorCode.CustomIdReservedFieldName, [name]);
|
|
412
|
+
if (name in this.shape) throw new SeedcordTypeError(SeedcordErrorCode.CustomIdDuplicateFieldName, [name]);
|
|
374
413
|
const shape = {
|
|
375
414
|
...this.shape,
|
|
376
415
|
[name]: field
|
|
@@ -385,8 +424,11 @@ var CustomId = class CustomId {
|
|
|
385
424
|
* new CustomId('ban').snowflake('userId');
|
|
386
425
|
* ```
|
|
387
426
|
*/
|
|
388
|
-
snowflake(name) {
|
|
389
|
-
return this.add(name, {
|
|
427
|
+
snowflake(name, opts) {
|
|
428
|
+
return this.add(name, {
|
|
429
|
+
...opts,
|
|
430
|
+
kind: "snowflake"
|
|
431
|
+
});
|
|
390
432
|
}
|
|
391
433
|
/**
|
|
392
434
|
* Add a UUID field, decoded as a lowercase uuid string.
|
|
@@ -396,21 +438,29 @@ var CustomId = class CustomId {
|
|
|
396
438
|
* new CustomId('ticket').uuid('ticketId');
|
|
397
439
|
* ```
|
|
398
440
|
*/
|
|
399
|
-
uuid(name) {
|
|
400
|
-
return this.add(name, {
|
|
441
|
+
uuid(name, opts) {
|
|
442
|
+
return this.add(name, {
|
|
443
|
+
...opts,
|
|
444
|
+
kind: "uuid"
|
|
445
|
+
});
|
|
401
446
|
}
|
|
402
|
-
int(name,
|
|
403
|
-
|
|
447
|
+
int(name, minOrOpts, max, opts) {
|
|
448
|
+
const min = typeof minOrOpts === "number" ? minOrOpts : void 0;
|
|
449
|
+
if (min !== void 0 && max !== void 0 && min > max) throw new SeedcordRangeError(SeedcordErrorCode.CustomIdInvalidBounds, [
|
|
404
450
|
name,
|
|
405
451
|
min,
|
|
406
452
|
max
|
|
407
453
|
]);
|
|
408
|
-
const
|
|
409
|
-
|
|
454
|
+
const options = typeof minOrOpts === "number" ? opts : minOrOpts;
|
|
455
|
+
const bounds = min === void 0 || max === void 0 ? {} : {
|
|
410
456
|
min,
|
|
411
457
|
max
|
|
412
458
|
};
|
|
413
|
-
return this.add(name,
|
|
459
|
+
return this.add(name, {
|
|
460
|
+
...options,
|
|
461
|
+
kind: "int",
|
|
462
|
+
...bounds
|
|
463
|
+
});
|
|
414
464
|
}
|
|
415
465
|
/**
|
|
416
466
|
* Add a boolean flag.
|
|
@@ -420,8 +470,11 @@ var CustomId = class CustomId {
|
|
|
420
470
|
* new CustomId('settings').bool('silent');
|
|
421
471
|
* ```
|
|
422
472
|
*/
|
|
423
|
-
bool(name) {
|
|
424
|
-
return this.add(name, {
|
|
473
|
+
bool(name, opts) {
|
|
474
|
+
return this.add(name, {
|
|
475
|
+
...opts,
|
|
476
|
+
kind: "bool"
|
|
477
|
+
});
|
|
425
478
|
}
|
|
426
479
|
/**
|
|
427
480
|
* Add a field that is one value from a fixed list, decoded as the literal union. No `as const` needed.
|
|
@@ -431,9 +484,10 @@ var CustomId = class CustomId {
|
|
|
431
484
|
* new CustomId('poll').oneOf('choice', ['yes', 'no', 'abstain']);
|
|
432
485
|
* ```
|
|
433
486
|
*/
|
|
434
|
-
oneOf(name, choices) {
|
|
435
|
-
if (choices.length === 0) throw new
|
|
487
|
+
oneOf(name, choices, opts) {
|
|
488
|
+
if (choices.length === 0) throw new SeedcordRangeError(SeedcordErrorCode.CustomIdEmptyChoices, [name]);
|
|
436
489
|
return this.add(name, {
|
|
490
|
+
...opts,
|
|
437
491
|
kind: "oneOf",
|
|
438
492
|
choices
|
|
439
493
|
});
|
|
@@ -447,8 +501,11 @@ var CustomId = class CustomId {
|
|
|
447
501
|
* new CustomId('note').str('message');
|
|
448
502
|
* ```
|
|
449
503
|
*/
|
|
450
|
-
str(name) {
|
|
451
|
-
return this.add(name, {
|
|
504
|
+
str(name, opts) {
|
|
505
|
+
return this.add(name, {
|
|
506
|
+
...opts,
|
|
507
|
+
kind: "string"
|
|
508
|
+
});
|
|
452
509
|
}
|
|
453
510
|
/**
|
|
454
511
|
* Mint a wire string from values. Throws if a value is out of its field's range or the wire is over 100 chars.
|
|
@@ -566,6 +623,285 @@ function contextMenuRouteOf(kind) {
|
|
|
566
623
|
return kind === ApplicationCommandType.User ? "userContextMenu" : "messageContextMenu";
|
|
567
624
|
}
|
|
568
625
|
|
|
626
|
+
//#endregion
|
|
627
|
+
//#region src/reply/ackLegality.ts
|
|
628
|
+
const showModalReason = {
|
|
629
|
+
reason: "this interaction was already acknowledged",
|
|
630
|
+
alternative: "showModal() must be the initial response."
|
|
631
|
+
};
|
|
632
|
+
function deferReason(what) {
|
|
633
|
+
return {
|
|
634
|
+
reason: `this interaction was already acknowledged with ${what}`,
|
|
635
|
+
alternative: "A deferral can only be the initial response."
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
const ILLEGAL = {
|
|
639
|
+
reply: {
|
|
640
|
+
"deferred-reply": {
|
|
641
|
+
reason: "this interaction was already deferred",
|
|
642
|
+
alternative: "Use edit() to fill the deferred reply or followUp() for a new message."
|
|
643
|
+
},
|
|
644
|
+
"deferred-update": {
|
|
645
|
+
reason: "this interaction was already acknowledged with a deferred update",
|
|
646
|
+
alternative: "Use followUp() for a new message."
|
|
647
|
+
},
|
|
648
|
+
replied: {
|
|
649
|
+
reason: "this interaction was already replied to",
|
|
650
|
+
alternative: "Use followUp() for a new message or edit() to rewrite the reply."
|
|
651
|
+
}
|
|
652
|
+
},
|
|
653
|
+
defer: {
|
|
654
|
+
"deferred-reply": deferReason("a deferred reply"),
|
|
655
|
+
"deferred-update": deferReason("a deferred update"),
|
|
656
|
+
replied: deferReason("a reply")
|
|
657
|
+
},
|
|
658
|
+
deferUpdate: {
|
|
659
|
+
"deferred-reply": deferReason("a deferred reply"),
|
|
660
|
+
"deferred-update": deferReason("a deferred update"),
|
|
661
|
+
replied: deferReason("a reply")
|
|
662
|
+
},
|
|
663
|
+
update: {
|
|
664
|
+
"deferred-reply": {
|
|
665
|
+
reason: "this interaction was deferred as a reply",
|
|
666
|
+
alternative: "The placeholder is yours via edit(). update() rewrites a source message."
|
|
667
|
+
},
|
|
668
|
+
replied: {
|
|
669
|
+
reason: "this interaction was already replied to",
|
|
670
|
+
alternative: "update() rewrites a source message. Use edit() or followUp() instead."
|
|
671
|
+
}
|
|
672
|
+
},
|
|
673
|
+
followUp: { unacked: {
|
|
674
|
+
reason: "this interaction has not been acknowledged yet",
|
|
675
|
+
alternative: "Ack first with reply() or defer()."
|
|
676
|
+
} },
|
|
677
|
+
edit: { unacked: {
|
|
678
|
+
reason: "nothing has been sent yet",
|
|
679
|
+
alternative: "Send with reply() or defer() first, then edit() rewrites it."
|
|
680
|
+
} },
|
|
681
|
+
delete: { unacked: {
|
|
682
|
+
reason: "nothing has been sent yet",
|
|
683
|
+
alternative: "Acknowledge first with reply() or defer(), then delete() removes it."
|
|
684
|
+
} },
|
|
685
|
+
showModal: {
|
|
686
|
+
"deferred-reply": showModalReason,
|
|
687
|
+
"deferred-update": showModalReason,
|
|
688
|
+
replied: showModalReason
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
const SEND_TARGET = {
|
|
692
|
+
unacked: "reply",
|
|
693
|
+
"deferred-reply": "edit",
|
|
694
|
+
"deferred-update": "followUp",
|
|
695
|
+
replied: "followUp"
|
|
696
|
+
};
|
|
697
|
+
function checkAckLegality(method, state, routeId, ackedBy) {
|
|
698
|
+
if (method === "send") return;
|
|
699
|
+
const illegal = ILLEGAL[method][state];
|
|
700
|
+
if (!illegal) return;
|
|
701
|
+
throw new SeedcordError(SeedcordErrorCode.ReplyIllegalAckState, [
|
|
702
|
+
method,
|
|
703
|
+
illegal.reason,
|
|
704
|
+
illegal.alternative,
|
|
705
|
+
routeId
|
|
706
|
+
], { cause: ackedBy });
|
|
707
|
+
}
|
|
708
|
+
function sendTarget(state) {
|
|
709
|
+
return SEND_TARGET[state];
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
//#endregion
|
|
713
|
+
//#region src/reply/AckTrace.ts
|
|
714
|
+
var AckTrace = class extends Error {
|
|
715
|
+
constructor(method) {
|
|
716
|
+
super(`${method}() acknowledged this interaction`);
|
|
717
|
+
this.name = "AckTrace";
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
|
|
721
|
+
//#endregion
|
|
722
|
+
//#region src/reply/responseReport.ts
|
|
723
|
+
let replyLogger;
|
|
724
|
+
function logger() {
|
|
725
|
+
replyLogger ??= new Logger("Reply", { channel: "interactions" });
|
|
726
|
+
return replyLogger;
|
|
727
|
+
}
|
|
728
|
+
/** @internal */
|
|
729
|
+
function publishResponse(telemetry, report) {
|
|
730
|
+
const durationMs = performance.now() - report.startedAt;
|
|
731
|
+
const write = {
|
|
732
|
+
routeId: report.routeId,
|
|
733
|
+
interactionId: telemetry.interactionId,
|
|
734
|
+
method: report.method,
|
|
735
|
+
durationMs
|
|
736
|
+
};
|
|
737
|
+
telemetry.bus[PublishDefault]("responseAttempted", report.outcome === "failed" ? {
|
|
738
|
+
...write,
|
|
739
|
+
outcome: "failed",
|
|
740
|
+
messageId: null,
|
|
741
|
+
error: report.error
|
|
742
|
+
} : {
|
|
743
|
+
...write,
|
|
744
|
+
outcome: "sent",
|
|
745
|
+
messageId: report.messageId
|
|
746
|
+
});
|
|
747
|
+
logger().trace(`${paint.sky.bold(report.routeId)} ${report.method} ${report.outcome} ${paint.mute("in")} ${Math.round(durationMs)}ms`);
|
|
748
|
+
}
|
|
749
|
+
async function reportedWrite(telemetry, routeId, method, write) {
|
|
750
|
+
const startedAt = performance.now();
|
|
751
|
+
const result = await attemptWrite(telemetry, routeId, method, startedAt, write);
|
|
752
|
+
publishResponse(telemetry, {
|
|
753
|
+
routeId,
|
|
754
|
+
method,
|
|
755
|
+
startedAt,
|
|
756
|
+
outcome: "sent",
|
|
757
|
+
messageId: null
|
|
758
|
+
});
|
|
759
|
+
return result;
|
|
760
|
+
}
|
|
761
|
+
async function attemptWrite(telemetry, routeId, method, startedAt, write) {
|
|
762
|
+
try {
|
|
763
|
+
return await write();
|
|
764
|
+
} catch (caught) {
|
|
765
|
+
publishResponse(telemetry, {
|
|
766
|
+
routeId,
|
|
767
|
+
method,
|
|
768
|
+
startedAt,
|
|
769
|
+
outcome: "failed",
|
|
770
|
+
error: asError(caught)
|
|
771
|
+
});
|
|
772
|
+
throw caught;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
//#endregion
|
|
777
|
+
//#region src/reply/translateSerialization.ts
|
|
778
|
+
const MAX_DEPTH = 8;
|
|
779
|
+
const OPERATOR_WORD = {
|
|
780
|
+
"<=": "at most",
|
|
781
|
+
">=": "at least",
|
|
782
|
+
"<": "fewer than",
|
|
783
|
+
">": "more than"
|
|
784
|
+
};
|
|
785
|
+
const KIND_WORD = {
|
|
786
|
+
string: "a string",
|
|
787
|
+
number: "a number",
|
|
788
|
+
boolean: "a boolean",
|
|
789
|
+
bigint: "a bigint",
|
|
790
|
+
array: "a list",
|
|
791
|
+
tuple: "a list",
|
|
792
|
+
date: "a date",
|
|
793
|
+
object: "an object"
|
|
794
|
+
};
|
|
795
|
+
function asRecord(value) {
|
|
796
|
+
return typeof value === "object" && value !== null ? value : null;
|
|
797
|
+
}
|
|
798
|
+
function firstLine(message) {
|
|
799
|
+
if (typeof message !== "string") return "unknown validation failure";
|
|
800
|
+
return message.split("\n")[0] ?? message;
|
|
801
|
+
}
|
|
802
|
+
const GIVEN_PREVIEW_LIMIT = 40;
|
|
803
|
+
function gotPhrase(given) {
|
|
804
|
+
if (given === void 0) return "nothing";
|
|
805
|
+
if (given === null) return "null";
|
|
806
|
+
if (typeof given === "string") {
|
|
807
|
+
if (given.length === 0) return "an empty string";
|
|
808
|
+
if (given.length > GIVEN_PREVIEW_LIMIT) return `${given.length} characters`;
|
|
809
|
+
return JSON.stringify(given);
|
|
810
|
+
}
|
|
811
|
+
if (Array.isArray(given)) return given.length === 0 ? "an empty list" : `${given.length} items`;
|
|
812
|
+
if (typeof given === "number" || typeof given === "bigint" || typeof given === "boolean") return String(given);
|
|
813
|
+
if (typeof given === "object") return given.constructor?.name ?? "an object";
|
|
814
|
+
return typeof given;
|
|
815
|
+
}
|
|
816
|
+
function needPhrase(expected, given) {
|
|
817
|
+
const bounds = [...expected.matchAll(/expected(\.length)?\s*(<=|>=|<|>)\s*(\d+)/g)];
|
|
818
|
+
if (bounds.length === 0) return null;
|
|
819
|
+
return bounds.map(([, lengthPart, operator, limit]) => {
|
|
820
|
+
const word = OPERATOR_WORD[operator ?? ""] ?? operator ?? "";
|
|
821
|
+
if (!lengthPart) return `${word} ${limit}`;
|
|
822
|
+
const unit = typeof given === "string" ? "character" : "item";
|
|
823
|
+
return `${word} ${limit} ${Number(limit) === 1 ? unit : `${unit}s`}`;
|
|
824
|
+
}).join(" and ");
|
|
825
|
+
}
|
|
826
|
+
function instanceName(expected) {
|
|
827
|
+
if (typeof expected === "function" && expected.name) return expected.name;
|
|
828
|
+
return "specific class instance";
|
|
829
|
+
}
|
|
830
|
+
function describeLeaf(record) {
|
|
831
|
+
if (typeof record.constraint === "string") {
|
|
832
|
+
const need = typeof record.expected === "string" ? needPhrase(record.expected, record.given) : null;
|
|
833
|
+
if (need) return `need ${need}, got ${gotPhrase(record.given)}`;
|
|
834
|
+
return `${firstLine(record.message)}${"given" in record ? ` (got ${gotPhrase(record.given)})` : ""}`;
|
|
835
|
+
}
|
|
836
|
+
if (typeof record.expected === "function") return `need a ${instanceName(record.expected)}, got ${gotPhrase(record.given)}`;
|
|
837
|
+
if (typeof record.validator === "string") {
|
|
838
|
+
const kind = KIND_WORD[record.validator.replace(/^s\./, "").replace(/\(.*$/, "")];
|
|
839
|
+
if (kind) return `need ${kind}, got ${gotPhrase(record.given)}`;
|
|
840
|
+
return `${firstLine(record.message)}, got ${gotPhrase(record.given)}`;
|
|
841
|
+
}
|
|
842
|
+
return firstLine(record.message);
|
|
843
|
+
}
|
|
844
|
+
function describeUnion(branches, depth) {
|
|
845
|
+
const records = [];
|
|
846
|
+
for (const branch of branches) {
|
|
847
|
+
const record = asRecord(branch);
|
|
848
|
+
if (record) records.push(record);
|
|
849
|
+
}
|
|
850
|
+
const bounded = records.find((record) => typeof record.constraint === "string");
|
|
851
|
+
if (bounded) return describeLeaf(bounded);
|
|
852
|
+
const names = [];
|
|
853
|
+
let allInstances = records.length > 0;
|
|
854
|
+
for (const record of records) if (typeof record.expected === "function") names.push(instanceName(record.expected));
|
|
855
|
+
else allInstances = false;
|
|
856
|
+
if (allInstances) return `need a ${[...new Set(names)].join(" or ")}, got ${gotPhrase(records[0]?.given)}`;
|
|
857
|
+
return detailOf(branches[0], depth + 1);
|
|
858
|
+
}
|
|
859
|
+
function detailOf(value, depth) {
|
|
860
|
+
const record = asRecord(value);
|
|
861
|
+
if (!record || depth >= MAX_DEPTH) return firstLine(record?.message);
|
|
862
|
+
if (Array.isArray(record.errors) && record.errors.length > 0) {
|
|
863
|
+
const errors = record.errors;
|
|
864
|
+
const [first] = errors;
|
|
865
|
+
if (Array.isArray(first)) {
|
|
866
|
+
const [key, inner] = first;
|
|
867
|
+
return `${String(key)}: ${detailOf(inner, depth + 1)}`;
|
|
868
|
+
}
|
|
869
|
+
return describeUnion(errors, depth);
|
|
870
|
+
}
|
|
871
|
+
return describeLeaf(record);
|
|
872
|
+
}
|
|
873
|
+
function translateSerializationError(error, componentClass, index, routeId) {
|
|
874
|
+
const detail = detailOf(error, 0);
|
|
875
|
+
return new SeedcordError(SeedcordErrorCode.ReplyComponentSerialization, [
|
|
876
|
+
componentClass,
|
|
877
|
+
index,
|
|
878
|
+
detail,
|
|
879
|
+
routeId
|
|
880
|
+
], { cause: error });
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
//#endregion
|
|
884
|
+
//#region src/reply/serializeReply.ts
|
|
885
|
+
function serializeReply(response, routeId) {
|
|
886
|
+
if (typeof response === "string") try {
|
|
887
|
+
return { components: [new TextDisplayBuilder().setContent(response).toJSON()] };
|
|
888
|
+
} catch (error) {
|
|
889
|
+
throw translateSerializationError(error, "TextDisplayBuilder", 0, routeId);
|
|
890
|
+
}
|
|
891
|
+
return {
|
|
892
|
+
components: response.components.map((component, index) => {
|
|
893
|
+
try {
|
|
894
|
+
return component.toJSON();
|
|
895
|
+
} catch (error) {
|
|
896
|
+
const name = component.constructor?.name;
|
|
897
|
+
throw translateSerializationError(error, !name || name === "Object" ? "component" : name, index, routeId);
|
|
898
|
+
}
|
|
899
|
+
}),
|
|
900
|
+
...response.allowedMentions && { allowedMentions: response.allowedMentions },
|
|
901
|
+
...response.files && { files: response.files }
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
|
|
569
905
|
//#endregion
|
|
570
906
|
//#region src/gates/Gate.ts
|
|
571
907
|
/**
|
|
@@ -660,23 +996,30 @@ var GateNotice = class extends Notice {
|
|
|
660
996
|
var NotOwner = class extends GateNotice {
|
|
661
997
|
constructor(message = "Only the bot owner can use this.") {
|
|
662
998
|
super(message);
|
|
999
|
+
this.summary = "be the bot owner";
|
|
663
1000
|
}
|
|
664
1001
|
};
|
|
665
1002
|
var NotInGuild = class extends GateNotice {
|
|
666
1003
|
constructor(message = "This can only be used in a server.") {
|
|
667
1004
|
super(message);
|
|
1005
|
+
this.summary = "be in a server";
|
|
668
1006
|
}
|
|
669
1007
|
};
|
|
670
1008
|
var NotInDm = class extends GateNotice {
|
|
671
1009
|
constructor(message = "This can only be used in a direct message.") {
|
|
672
1010
|
super(message);
|
|
1011
|
+
this.summary = "be in a direct message";
|
|
673
1012
|
}
|
|
674
1013
|
};
|
|
1014
|
+
function retryAt(resetAt) {
|
|
1015
|
+
return `<t:${toEpochSeconds(resetAt)}:R>`;
|
|
1016
|
+
}
|
|
675
1017
|
var OnCooldown = class extends GateNotice {
|
|
676
1018
|
resetAt;
|
|
677
1019
|
constructor(resetAt, message) {
|
|
678
|
-
super(message ?? `You are doing that too fast. Try again
|
|
1020
|
+
super(message ?? `You are doing that too fast. Try again ${retryAt(resetAt)}.`);
|
|
679
1021
|
this.resetAt = resetAt;
|
|
1022
|
+
this.summary = `try again ${retryAt(resetAt)}`;
|
|
680
1023
|
}
|
|
681
1024
|
};
|
|
682
1025
|
var NotAllowed = class extends Notice {
|
|
@@ -691,16 +1034,17 @@ var NeedsAny = class extends Notice {
|
|
|
691
1034
|
summaries;
|
|
692
1035
|
constructor(summaries) {
|
|
693
1036
|
super("not allowed");
|
|
694
|
-
this.summaries = summaries;
|
|
1037
|
+
this.summaries = [...new Set(summaries)];
|
|
695
1038
|
}
|
|
696
1039
|
render() {
|
|
697
1040
|
const bullets = this.summaries.map((summary) => `• ${summary}`).join("\n");
|
|
698
|
-
return { components: [new NoticeCard(`You need
|
|
1041
|
+
return { components: [new NoticeCard(`You need to meet at least one of these:\n${bullets}`).component] };
|
|
699
1042
|
}
|
|
700
1043
|
};
|
|
701
1044
|
var MissingRole = class extends GateNotice {
|
|
702
1045
|
constructor(message, roleId) {
|
|
703
1046
|
super(message ?? (roleId ? `You need the <@&${roleId}> role to use this.` : "You do not have the required role."));
|
|
1047
|
+
this.summary = roleId ? `hold the <@&${roleId}> role` : "hold the required role";
|
|
704
1048
|
}
|
|
705
1049
|
};
|
|
706
1050
|
var MissingPermissions = class extends Notice {
|
|
@@ -712,6 +1056,8 @@ var MissingPermissions = class extends Notice {
|
|
|
712
1056
|
this.subject = subject;
|
|
713
1057
|
this.missingPerms = missingPerms;
|
|
714
1058
|
this.customLead = message;
|
|
1059
|
+
const names = missingPerms.join(", ");
|
|
1060
|
+
this.summary = subject === null ? `hold ${names}` : `${subject} needs ${names}`;
|
|
715
1061
|
}
|
|
716
1062
|
render() {
|
|
717
1063
|
const bullets = this.missingPerms.map((perm) => `• ${perm}`).join("\n");
|
|
@@ -728,6 +1074,7 @@ var HasDangerousPermissions = class extends Notice {
|
|
|
728
1074
|
this.subject = subject;
|
|
729
1075
|
this.dangerousPerms = dangerousPerms;
|
|
730
1076
|
this.customLead = message;
|
|
1077
|
+
this.summary = `${subject} must not hold ${dangerousPerms.join(", ")}`;
|
|
731
1078
|
}
|
|
732
1079
|
render() {
|
|
733
1080
|
const bullets = this.dangerousPerms.map((perm) => `• ${perm}`).join("\n");
|
|
@@ -875,8 +1222,9 @@ function RequireRole(roleId, options) {
|
|
|
875
1222
|
* ```ts
|
|
876
1223
|
* import { Silence } from '@seedcord/gateway';
|
|
877
1224
|
*
|
|
878
|
-
* //
|
|
879
|
-
*
|
|
1225
|
+
* // a helper under a guildMemberAdd handler, stopping when this guild configured nothing to send
|
|
1226
|
+
* const template = await settings.welcome(member.guild.id);
|
|
1227
|
+
* if (!template) throw new Silence('no welcome message set');
|
|
880
1228
|
* ```
|
|
881
1229
|
*/
|
|
882
1230
|
var Silence = class extends Error {
|
|
@@ -901,5 +1249,5 @@ function pageCursor(prefix) {
|
|
|
901
1249
|
}
|
|
902
1250
|
|
|
903
1251
|
//#endregion
|
|
904
|
-
export {
|
|
905
|
-
//# sourceMappingURL=cursor-
|
|
1252
|
+
export { translateSerializationError as A, interactionRoutesOf as B, NotInDm as C, defineEffectGate as D, OnCooldown as E, checkAckLegality as F, decodeComponentRoute as G, storeComponentRoute as H, sendTarget as I, prefixOf as J, CustomId as K, SelectMenuKind as L, publishResponse as M, reportedWrite as N, defineGate as O, AckTrace as P, areRoutes as R, NotAllowed as S, NotOwner as T, storeInteractionRoute as U, selectMenuRouteOf as V, ComponentDefsKey as W, Notice as X, NoticeCard as Y, GateNotice as _, RequirePermissions as a, MissingRole as b, hasAll as c, pickNotice as d, discardCommits as f, runCommits as g, runCheck as h, RequireBotPermissions as i, attemptWrite as j, serializeReply as k, missingNames as l, rollbackCommits as m, pageCursor as n, RequireRole as o, markCommits as p, decodeFor as q, Silence as r, PermissionNames as s, PAGE_MAX as t, presentNames as u, HasDangerousPermissions as v, NotInGuild as w, NeedsAny as x, MissingPermissions as y, contextMenuRouteOf as z };
|
|
1253
|
+
//# sourceMappingURL=cursor-GBUYz3jk.mjs.map
|