lunibee 0.3.0 → 0.3.2
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/builders/attachment.d.ts +1 -0
- package/dist/builders/clone.d.ts +10 -0
- package/dist/builders/commands.d.ts +1 -1
- package/dist/builders/components.d.ts +24 -5
- package/dist/builders/embed.d.ts +1 -0
- package/dist/builders/index.js +68 -17
- package/dist/builders/index.js.map +10 -9
- package/dist/collection/index.d.ts +1 -0
- package/dist/collection/index.js +297 -19
- package/dist/collection/index.js.map +5 -4
- package/dist/collection/redis.d.ts +98 -0
- package/dist/core/collector.d.ts +8 -0
- package/dist/core/events.d.ts +1 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.js +6252 -4704
- package/dist/core/index.js.map +47 -40
- package/dist/core/permissions.d.ts +3 -402
- package/dist/core/redis-cache.d.ts +85 -0
- package/dist/formatters/index.d.ts +5 -1
- package/dist/formatters/index.js +7 -3
- package/dist/formatters/index.js.map +3 -3
- package/dist/handlers/index.js +11 -2
- package/dist/handlers/index.js.map +3 -3
- package/dist/index.js +10481 -6148
- package/dist/index.js.map +70 -56
- package/dist/managers/application.d.ts +10 -6
- package/dist/managers/base.d.ts +4 -1
- package/dist/managers/guild.d.ts +3 -1
- package/dist/managers/index.d.ts +6 -1
- package/dist/managers/index.js +365 -103
- package/dist/managers/index.js.map +19 -22
- package/dist/managers/member.d.ts +3 -1
- package/dist/managers/message.d.ts +13 -4
- package/dist/managers/thread.d.ts +3 -3
- package/dist/rest/decoder.d.ts +2 -0
- package/dist/rest/errors.d.ts +13 -2
- package/dist/rest/headers.d.ts +31 -0
- package/dist/rest/identity.d.ts +31 -0
- package/dist/rest/index.d.ts +99 -6
- package/dist/rest/index.js +1412 -231
- package/dist/rest/index.js.map +16 -13
- package/dist/rest/limiter.d.ts +75 -10
- package/dist/rest/redis.d.ts +103 -22
- package/dist/rest/scheduler.d.ts +13 -0
- package/dist/rest/store.d.ts +135 -12
- package/dist/rest/telemetry.d.ts +151 -0
- package/dist/rest/transport.d.ts +9 -0
- package/dist/rest/webhook.d.ts +18 -6
- package/dist/sharding/bus.d.ts +12 -2
- package/dist/sharding/cluster.d.ts +225 -15
- package/dist/sharding/context.d.ts +41 -0
- package/dist/sharding/gateway-bot.d.ts +20 -0
- package/dist/sharding/health.d.ts +94 -0
- package/dist/sharding/host.d.ts +76 -0
- package/dist/sharding/identify.d.ts +64 -0
- package/dist/sharding/index.d.ts +62 -12
- package/dist/sharding/index.js +2459 -202
- package/dist/sharding/index.js.map +21 -13
- package/dist/sharding/protocol.d.ts +47 -0
- package/dist/sharding/remote-protocol.d.ts +100 -0
- package/dist/sharding/remote.d.ts +134 -0
- package/dist/sharding/requests.d.ts +54 -0
- package/dist/sharding/supervisor.d.ts +1 -1
- package/dist/sharding/transport.d.ts +6 -5
- package/dist/sharding/worker.d.ts +55 -0
- package/dist/structures/base.d.ts +16 -5
- package/dist/structures/index.d.ts +1 -1
- package/dist/structures/index.js +57 -91
- package/dist/structures/index.js.map +10 -18
- package/dist/structures/options.d.ts +3 -2
- package/dist/structures/permissions.d.ts +409 -0
- package/dist/structures/resources.d.ts +4 -1
- package/dist/types/gateway.d.ts +7 -0
- package/dist/types/index.d.ts +14 -4
- package/dist/types/index.js.map +3 -3
- package/dist/utils/args.d.ts +3 -1
- package/dist/utils/index.d.ts +6 -1
- package/dist/utils/index.js +17 -10
- package/dist/utils/index.js.map +4 -4
- package/dist/voice/index.d.ts +7 -1
- package/dist/voice/index.js +33 -10
- package/dist/voice/index.js.map +3 -3
- package/dist/ws/index.d.ts +3 -1
- package/dist/ws/index.js +33 -5
- package/dist/ws/index.js.map +6 -6
- package/dist/ws/send-budget.d.ts +1 -1
- package/package.json +22 -17
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A deep copy of builder data, for `toJSON()`.
|
|
3
|
+
*
|
|
4
|
+
* Builder payloads are plain JSON: objects, arrays and primitives. Copying
|
|
5
|
+
* those directly is several times faster than `structuredClone` on the small
|
|
6
|
+
* payloads builders hold. Anything else (a Date, a Map, a class instance) and
|
|
7
|
+
* anything nested deeper than 64 levels (a cycle) goes to `structuredClone`,
|
|
8
|
+
* so the result is what `structuredClone` would give.
|
|
9
|
+
*/
|
|
10
|
+
export declare function cloneData<T>(value: T, depth?: number): T;
|
|
@@ -69,7 +69,7 @@ export declare class CreateCommandOption {
|
|
|
69
69
|
setDescription(description: string): this;
|
|
70
70
|
/** Makes the option required or optional. */
|
|
71
71
|
setRequired(required?: boolean): this;
|
|
72
|
-
/** Sets autocomplete. */
|
|
72
|
+
/** Sets autocomplete; options with choices cannot use it. */
|
|
73
73
|
setAutocomplete(enabled?: boolean): this;
|
|
74
74
|
/** Serializes the option payload. */
|
|
75
75
|
toJSON(): Record<string, unknown>;
|
|
@@ -6,11 +6,13 @@ export declare const TextInputType: {
|
|
|
6
6
|
};
|
|
7
7
|
/** One {@link TextInputType} value, usable as a type. */
|
|
8
8
|
export type TextInputType = (typeof TextInputType)[keyof typeof TextInputType];
|
|
9
|
+
/** An emoji on a button or select option: a custom emoji `id`, or a Unicode `name`. */
|
|
9
10
|
export interface APIComponentEmoji {
|
|
10
11
|
id?: string | null;
|
|
11
12
|
name?: string | null;
|
|
12
13
|
animated?: boolean;
|
|
13
14
|
}
|
|
15
|
+
/** A button as a builder sends it. Exported from `lunibee` as `APIButtonPayload`. */
|
|
14
16
|
export interface APIButtonComponent {
|
|
15
17
|
type: typeof ComponentEnum.Button;
|
|
16
18
|
style: 1 | 2 | 3 | 4 | 5 | 6;
|
|
@@ -22,6 +24,7 @@ export interface APIButtonComponent {
|
|
|
22
24
|
sku_id?: string;
|
|
23
25
|
disabled?: boolean;
|
|
24
26
|
}
|
|
27
|
+
/** One option of a string select menu. */
|
|
25
28
|
export interface APISelectOption {
|
|
26
29
|
label: string;
|
|
27
30
|
value: string;
|
|
@@ -29,6 +32,7 @@ export interface APISelectOption {
|
|
|
29
32
|
emoji?: APIComponentEmoji;
|
|
30
33
|
default?: boolean;
|
|
31
34
|
}
|
|
35
|
+
/** A string select menu (component type 3) as Discord receives it. */
|
|
32
36
|
export interface APIStringSelectComponent {
|
|
33
37
|
type: typeof ComponentEnum.StringSelect;
|
|
34
38
|
custom_id?: string;
|
|
@@ -39,6 +43,7 @@ export interface APIStringSelectComponent {
|
|
|
39
43
|
disabled?: boolean;
|
|
40
44
|
options?: APISelectOption[];
|
|
41
45
|
}
|
|
46
|
+
/** A user, role, mentionable or channel select menu as Discord receives it. */
|
|
42
47
|
export interface APIEntitySelectComponent {
|
|
43
48
|
type: typeof ComponentEnum.UserSelect | typeof ComponentEnum.RoleSelect | typeof ComponentEnum.MentionableSelect | typeof ComponentEnum.ChannelSelect;
|
|
44
49
|
custom_id?: string;
|
|
@@ -49,6 +54,7 @@ export interface APIEntitySelectComponent {
|
|
|
49
54
|
disabled?: boolean;
|
|
50
55
|
default_values?: APISelectDefaultValue[];
|
|
51
56
|
}
|
|
57
|
+
/** A modal text input as a builder sends it. Exported from `lunibee` as `APITextInputPayload`. */
|
|
52
58
|
export interface APITextInputComponent {
|
|
53
59
|
type: typeof ComponentEnum.TextInput;
|
|
54
60
|
style: typeof TextInputType.Short | typeof TextInputType.Paragraph;
|
|
@@ -60,33 +66,40 @@ export interface APITextInputComponent {
|
|
|
60
66
|
required?: boolean;
|
|
61
67
|
value?: string;
|
|
62
68
|
}
|
|
69
|
+
/** A modal (callback type 9 data): title, custom ID and its components. */
|
|
63
70
|
export interface APIModalComponent {
|
|
64
71
|
type: 9;
|
|
65
72
|
custom_id: string;
|
|
66
73
|
title: string;
|
|
67
74
|
components: APIActionRowComponent[];
|
|
68
75
|
}
|
|
76
|
+
/** Any component an action row can hold: a button, a select menu or a text input. */
|
|
69
77
|
export type APIActionRowChild = APIButtonComponent | APIStringSelectComponent | APIEntitySelectComponent | APITextInputComponent;
|
|
78
|
+
/** An action row as a builder sends it: up to five buttons, or one select menu or text input. Exported from `lunibee` as `APIActionRowPayload`. */
|
|
70
79
|
export interface APIActionRowComponent {
|
|
71
80
|
type: typeof ComponentEnum.ActionRow;
|
|
72
81
|
components: APIActionRowChild[];
|
|
73
82
|
}
|
|
83
|
+
/** A Components V2 section: up to three text displays with an accessory. */
|
|
74
84
|
export interface APISectionComponent {
|
|
75
85
|
type: typeof ComponentEnum.Section;
|
|
76
86
|
components?: APIComponent[];
|
|
77
87
|
accessory?: APIComponent;
|
|
78
88
|
}
|
|
89
|
+
/** A Components V2 text display (Markdown content). */
|
|
79
90
|
export interface APITextDisplayComponent {
|
|
80
91
|
type: typeof ComponentEnum.TextDisplay;
|
|
81
92
|
content: string;
|
|
82
93
|
}
|
|
94
|
+
/** A Components V2 media gallery; each item is `{ media: { url }, description?, spoiler? }`. */
|
|
83
95
|
export interface APIMediaGalleryComponent {
|
|
84
96
|
type: typeof ComponentEnum.MediaGallery;
|
|
85
97
|
items: {
|
|
86
98
|
media: {
|
|
87
99
|
url: string;
|
|
88
|
-
description?: string;
|
|
89
100
|
};
|
|
101
|
+
description?: string;
|
|
102
|
+
spoiler?: boolean;
|
|
90
103
|
}[];
|
|
91
104
|
}
|
|
92
105
|
/** Default values accepted by an auto-populated entity select. */
|
|
@@ -94,6 +107,7 @@ export interface APISelectDefaultValue {
|
|
|
94
107
|
id: string;
|
|
95
108
|
type: "user" | "role" | "channel";
|
|
96
109
|
}
|
|
110
|
+
/** A Components V2 file display for an uploaded attachment. */
|
|
97
111
|
export interface APIFileComponent {
|
|
98
112
|
type: typeof ComponentEnum.File;
|
|
99
113
|
file: {
|
|
@@ -101,30 +115,34 @@ export interface APIFileComponent {
|
|
|
101
115
|
};
|
|
102
116
|
spoiler?: boolean;
|
|
103
117
|
}
|
|
118
|
+
/** A Components V2 separator, with optional divider line and spacing. */
|
|
104
119
|
export interface APISeparatorComponent {
|
|
105
120
|
type: typeof ComponentEnum.Separator;
|
|
106
121
|
spacing?: 1 | 2;
|
|
107
122
|
divider?: boolean;
|
|
108
123
|
}
|
|
124
|
+
/** A Components V2 thumbnail: `{ type: 11, media: { url }, description?, spoiler? }`. */
|
|
109
125
|
export interface APIThumbnailComponent {
|
|
110
126
|
type: typeof ComponentEnum.Thumbnail;
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
height?: number;
|
|
127
|
+
media: {
|
|
128
|
+
url: string;
|
|
129
|
+
};
|
|
115
130
|
description?: string;
|
|
116
131
|
spoiler?: boolean;
|
|
117
132
|
}
|
|
133
|
+
/** A Components V2 content inventory entry. */
|
|
118
134
|
export interface APIContentInventoryEntryComponent {
|
|
119
135
|
type: typeof ComponentEnum.ContentInventoryEntry;
|
|
120
136
|
id: string;
|
|
121
137
|
}
|
|
138
|
+
/** A Components V2 container: a box around other components, with an optional accent colour. */
|
|
122
139
|
export interface APIContainerComponent {
|
|
123
140
|
type: typeof ComponentEnum.Container;
|
|
124
141
|
components: APIComponent[];
|
|
125
142
|
accent_color?: number;
|
|
126
143
|
spoiler?: boolean;
|
|
127
144
|
}
|
|
145
|
+
/** Any top-level message component: an action row or a Components V2 layout component. */
|
|
128
146
|
export type APIComponent = APIActionRowComponent | APIButtonComponent | APIStringSelectComponent | APIEntitySelectComponent | APITextInputComponent | APISectionComponent | APITextDisplayComponent | APIThumbnailComponent | APIMediaGalleryComponent | APIFileComponent | APISeparatorComponent | APIContentInventoryEntryComponent | APIContainerComponent;
|
|
129
147
|
export declare class CreateActionRow<T extends {
|
|
130
148
|
toJSON(): APIActionRowChild;
|
|
@@ -225,6 +243,7 @@ export declare class CreateMediaGallery {
|
|
|
225
243
|
addItems(...items: {
|
|
226
244
|
url: string;
|
|
227
245
|
description?: string;
|
|
246
|
+
spoiler?: boolean;
|
|
228
247
|
}[]): this;
|
|
229
248
|
toJSON(): APIMediaGalleryComponent;
|
|
230
249
|
}
|
package/dist/builders/embed.d.ts
CHANGED
|
@@ -90,5 +90,6 @@ export declare class CreateEmbed {
|
|
|
90
90
|
clearDescription(): this;
|
|
91
91
|
/** Returns a deep-cloned Discord API payload. @returns Strict embed payload. */
|
|
92
92
|
get data(): APIEmbed;
|
|
93
|
+
/** Returns a deep-cloned Discord API payload. @returns Strict embed payload. @throws {RangeError} If the text in the embed adds up to more than Discord's 6000-character limit. */
|
|
93
94
|
toJSON(): APIEmbed;
|
|
94
95
|
}
|
package/dist/builders/index.js
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
// packages/builders/src/clone.ts
|
|
3
|
+
function cloneData(value, depth = 0) {
|
|
4
|
+
if (value === null || typeof value !== "object")
|
|
5
|
+
return value;
|
|
6
|
+
if (depth > 64)
|
|
7
|
+
return structuredClone(value);
|
|
8
|
+
if (Array.isArray(value)) {
|
|
9
|
+
const out = new Array(value.length);
|
|
10
|
+
for (let i = 0;i < value.length; i++)
|
|
11
|
+
out[i] = cloneData(value[i], depth + 1);
|
|
12
|
+
return out;
|
|
13
|
+
}
|
|
14
|
+
const proto = Object.getPrototypeOf(value);
|
|
15
|
+
if (proto !== Object.prototype && proto !== null)
|
|
16
|
+
return structuredClone(value);
|
|
17
|
+
const from = value;
|
|
18
|
+
const out = {};
|
|
19
|
+
for (const key of Object.keys(from))
|
|
20
|
+
out[key] = cloneData(from[key], depth + 1);
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
|
|
2
24
|
// packages/builders/src/embed.ts
|
|
3
25
|
class CreateEmbed {
|
|
4
26
|
#data = {};
|
|
@@ -94,7 +116,11 @@ class CreateEmbed {
|
|
|
94
116
|
const current = [...this.#data.fields ?? []];
|
|
95
117
|
if (!Number.isInteger(index) || !Number.isInteger(deleteCount) || index < 0 || deleteCount < 0)
|
|
96
118
|
throw new RangeError("Field index and delete count must be non-negative integers.");
|
|
97
|
-
|
|
119
|
+
for (const field of fields) {
|
|
120
|
+
validate(field.name, 256, "Embed field name");
|
|
121
|
+
validate(field.value, 1024, "Embed field value");
|
|
122
|
+
}
|
|
123
|
+
current.splice(index, deleteCount, ...fields.map((f) => ({ ...f })));
|
|
98
124
|
if (current.length > 25)
|
|
99
125
|
throw new RangeError("An embed cannot contain more than 25 fields.");
|
|
100
126
|
this.#data.fields = current;
|
|
@@ -116,7 +142,11 @@ class CreateEmbed {
|
|
|
116
142
|
return this.toJSON();
|
|
117
143
|
}
|
|
118
144
|
toJSON() {
|
|
119
|
-
|
|
145
|
+
const data = this.#data;
|
|
146
|
+
const total = (data.title?.length ?? 0) + (data.description?.length ?? 0) + (data.footer?.text.length ?? 0) + (data.author?.name.length ?? 0) + (data.fields ?? []).reduce((sum, field) => sum + field.name.length + field.value.length, 0);
|
|
147
|
+
if (total > 6000)
|
|
148
|
+
throw new RangeError(`An embed cannot contain more than 6000 characters in total (this one has ${total}).`);
|
|
149
|
+
return cloneData(data);
|
|
120
150
|
}
|
|
121
151
|
}
|
|
122
152
|
function validate(value, max, field) {
|
|
@@ -125,11 +155,15 @@ function validate(value, max, field) {
|
|
|
125
155
|
return value;
|
|
126
156
|
}
|
|
127
157
|
function url(value, field) {
|
|
158
|
+
let parsed;
|
|
128
159
|
try {
|
|
129
|
-
|
|
160
|
+
parsed = new URL(value);
|
|
130
161
|
} catch (error) {
|
|
131
162
|
throw new TypeError(`${field} must be a valid URL.`, { cause: error });
|
|
132
163
|
}
|
|
164
|
+
if (!["http:", "https:", "attachment:"].includes(parsed.protocol))
|
|
165
|
+
throw new TypeError(`${field} must use http, https or attachment.`);
|
|
166
|
+
return parsed.toString();
|
|
133
167
|
}
|
|
134
168
|
// packages/types/src/channel-kind.ts
|
|
135
169
|
var ChannelKinds = {
|
|
@@ -323,7 +357,7 @@ class CreateStringSelect extends CreateSelectMenu {
|
|
|
323
357
|
throw new RangeError("A string select needs at least one option.");
|
|
324
358
|
if ((this.#data.max_values ?? 1) > count)
|
|
325
359
|
throw new RangeError("max_values cannot exceed the number of options.");
|
|
326
|
-
return
|
|
360
|
+
return cloneData(this.#data);
|
|
327
361
|
}
|
|
328
362
|
}
|
|
329
363
|
|
|
@@ -371,6 +405,8 @@ class CreateButton {
|
|
|
371
405
|
cause: error
|
|
372
406
|
});
|
|
373
407
|
}
|
|
408
|
+
if (!["http:", "https:", "discord:"].includes(url.protocol))
|
|
409
|
+
throw new TypeError("Button URL must use http, https or discord.");
|
|
374
410
|
this.setStyle(ButtonType.Link);
|
|
375
411
|
this.#data.url = url.toString();
|
|
376
412
|
return this;
|
|
@@ -409,7 +445,7 @@ class CreateButton {
|
|
|
409
445
|
}
|
|
410
446
|
if (data.style !== ButtonType.Premium && !data.label && !data.emoji)
|
|
411
447
|
throw new TypeError("Buttons require a label or an emoji.");
|
|
412
|
-
return
|
|
448
|
+
return cloneData(data);
|
|
413
449
|
}
|
|
414
450
|
}
|
|
415
451
|
|
|
@@ -428,7 +464,7 @@ class CreateEntitySelect extends CreateSelectMenu {
|
|
|
428
464
|
}
|
|
429
465
|
toJSON() {
|
|
430
466
|
assertSelect(this.#data);
|
|
431
|
-
return
|
|
467
|
+
return cloneData(this.#data);
|
|
432
468
|
}
|
|
433
469
|
}
|
|
434
470
|
|
|
@@ -520,7 +556,7 @@ class CreateTextInput {
|
|
|
520
556
|
throw new TypeError("Text inputs require a custom ID.");
|
|
521
557
|
if (data.min_length !== undefined && data.max_length !== undefined && data.min_length > data.max_length)
|
|
522
558
|
throw new RangeError("min_length cannot exceed max_length.");
|
|
523
|
-
return
|
|
559
|
+
return cloneData(data);
|
|
524
560
|
}
|
|
525
561
|
}
|
|
526
562
|
|
|
@@ -604,13 +640,17 @@ class CreateMediaGallery {
|
|
|
604
640
|
if (this.#items.length + items.length > 10) {
|
|
605
641
|
throw new RangeError("MediaGallery can only contain up to 10 items.");
|
|
606
642
|
}
|
|
607
|
-
this.#items.push(...items.map((
|
|
643
|
+
this.#items.push(...items.map(({ url, description, spoiler }) => ({
|
|
644
|
+
media: { url },
|
|
645
|
+
...description !== undefined ? { description } : {},
|
|
646
|
+
...spoiler !== undefined ? { spoiler } : {}
|
|
647
|
+
})));
|
|
608
648
|
return this;
|
|
609
649
|
}
|
|
610
650
|
toJSON() {
|
|
611
651
|
return {
|
|
612
652
|
type: ComponentEnum.MediaGallery,
|
|
613
|
-
items:
|
|
653
|
+
items: cloneData(this.#items)
|
|
614
654
|
};
|
|
615
655
|
}
|
|
616
656
|
}
|
|
@@ -684,7 +724,7 @@ class CreateThumbnail {
|
|
|
684
724
|
toJSON() {
|
|
685
725
|
const data = {
|
|
686
726
|
type: ComponentEnum.Thumbnail,
|
|
687
|
-
url: this.#url
|
|
727
|
+
media: { url: this.#url }
|
|
688
728
|
};
|
|
689
729
|
if (this.#description !== undefined)
|
|
690
730
|
data.description = this.#description;
|
|
@@ -849,7 +889,7 @@ class CreateSlashCommand {
|
|
|
849
889
|
return this.addOption(configure(new CreateSubcommandGroup));
|
|
850
890
|
}
|
|
851
891
|
toJSON() {
|
|
852
|
-
return
|
|
892
|
+
return cloneData(this.#data);
|
|
853
893
|
}
|
|
854
894
|
addOption(option) {
|
|
855
895
|
this.#data.options = appendOption(this.#data.options, option.toJSON(), "application command");
|
|
@@ -877,11 +917,13 @@ class CreateCommandOption {
|
|
|
877
917
|
return this;
|
|
878
918
|
}
|
|
879
919
|
setAutocomplete(enabled = true) {
|
|
920
|
+
if (enabled && Array.isArray(this.data.choices) && this.data.choices.length)
|
|
921
|
+
throw new RangeError("Autocomplete options cannot define choices.");
|
|
880
922
|
this.data.autocomplete = enabled;
|
|
881
923
|
return this;
|
|
882
924
|
}
|
|
883
925
|
toJSON() {
|
|
884
|
-
return
|
|
926
|
+
return cloneData(this.data);
|
|
885
927
|
}
|
|
886
928
|
}
|
|
887
929
|
|
|
@@ -917,6 +959,9 @@ class CreateNumericOption extends CreateCommandOption {
|
|
|
917
959
|
}
|
|
918
960
|
setMinValue(value) {
|
|
919
961
|
validateNumberRange(value, -MAX_SAFE, MAX_SAFE, "min_value", this.#integer);
|
|
962
|
+
const max = this.data.max_value;
|
|
963
|
+
if (max !== undefined && value > max)
|
|
964
|
+
throw new RangeError("min_value cannot exceed max_value.");
|
|
920
965
|
this.data.min_value = value;
|
|
921
966
|
return this;
|
|
922
967
|
}
|
|
@@ -1071,8 +1116,12 @@ function appendChoices(data, choices) {
|
|
|
1071
1116
|
throw new RangeError("Autocomplete options cannot define choices.");
|
|
1072
1117
|
if (current.length + choices.length > 25)
|
|
1073
1118
|
throw new RangeError("An option cannot contain more than 25 choices.");
|
|
1074
|
-
for (const choice of choices)
|
|
1119
|
+
for (const choice of choices) {
|
|
1075
1120
|
validateText2(choice.name, "Choice name", 100);
|
|
1121
|
+
const value = choice.value;
|
|
1122
|
+
if (typeof value === "string" ? value.length === 0 || value.length > 100 : typeof value !== "number" || !Number.isFinite(value))
|
|
1123
|
+
throw new TypeError("Choice value must be a string of 1-100 characters or a finite number.");
|
|
1124
|
+
}
|
|
1076
1125
|
data.choices = [...current, ...choices.map((choice) => ({ ...choice }))];
|
|
1077
1126
|
}
|
|
1078
1127
|
function validateName(value, field) {
|
|
@@ -1127,7 +1176,7 @@ class CreateContextMenuCommand {
|
|
|
1127
1176
|
return this;
|
|
1128
1177
|
}
|
|
1129
1178
|
toJSON() {
|
|
1130
|
-
return
|
|
1179
|
+
return cloneData(this.data);
|
|
1131
1180
|
}
|
|
1132
1181
|
}
|
|
1133
1182
|
|
|
@@ -1194,12 +1243,14 @@ class CreateAttachment {
|
|
|
1194
1243
|
}
|
|
1195
1244
|
}
|
|
1196
1245
|
async function insideRoot(root, file) {
|
|
1197
|
-
const base = await realpath(root)
|
|
1246
|
+
const base = await realpath(root).catch(() => {
|
|
1247
|
+
throw new Error("Attachment root folder was not found.");
|
|
1248
|
+
});
|
|
1198
1249
|
const target = await realpath(resolve(base, file)).catch(() => {
|
|
1199
1250
|
throw new Error("Attachment file was not found inside its root.");
|
|
1200
1251
|
});
|
|
1201
1252
|
const rel = relative(base, target);
|
|
1202
|
-
if (rel === "" || rel.startsWith("
|
|
1253
|
+
if (rel === "" || rel === ".." || rel.startsWith("../") || rel.startsWith("..\\") || isAbsolute(rel))
|
|
1203
1254
|
throw new Error("Attachment file is outside its root folder.");
|
|
1204
1255
|
return target;
|
|
1205
1256
|
}
|
|
@@ -1248,4 +1299,4 @@ export {
|
|
|
1248
1299
|
componentsV2Message
|
|
1249
1300
|
};
|
|
1250
1301
|
|
|
1251
|
-
//# debugId=
|
|
1302
|
+
//# debugId=53A00A51A367F67A64756E2164756E21
|