@seedcord/core 0.4.0 → 0.5.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-BVwmKc-A.mjs → Bus-dGy6xq3F.mjs} +88 -85
- package/dist/Bus-dGy6xq3F.mjs.map +1 -0
- package/dist/{Pluggable-DFNUIlJM.d.mts → Pluggable-BKe2uCa0.d.mts} +3 -3
- package/dist/{Pluggable-Cf5-WWmW.mjs → Pluggable-CtMiOP3p.mjs} +4 -4
- package/dist/{Pluggable-Cf5-WWmW.mjs.map → Pluggable-CtMiOP3p.mjs.map} +1 -1
- package/dist/{Plugin-C6oMqWf8.mjs → Plugin-BJfRk0s_.mjs} +4 -4
- package/dist/{Plugin-C6oMqWf8.mjs.map → Plugin-BJfRk0s_.mjs.map} +1 -1
- package/dist/{Plugin-CG9pWbPF.d.mts → Plugin-iAaWcLaD.d.mts} +2 -2
- package/dist/{cursor-BcRfmTSo.d.mts → cursor-8Y2zpF-Y.d.mts} +5 -224
- package/dist/{cursor-GBUYz3jk.mjs → cursor-BkI9lxy2.mjs} +9 -498
- package/dist/cursor-BkI9lxy2.mjs.map +1 -0
- package/dist/{index-ZzdQafFv.d.mts → index-CD8l15aZ.d.mts} +2 -2
- package/dist/index.d.mts +99 -17
- package/dist/index.mjs +148 -16
- package/dist/index.mjs.map +1 -1
- package/dist/internal.index.d.mts +15 -7
- package/dist/internal.index.mjs +11 -11
- package/dist/internal.index.mjs.map +1 -1
- package/dist/node-internal.index.d.mts +4 -4
- package/dist/node-internal.index.mjs +7 -7
- package/dist/node.index.d.mts +1 -1
- package/dist/node.index.mjs +2 -2
- package/dist/{phases-F8yvPd60.d.mts → phases-D0a8BV9Z.d.mts} +60 -57
- package/dist/plugin.index.d.mts +1 -1
- package/dist/plugin.index.mjs +1 -1
- package/dist/{publishDefault-D826XXDQ.mjs → publishDefault-BuSZPbjT.mjs} +2 -2
- package/dist/{publishDefault-D826XXDQ.mjs.map → publishDefault-BuSZPbjT.mjs.map} +1 -1
- package/dist/{slashRouteLeaves-CbYRwqMY.mjs → slashRouteLeaves-C1msUE9Q.mjs} +2 -2
- package/dist/{slashRouteLeaves-CbYRwqMY.mjs.map → slashRouteLeaves-C1msUE9Q.mjs.map} +1 -1
- package/dist/{subscribers-CGGQkUfM.mjs → subscribers-A8lNU5yM.mjs} +3 -3
- package/dist/{subscribers-CGGQkUfM.mjs.map → subscribers-A8lNU5yM.mjs.map} +1 -1
- package/package.json +11 -10
- package/dist/Bus-BVwmKc-A.mjs.map +0 -1
- package/dist/cursor-GBUYz3jk.mjs.map +0 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as asError, t as PublishDefault } from "./publishDefault-
|
|
1
|
+
import { b as InteractionMetadataKey, k as BuilderComponent, x as InteractionRouteKeys, y as InteractionKind } from "./Bus-dGy6xq3F.mjs";
|
|
2
|
+
import { n as asError, t as PublishDefault } from "./publishDefault-BuSZPbjT.mjs";
|
|
3
3
|
import "reflect-metadata";
|
|
4
|
+
import { CustomId, decodeFor } from "@seedcord/custom-id";
|
|
4
5
|
import { TextDisplayBuilder } from "@discordjs/builders";
|
|
6
|
+
import { ApplicationCommandType, PermissionFlagsBits } from "discord-api-types/v10";
|
|
5
7
|
import { SeedcordErrorCode, paint } from "@seedcord/errors";
|
|
8
|
+
import { SeedcordError } from "@seedcord/errors/internal";
|
|
6
9
|
import { Logger } from "@seedcord/logger";
|
|
7
|
-
import { ApplicationCommandType, PermissionFlagsBits } from "discord-api-types/v10";
|
|
8
|
-
import { SeedcordError, SeedcordRangeError, SeedcordTypeError } from "@seedcord/errors/internal";
|
|
9
10
|
import { prettify, toEpochSeconds } from "@seedcord/utils";
|
|
10
11
|
|
|
11
12
|
//#region src/stops/Notice.ts
|
|
@@ -83,473 +84,6 @@ var NoticeCard = class extends BuilderComponent {
|
|
|
83
84
|
}
|
|
84
85
|
};
|
|
85
86
|
|
|
86
|
-
//#endregion
|
|
87
|
-
//#region src/customId/Errors.ts
|
|
88
|
-
/**
|
|
89
|
-
* Thrown when a customId was minted by an older version of its shape.
|
|
90
|
-
*
|
|
91
|
-
* This is normal after the shape changes.
|
|
92
|
-
*/
|
|
93
|
-
var StaleCustomId = class extends Notice {
|
|
94
|
-
constructor(prefix) {
|
|
95
|
-
super(`Stale customId for "${prefix}".`);
|
|
96
|
-
}
|
|
97
|
-
render() {
|
|
98
|
-
return { components: [new NoticeCard("This button or menu is from an older version. Please run the command again.", "Outdated").component] };
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
/**
|
|
102
|
-
* Thrown when a customId wire is corrupt or tampered with and cannot be trusted.
|
|
103
|
-
*
|
|
104
|
-
* It reports because this is an odd case that should not happen.
|
|
105
|
-
*/
|
|
106
|
-
var InvalidCustomId = class extends Notice {
|
|
107
|
-
constructor(detail) {
|
|
108
|
-
super(`Invalid customId. ${detail}`);
|
|
109
|
-
this.report = true;
|
|
110
|
-
}
|
|
111
|
-
render() {
|
|
112
|
-
return { components: [new NoticeCard("Something went wrong. Please try again.").component] };
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
//#endregion
|
|
117
|
-
//#region src/customId/codec.ts
|
|
118
|
-
const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
119
|
-
const BASE = 64n;
|
|
120
|
-
const CHAR_TO_VALUE = new Map([...ALPHABET].map((char, index) => [char, index]));
|
|
121
|
-
const DELIMITER = "";
|
|
122
|
-
const ESCAPE = "\x1B";
|
|
123
|
-
/** @internal */
|
|
124
|
-
const HASH_LENGTH = 3;
|
|
125
|
-
const SAFE_MAX = BigInt(Number.MAX_SAFE_INTEGER);
|
|
126
|
-
const SAFE_MIN = BigInt(Number.MIN_SAFE_INTEGER);
|
|
127
|
-
function bigintToBase64(value) {
|
|
128
|
-
if (value === 0n) return ALPHABET.charAt(0);
|
|
129
|
-
let text = "";
|
|
130
|
-
for (let remaining = value; remaining > 0n; remaining /= BASE) text = ALPHABET.charAt(Number(remaining % BASE)) + text;
|
|
131
|
-
return text;
|
|
132
|
-
}
|
|
133
|
-
function base64ToBigint(text) {
|
|
134
|
-
let value = 0n;
|
|
135
|
-
for (const char of text) {
|
|
136
|
-
const digit = CHAR_TO_VALUE.get(char);
|
|
137
|
-
if (digit === void 0) throw new InvalidCustomId(`bad character ${JSON.stringify(char)}`);
|
|
138
|
-
value = value * BASE + BigInt(digit);
|
|
139
|
-
}
|
|
140
|
-
return value;
|
|
141
|
-
}
|
|
142
|
-
function zigzagEncode(value) {
|
|
143
|
-
const big = BigInt(value);
|
|
144
|
-
return big >= 0n ? big << 1n : (-big << 1n) - 1n;
|
|
145
|
-
}
|
|
146
|
-
function zigzagDecode(encoded) {
|
|
147
|
-
return (encoded & 1n) === 1n ? -(encoded + 1n >> 1n) : encoded >> 1n;
|
|
148
|
-
}
|
|
149
|
-
function escapeToken(text) {
|
|
150
|
-
return text.replaceAll(/[\x1B\x1F]/g, (char) => ESCAPE + char);
|
|
151
|
-
}
|
|
152
|
-
function unescapeToken(text) {
|
|
153
|
-
let out = "";
|
|
154
|
-
for (let i = 0; i < text.length; i++) {
|
|
155
|
-
if (text.charAt(i) !== ESCAPE) {
|
|
156
|
-
out += text.charAt(i);
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
const next = text.charAt(i + 1);
|
|
160
|
-
if (next === "") throw new InvalidCustomId("dangling escape at end of token");
|
|
161
|
-
out += next;
|
|
162
|
-
i++;
|
|
163
|
-
}
|
|
164
|
-
return out;
|
|
165
|
-
}
|
|
166
|
-
function splitTokens(body) {
|
|
167
|
-
const pieces = [];
|
|
168
|
-
let current = "";
|
|
169
|
-
for (let i = 0; i < body.length; i++) {
|
|
170
|
-
const char = body.charAt(i);
|
|
171
|
-
if (char === ESCAPE) {
|
|
172
|
-
current += char + body.charAt(i + 1);
|
|
173
|
-
i++;
|
|
174
|
-
} else if (char === DELIMITER) {
|
|
175
|
-
pieces.push(current);
|
|
176
|
-
current = "";
|
|
177
|
-
} else current += char;
|
|
178
|
-
}
|
|
179
|
-
pieces.push(current);
|
|
180
|
-
return pieces;
|
|
181
|
-
}
|
|
182
|
-
function isBounded(field) {
|
|
183
|
-
if (field.kind === "int") return field.min !== void 0 && field.max !== void 0;
|
|
184
|
-
return field.kind === "snowflake" || field.kind === "uuid" || field.kind === "bool" || field.kind === "oneOf";
|
|
185
|
-
}
|
|
186
|
-
function radixOf(field) {
|
|
187
|
-
return kindRadix(field) + (field.nullable === true ? 1n : 0n);
|
|
188
|
-
}
|
|
189
|
-
function kindRadix(field) {
|
|
190
|
-
switch (field.kind) {
|
|
191
|
-
case "snowflake": return 1n << 64n;
|
|
192
|
-
case "uuid": return 1n << 128n;
|
|
193
|
-
case "bool": return 2n;
|
|
194
|
-
case "oneOf":
|
|
195
|
-
if (!field.choices?.length) throw new InvalidCustomId("oneOf field has no choices");
|
|
196
|
-
return BigInt(field.choices.length);
|
|
197
|
-
case "int":
|
|
198
|
-
if (field.min === void 0 || field.max === void 0) throw new InvalidCustomId("bounded int field is missing a bound");
|
|
199
|
-
return BigInt(field.max) - BigInt(field.min) + 1n;
|
|
200
|
-
default: throw new InvalidCustomId(`field kind ${field.kind} has no radix`);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
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
|
-
}
|
|
211
|
-
const slot = boundedSlot(field, name, value);
|
|
212
|
-
if (slot < 0n || slot >= radixOf(field)) outOfRange(name, value);
|
|
213
|
-
return slot;
|
|
214
|
-
}
|
|
215
|
-
function boundedSlot(field, name, value) {
|
|
216
|
-
switch (field.kind) {
|
|
217
|
-
case "snowflake":
|
|
218
|
-
if (typeof value !== "string" || !/^\d+$/.test(value)) return outOfRange(name, value);
|
|
219
|
-
return BigInt(value);
|
|
220
|
-
case "uuid": {
|
|
221
|
-
if (typeof value !== "string") return outOfRange(name, value);
|
|
222
|
-
const hex = value.replaceAll("-", "");
|
|
223
|
-
if (!/^[0-9a-fA-F]{32}$/.test(hex)) return outOfRange(name, value);
|
|
224
|
-
return BigInt(`0x${hex}`);
|
|
225
|
-
}
|
|
226
|
-
case "bool": return value ? 1n : 0n;
|
|
227
|
-
case "oneOf": {
|
|
228
|
-
const index = (field.choices ?? []).indexOf(value);
|
|
229
|
-
return index === -1 ? outOfRange(name, value) : BigInt(index);
|
|
230
|
-
}
|
|
231
|
-
case "int":
|
|
232
|
-
if (!Number.isInteger(value)) return outOfRange(name, value);
|
|
233
|
-
return BigInt(value - (field.min ?? 0));
|
|
234
|
-
default: return outOfRange(name, value);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
function outOfRange(name, value) {
|
|
238
|
-
throw new SeedcordRangeError(SeedcordErrorCode.CustomIdValueOutOfRange, [name, String(value)]);
|
|
239
|
-
}
|
|
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) {
|
|
248
|
-
switch (field.kind) {
|
|
249
|
-
case "snowflake": return slot.toString();
|
|
250
|
-
case "uuid": return bigintToUuid(slot);
|
|
251
|
-
case "bool": return slot === 1n;
|
|
252
|
-
case "oneOf": return (field.choices ?? [])[Number(slot)];
|
|
253
|
-
case "int": return Number(slot) + (field.min ?? 0);
|
|
254
|
-
default: throw new InvalidCustomId(`field kind ${field.kind} is not bounded`);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
function bigintToUuid(value) {
|
|
258
|
-
const hex = value.toString(16).padStart(32, "0");
|
|
259
|
-
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
260
|
-
}
|
|
261
|
-
const ABSENT = "0";
|
|
262
|
-
const PRESENT = "1";
|
|
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
|
-
}
|
|
271
|
-
if (field.kind === "int") {
|
|
272
|
-
if (!Number.isSafeInteger(value)) outOfRange(name, value);
|
|
273
|
-
return bigintToBase64(zigzagEncode(value));
|
|
274
|
-
}
|
|
275
|
-
return escapeToken(value);
|
|
276
|
-
}
|
|
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
|
-
}
|
|
287
|
-
if (field.kind !== "int") return unescapeToken(piece);
|
|
288
|
-
if (piece === "") throw new InvalidCustomId("empty integer token");
|
|
289
|
-
const decoded = zigzagDecode(base64ToBigint(piece));
|
|
290
|
-
if (decoded > SAFE_MAX || decoded < SAFE_MIN) throw new InvalidCustomId("integer out of safe range");
|
|
291
|
-
return Number(decoded);
|
|
292
|
-
}
|
|
293
|
-
/** @internal */
|
|
294
|
-
function computeLayoutHash(shape) {
|
|
295
|
-
const signature = JSON.stringify(Object.entries(shape).map(([name, field]) => [
|
|
296
|
-
name,
|
|
297
|
-
field.kind,
|
|
298
|
-
isBounded(field),
|
|
299
|
-
field.nullable === true,
|
|
300
|
-
field.kind === "oneOf" ? field.choices ?? [] : null,
|
|
301
|
-
field.kind === "int" ? [field.min ?? null, field.max ?? null] : null
|
|
302
|
-
]));
|
|
303
|
-
const modulus = BASE ** BigInt(3);
|
|
304
|
-
let hash = 0n;
|
|
305
|
-
for (const char of signature) hash = (hash * 131n + BigInt(char.charCodeAt(0))) % modulus;
|
|
306
|
-
let text = "";
|
|
307
|
-
for (let i = 0; i < 3; i++) {
|
|
308
|
-
text = ALPHABET.charAt(Number(hash % BASE)) + text;
|
|
309
|
-
hash /= BASE;
|
|
310
|
-
}
|
|
311
|
-
return text;
|
|
312
|
-
}
|
|
313
|
-
/** @internal */
|
|
314
|
-
function encodeBody(shape, values) {
|
|
315
|
-
const fields = Object.entries(shape);
|
|
316
|
-
const pieces = [];
|
|
317
|
-
const bounded = fields.filter(([, field]) => isBounded(field));
|
|
318
|
-
if (bounded.length > 0) {
|
|
319
|
-
let packed = 0n;
|
|
320
|
-
for (const [name, field] of bounded) packed = packed * radixOf(field) + boundedToBigint(field, name, values[name]);
|
|
321
|
-
pieces.push(bigintToBase64(packed));
|
|
322
|
-
}
|
|
323
|
-
for (const [name, field] of fields) if (!isBounded(field)) pieces.push(encodeUnboundedToken(field, name, values[name]));
|
|
324
|
-
return pieces.join(DELIMITER);
|
|
325
|
-
}
|
|
326
|
-
function unpackBounded(bounded, blob, result) {
|
|
327
|
-
if (blob === void 0 || blob === "") throw new InvalidCustomId("empty packed block");
|
|
328
|
-
let packed = base64ToBigint(blob);
|
|
329
|
-
for (const [name, field] of [...bounded].reverse()) {
|
|
330
|
-
const radix = radixOf(field);
|
|
331
|
-
result[name] = bigintToBoundedValue(field, packed % radix);
|
|
332
|
-
packed /= radix;
|
|
333
|
-
}
|
|
334
|
-
if (packed !== 0n) throw new InvalidCustomId("leftover bits after unpacking");
|
|
335
|
-
}
|
|
336
|
-
/** @internal */
|
|
337
|
-
function decodeBody(shape, body) {
|
|
338
|
-
const fields = Object.entries(shape);
|
|
339
|
-
const bounded = fields.filter(([, field]) => isBounded(field));
|
|
340
|
-
const unbounded = fields.filter(([, field]) => !isBounded(field));
|
|
341
|
-
const expected = (bounded.length > 0 ? 1 : 0) + unbounded.length;
|
|
342
|
-
if (expected === 0) {
|
|
343
|
-
if (body !== "") throw new InvalidCustomId(`expected an empty body, got ${JSON.stringify(body)}`);
|
|
344
|
-
return {};
|
|
345
|
-
}
|
|
346
|
-
const pieces = splitTokens(body);
|
|
347
|
-
if (pieces.length !== expected) throw new InvalidCustomId(`expected ${expected} piece(s), got ${pieces.length}`);
|
|
348
|
-
const result = {};
|
|
349
|
-
let cursor = 0;
|
|
350
|
-
if (bounded.length > 0) {
|
|
351
|
-
unpackBounded(bounded, pieces[cursor], result);
|
|
352
|
-
cursor++;
|
|
353
|
-
}
|
|
354
|
-
for (const [name, field] of unbounded) {
|
|
355
|
-
const piece = pieces[cursor];
|
|
356
|
-
cursor++;
|
|
357
|
-
if (piece === void 0) throw new InvalidCustomId("missing trailing piece");
|
|
358
|
-
result[name] = decodeUnboundedToken(field, piece);
|
|
359
|
-
}
|
|
360
|
-
return result;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
//#endregion
|
|
364
|
-
//#region src/customId/CustomId.ts
|
|
365
|
-
const MAX_WIRE_LENGTH = 100;
|
|
366
|
-
function routeKeyOf(wire) {
|
|
367
|
-
const colon = wire.indexOf(":");
|
|
368
|
-
return colon === -1 ? "" : wire.slice(0, colon);
|
|
369
|
-
}
|
|
370
|
-
/** Strip the layout hash off the routeKey to recover the stable prefix the controller routes by. @internal */
|
|
371
|
-
function prefixOf(wire) {
|
|
372
|
-
const key = routeKeyOf(wire);
|
|
373
|
-
return key.length <= 3 ? "" : key.slice(0, key.length - 3);
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* A typed customId. The single source of truth shared by the component that mints it and the handler
|
|
377
|
-
* that reads it. This gives you typed reads on the `.customId` field in components. Values are packed
|
|
378
|
-
* into a compact wire string, which fits more of them inside Discord's 100-char limit.
|
|
379
|
-
*
|
|
380
|
-
* @typeParam Prefix - The stable route prefix, e.g. 'approve'.
|
|
381
|
-
* @typeParam Shape - The accumulated fields, filled in by the chain.
|
|
382
|
-
*
|
|
383
|
-
* @example
|
|
384
|
-
* ```ts
|
|
385
|
-
* const ApproveId = new CustomId('approve')
|
|
386
|
-
* .snowflake('userId')
|
|
387
|
-
* .oneOf('action', ['approve', 'deny']);
|
|
388
|
-
*
|
|
389
|
-
* // Set the custom id on a button when creating it.
|
|
390
|
-
* new ButtonBuilder().setCustomId(ApproveId.encode({ userId: '123', action: 'approve' }));
|
|
391
|
-
*
|
|
392
|
-
* // in the handler, userId comes back a string
|
|
393
|
-
* const { userId, action } = this.params; // userId: string, action: 'approve' | 'deny'
|
|
394
|
-
* await this.event.guild?.members.fetch(userId);
|
|
395
|
-
* ```
|
|
396
|
-
*/
|
|
397
|
-
var CustomId = class CustomId {
|
|
398
|
-
/** The stable route prefix, e.g. 'approve'. */
|
|
399
|
-
prefix;
|
|
400
|
-
/** The field definitions accumulated by the chain, keyed by name. */
|
|
401
|
-
shape;
|
|
402
|
-
/** The prefix plus a short hash of the shape, the part of the wire before the colon. */
|
|
403
|
-
routeKey;
|
|
404
|
-
constructor(prefix, shape = {}) {
|
|
405
|
-
if (!prefix || /[:\x1B\x1F]/.test(prefix)) throw new SeedcordTypeError(SeedcordErrorCode.CustomIdInvalidPrefix, [prefix]);
|
|
406
|
-
this.prefix = prefix;
|
|
407
|
-
this.shape = shape;
|
|
408
|
-
this.routeKey = prefix + computeLayoutHash(shape);
|
|
409
|
-
}
|
|
410
|
-
add(name, field) {
|
|
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]);
|
|
413
|
-
const shape = {
|
|
414
|
-
...this.shape,
|
|
415
|
-
[name]: field
|
|
416
|
-
};
|
|
417
|
-
return new CustomId(this.prefix, shape);
|
|
418
|
-
}
|
|
419
|
-
/**
|
|
420
|
-
* Add a Discord ID field, decoded as a string (the `Snowflake` type from discord-api-types).
|
|
421
|
-
*
|
|
422
|
-
* @example
|
|
423
|
-
* ```ts
|
|
424
|
-
* new CustomId('ban').snowflake('userId');
|
|
425
|
-
* ```
|
|
426
|
-
*/
|
|
427
|
-
snowflake(name, opts) {
|
|
428
|
-
return this.add(name, {
|
|
429
|
-
...opts,
|
|
430
|
-
kind: "snowflake"
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
/**
|
|
434
|
-
* Add a UUID field, decoded as a lowercase uuid string.
|
|
435
|
-
*
|
|
436
|
-
* @example
|
|
437
|
-
* ```ts
|
|
438
|
-
* new CustomId('ticket').uuid('ticketId');
|
|
439
|
-
* ```
|
|
440
|
-
*/
|
|
441
|
-
uuid(name, opts) {
|
|
442
|
-
return this.add(name, {
|
|
443
|
-
...opts,
|
|
444
|
-
kind: "uuid"
|
|
445
|
-
});
|
|
446
|
-
}
|
|
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, [
|
|
450
|
-
name,
|
|
451
|
-
min,
|
|
452
|
-
max
|
|
453
|
-
]);
|
|
454
|
-
const options = typeof minOrOpts === "number" ? opts : minOrOpts;
|
|
455
|
-
const bounds = min === void 0 || max === void 0 ? {} : {
|
|
456
|
-
min,
|
|
457
|
-
max
|
|
458
|
-
};
|
|
459
|
-
return this.add(name, {
|
|
460
|
-
...options,
|
|
461
|
-
kind: "int",
|
|
462
|
-
...bounds
|
|
463
|
-
});
|
|
464
|
-
}
|
|
465
|
-
/**
|
|
466
|
-
* Add a boolean flag.
|
|
467
|
-
*
|
|
468
|
-
* @example
|
|
469
|
-
* ```ts
|
|
470
|
-
* new CustomId('settings').bool('silent');
|
|
471
|
-
* ```
|
|
472
|
-
*/
|
|
473
|
-
bool(name, opts) {
|
|
474
|
-
return this.add(name, {
|
|
475
|
-
...opts,
|
|
476
|
-
kind: "bool"
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
/**
|
|
480
|
-
* Add a field that is one value from a fixed list, decoded as the literal union. No `as const` needed.
|
|
481
|
-
*
|
|
482
|
-
* @example
|
|
483
|
-
* ```ts
|
|
484
|
-
* new CustomId('poll').oneOf('choice', ['yes', 'no', 'abstain']);
|
|
485
|
-
* ```
|
|
486
|
-
*/
|
|
487
|
-
oneOf(name, choices, opts) {
|
|
488
|
-
if (choices.length === 0) throw new SeedcordRangeError(SeedcordErrorCode.CustomIdEmptyChoices, [name]);
|
|
489
|
-
return this.add(name, {
|
|
490
|
-
...opts,
|
|
491
|
-
kind: "oneOf",
|
|
492
|
-
choices
|
|
493
|
-
});
|
|
494
|
-
}
|
|
495
|
-
/**
|
|
496
|
-
* Add a free short text field. Avoid it where possible. It cannot be packed, which makes it the most
|
|
497
|
-
* expensive field on the wire.
|
|
498
|
-
*
|
|
499
|
-
* @example
|
|
500
|
-
* ```ts
|
|
501
|
-
* new CustomId('note').str('message');
|
|
502
|
-
* ```
|
|
503
|
-
*/
|
|
504
|
-
str(name, opts) {
|
|
505
|
-
return this.add(name, {
|
|
506
|
-
...opts,
|
|
507
|
-
kind: "string"
|
|
508
|
-
});
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
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.
|
|
512
|
-
*
|
|
513
|
-
* @param values - One value per field, typed by the chain.
|
|
514
|
-
* @returns The wire string to put on the component's customId.
|
|
515
|
-
*/
|
|
516
|
-
encode(values) {
|
|
517
|
-
const wire = `${this.routeKey}:${encodeBody(this.shape, values)}`;
|
|
518
|
-
if (wire.length > MAX_WIRE_LENGTH) throw new SeedcordRangeError(SeedcordErrorCode.CustomIdWireTooLong, [wire.length]);
|
|
519
|
-
return wire;
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* Read a wire string back into values.
|
|
523
|
-
*
|
|
524
|
-
* - This will refuse with a default Notice when the shape changed since the wire was minted.
|
|
525
|
-
* - Or refuse with a different default Notice on a corrupt or foreign wire.
|
|
526
|
-
*
|
|
527
|
-
* @param wire - The customId string from the interaction.
|
|
528
|
-
* @returns The decoded values, typed by the chain.
|
|
529
|
-
*/
|
|
530
|
-
decode(wire) {
|
|
531
|
-
const key = routeKeyOf(wire);
|
|
532
|
-
if (key !== this.routeKey) {
|
|
533
|
-
if (prefixOf(wire) === this.prefix) throw new StaleCustomId(this.prefix);
|
|
534
|
-
throw new InvalidCustomId(`routeKey ${JSON.stringify(key)} is not ${JSON.stringify(this.routeKey)}`);
|
|
535
|
-
}
|
|
536
|
-
return decodeBody(this.shape, wire.slice(key.length + 1));
|
|
537
|
-
}
|
|
538
|
-
/** True if this wire was minted from this customId's prefix, ignoring the shape hash. */
|
|
539
|
-
owns(wire) {
|
|
540
|
-
return prefixOf(wire) === this.prefix;
|
|
541
|
-
}
|
|
542
|
-
};
|
|
543
|
-
/** @internal */
|
|
544
|
-
function decodeFor(defs, wire) {
|
|
545
|
-
const match = defs.find((def) => def.owns(wire));
|
|
546
|
-
if (!match) throw new InvalidCustomId(`no customId owns ${JSON.stringify(routeKeyOf(wire))}`);
|
|
547
|
-
return {
|
|
548
|
-
prefix: match.prefix,
|
|
549
|
-
params: match.decode(wire)
|
|
550
|
-
};
|
|
551
|
-
}
|
|
552
|
-
|
|
553
87
|
//#endregion
|
|
554
88
|
//#region src/customId/routing.ts
|
|
555
89
|
/**
|
|
@@ -558,7 +92,7 @@ function decodeFor(defs, wire) {
|
|
|
558
92
|
*
|
|
559
93
|
* @internal
|
|
560
94
|
*/
|
|
561
|
-
const ComponentDefsKey = Symbol("seedcord:
|
|
95
|
+
const ComponentDefsKey = Symbol.for("seedcord:custom-id:component-defs");
|
|
562
96
|
/**
|
|
563
97
|
* throws `CustomIdHandlerRouteMissing` when the class has no stored defs. a drifted or corrupt wire
|
|
564
98
|
* throws `StaleCustomId` or `InvalidCustomId`.
|
|
@@ -573,25 +107,12 @@ function decodeComponentRoute(handlerClass, wire) {
|
|
|
573
107
|
|
|
574
108
|
//#endregion
|
|
575
109
|
//#region src/decorators/interactionRoutes.ts
|
|
576
|
-
/** The select menu kinds the select route decorators take. */
|
|
577
|
-
let SelectMenuKind = /* @__PURE__ */ function(SelectMenuKind) {
|
|
578
|
-
SelectMenuKind["String"] = "string";
|
|
579
|
-
SelectMenuKind["User"] = "user";
|
|
580
|
-
SelectMenuKind["Role"] = "role";
|
|
581
|
-
SelectMenuKind["Channel"] = "channel";
|
|
582
|
-
SelectMenuKind["Mentionable"] = "mentionable";
|
|
583
|
-
return SelectMenuKind;
|
|
584
|
-
}({});
|
|
585
110
|
function areRoutes(routes) {
|
|
586
111
|
return Array.isArray(routes) && routes.every((route) => typeof route === "string");
|
|
587
112
|
}
|
|
588
|
-
/**
|
|
589
|
-
* every stored route kind and its route strings on a decorated constructor. the build's manifest
|
|
590
|
-
* emitter reads the same pairs.
|
|
591
|
-
*/
|
|
592
113
|
function interactionRoutesOf(constructor) {
|
|
593
114
|
const pairs = [];
|
|
594
|
-
for (const route of Object.values(
|
|
115
|
+
for (const route of Object.values(InteractionKind)) {
|
|
595
116
|
const meta = Reflect.getMetadata(InteractionRouteKeys[route], constructor);
|
|
596
117
|
if (areRoutes(meta)) pairs.push([route, meta]);
|
|
597
118
|
}
|
|
@@ -609,16 +130,6 @@ function storeComponentRoute(route, defs, constructor) {
|
|
|
609
130
|
storeInteractionRoute(route, defs.map((def) => def.prefix), constructor);
|
|
610
131
|
Reflect.defineMetadata(ComponentDefsKey, defs, constructor);
|
|
611
132
|
}
|
|
612
|
-
const SELECT_ROUTES = {
|
|
613
|
-
["string"]: "stringMenu",
|
|
614
|
-
["user"]: "userMenu",
|
|
615
|
-
["role"]: "roleMenu",
|
|
616
|
-
["channel"]: "channelMenu",
|
|
617
|
-
["mentionable"]: "mentionableMenu"
|
|
618
|
-
};
|
|
619
|
-
function selectMenuRouteOf(kind) {
|
|
620
|
-
return SELECT_ROUTES[kind];
|
|
621
|
-
}
|
|
622
133
|
function contextMenuRouteOf(kind) {
|
|
623
134
|
return kind === ApplicationCommandType.User ? "userContextMenu" : "messageContextMenu";
|
|
624
135
|
}
|
|
@@ -1249,5 +760,5 @@ function pageCursor(prefix) {
|
|
|
1249
760
|
}
|
|
1250
761
|
|
|
1251
762
|
//#endregion
|
|
1252
|
-
export { translateSerializationError as A,
|
|
1253
|
-
//# sourceMappingURL=cursor-
|
|
763
|
+
export { translateSerializationError as A, storeComponentRoute as B, NotInDm as C, defineEffectGate as D, OnCooldown as E, checkAckLegality as F, Notice as G, ComponentDefsKey as H, sendTarget as I, areRoutes as L, publishResponse as M, reportedWrite as N, defineGate as O, AckTrace as P, contextMenuRouteOf as R, NotAllowed as S, NotOwner as T, decodeComponentRoute as U, storeInteractionRoute as V, NoticeCard as W, 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, 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, interactionRoutesOf as z };
|
|
764
|
+
//# sourceMappingURL=cursor-BkI9lxy2.mjs.map
|