@discordjs/builders 2.0.0-djs-file-upload.1761302390-5ae769c9e → 2.0.0-pr-11006.1765450224-e636950b2

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/index.mjs CHANGED
@@ -95,15 +95,15 @@ import { Locale } from "discord-api-types/v10";
95
95
  import { z as z2 } from "zod";
96
96
  var idPredicate = z2.int().min(0).max(2147483647).optional();
97
97
  var customIdPredicate = z2.string().min(1).max(100);
98
+ var snowflakePredicate = z2.string().regex(/^(?:0|[1-9]\d*)$/);
98
99
  var memberPermissionsPredicate = z2.coerce.bigint();
99
100
  var localeMapPredicate = z2.strictObject(
100
101
  Object.fromEntries(Object.values(Locale).map((loc) => [loc, z2.string().optional()]))
101
102
  );
102
103
 
103
104
  // src/components/Assertions.ts
104
- var labelPredicate = z3.string().min(1).max(80);
105
105
  var emojiPredicate = z3.strictObject({
106
- id: z3.string().optional(),
106
+ id: snowflakePredicate.optional(),
107
107
  name: z3.string().min(2).max(32).optional(),
108
108
  animated: z3.boolean().optional()
109
109
  }).refine((data) => data.id !== void 0 || data.name !== void 0, {
@@ -113,24 +113,29 @@ var buttonPredicateBase = z3.strictObject({
113
113
  type: z3.literal(ComponentType.Button),
114
114
  disabled: z3.boolean().optional()
115
115
  });
116
+ var buttonLabelPredicate = z3.string().min(1).max(80);
116
117
  var buttonCustomIdPredicateBase = buttonPredicateBase.extend({
117
118
  custom_id: customIdPredicate,
118
119
  emoji: emojiPredicate.optional(),
119
- label: labelPredicate
120
+ label: buttonLabelPredicate.optional()
121
+ }).refine((data) => data.emoji !== void 0 || data.label !== void 0, {
122
+ message: "Buttons with a custom id must have either an emoji or a label."
120
123
  });
121
- var buttonPrimaryPredicate = buttonCustomIdPredicateBase.extend({ style: z3.literal(ButtonStyle.Primary) });
122
- var buttonSecondaryPredicate = buttonCustomIdPredicateBase.extend({ style: z3.literal(ButtonStyle.Secondary) });
123
- var buttonSuccessPredicate = buttonCustomIdPredicateBase.extend({ style: z3.literal(ButtonStyle.Success) });
124
- var buttonDangerPredicate = buttonCustomIdPredicateBase.extend({ style: z3.literal(ButtonStyle.Danger) });
124
+ var buttonPrimaryPredicate = buttonCustomIdPredicateBase.safeExtend({ style: z3.literal(ButtonStyle.Primary) });
125
+ var buttonSecondaryPredicate = buttonCustomIdPredicateBase.safeExtend({ style: z3.literal(ButtonStyle.Secondary) });
126
+ var buttonSuccessPredicate = buttonCustomIdPredicateBase.safeExtend({ style: z3.literal(ButtonStyle.Success) });
127
+ var buttonDangerPredicate = buttonCustomIdPredicateBase.safeExtend({ style: z3.literal(ButtonStyle.Danger) });
125
128
  var buttonLinkPredicate = buttonPredicateBase.extend({
126
129
  style: z3.literal(ButtonStyle.Link),
127
130
  url: z3.url({ protocol: /^(?:https?|discord)$/ }).max(512),
128
131
  emoji: emojiPredicate.optional(),
129
- label: labelPredicate
132
+ label: buttonLabelPredicate.optional()
133
+ }).refine((data) => data.emoji !== void 0 || data.label !== void 0, {
134
+ message: "Link buttons must have either an emoji or a label."
130
135
  });
131
136
  var buttonPremiumPredicate = buttonPredicateBase.extend({
132
137
  style: z3.literal(ButtonStyle.Premium),
133
- sku_id: z3.string()
138
+ sku_id: snowflakePredicate
134
139
  });
135
140
  var buttonPredicate = z3.discriminatedUnion("style", [
136
141
  buttonLinkPredicate,
@@ -151,21 +156,21 @@ var selectMenuBasePredicate = z3.object({
151
156
  var selectMenuChannelPredicate = selectMenuBasePredicate.extend({
152
157
  type: z3.literal(ComponentType.ChannelSelect),
153
158
  channel_types: z3.enum(ChannelType).array().optional(),
154
- default_values: z3.object({ id: z3.string(), type: z3.literal(SelectMenuDefaultValueType.Channel) }).array().max(25).optional()
159
+ default_values: z3.object({ id: snowflakePredicate, type: z3.literal(SelectMenuDefaultValueType.Channel) }).array().max(25).optional()
155
160
  });
156
161
  var selectMenuMentionablePredicate = selectMenuBasePredicate.extend({
157
162
  type: z3.literal(ComponentType.MentionableSelect),
158
163
  default_values: z3.object({
159
- id: z3.string(),
164
+ id: snowflakePredicate,
160
165
  type: z3.literal([SelectMenuDefaultValueType.Role, SelectMenuDefaultValueType.User])
161
166
  }).array().max(25).optional()
162
167
  });
163
168
  var selectMenuRolePredicate = selectMenuBasePredicate.extend({
164
169
  type: z3.literal(ComponentType.RoleSelect),
165
- default_values: z3.object({ id: z3.string(), type: z3.literal(SelectMenuDefaultValueType.Role) }).array().max(25).optional()
170
+ default_values: z3.object({ id: snowflakePredicate, type: z3.literal(SelectMenuDefaultValueType.Role) }).array().max(25).optional()
166
171
  });
167
172
  var selectMenuStringOptionPredicate = z3.object({
168
- label: labelPredicate,
173
+ label: z3.string().min(1).max(100),
169
174
  value: z3.string().min(1).max(100),
170
175
  description: z3.string().min(1).max(100).optional(),
171
176
  emoji: emojiPredicate.optional(),
@@ -203,7 +208,7 @@ var selectMenuStringPredicate = selectMenuBasePredicate.extend({
203
208
  });
204
209
  var selectMenuUserPredicate = selectMenuBasePredicate.extend({
205
210
  type: z3.literal(ComponentType.UserSelect),
206
- default_values: z3.object({ id: z3.string(), type: z3.literal(SelectMenuDefaultValueType.User) }).array().max(25).optional()
211
+ default_values: z3.object({ id: snowflakePredicate, type: z3.literal(SelectMenuDefaultValueType.User) }).array().max(25).optional()
207
212
  });
208
213
  var actionRowPredicate = z3.object({
209
214
  id: idPredicate,
@@ -390,7 +395,7 @@ import { ComponentType as ComponentType5 } from "discord-api-types/v10";
390
395
  import { z as z4 } from "zod";
391
396
  var fileUploadPredicate = z4.object({
392
397
  type: z4.literal(ComponentType5.FileUpload),
393
- id: z4.int().min(0).optional(),
398
+ id: idPredicate,
394
399
  custom_id: customIdPredicate,
395
400
  min_values: z4.int().min(0).max(10).optional(),
396
401
  max_values: z4.int().min(1).max(10).optional(),
@@ -461,7 +466,7 @@ var FileUploadBuilder = class extends ComponentBuilder {
461
466
  /**
462
467
  * Sets the maximum number of file uploads required.
463
468
  *
464
- * @param maxValues - The maximum values that must be uploaded
469
+ * @param maxValues - The maximum values that can be uploaded
465
470
  */
466
471
  setMaxValues(maxValues) {
467
472
  this.data.max_values = maxValues;
@@ -562,9 +567,9 @@ var BaseSelectMenuBuilder = class extends ComponentBuilder {
562
567
  return this;
563
568
  }
564
569
  /**
565
- * Sets the maximum values that must be selected in the select menu.
570
+ * Sets the maximum values that can be selected in the select menu.
566
571
  *
567
- * @param maxValues - The maximum values that must be selected
572
+ * @param maxValues - The maximum values that can be selected
568
573
  */
569
574
  setMaxValues(maxValues) {
570
575
  this.data.max_values = maxValues;
@@ -2512,7 +2517,7 @@ __name(resolveAccessoryComponent, "resolveAccessoryComponent");
2512
2517
  // src/components/label/Assertions.ts
2513
2518
  import { ComponentType as ComponentType24 } from "discord-api-types/v10";
2514
2519
  import { z as z7 } from "zod";
2515
- var labelPredicate2 = z7.object({
2520
+ var labelPredicate = z7.object({
2516
2521
  id: idPredicate,
2517
2522
  type: z7.literal(ComponentType24.Label),
2518
2523
  label: z7.string().min(1).max(45),
@@ -2665,7 +2670,7 @@ var LabelBuilder = class extends ComponentBuilder {
2665
2670
  // The label predicate validates the component.
2666
2671
  component: component?.toJSON(false)
2667
2672
  };
2668
- validate(labelPredicate2, data, validationOverride);
2673
+ validate(labelPredicate, data, validationOverride);
2669
2674
  return data;
2670
2675
  }
2671
2676
  };
@@ -2995,8 +3000,8 @@ var numberOptionPredicate = z8.object({
2995
3000
  ...numericMixinNumberOptionPredicate.shape
2996
3001
  }).and(autocompleteOrNumberChoicesMixinOptionPredicate);
2997
3002
  var stringOptionPredicate = basicOptionPredicate.extend({
2998
- max_length: z8.number().min(0).max(6e3).optional(),
2999
- min_length: z8.number().min(1).max(6e3).optional()
3003
+ max_length: z8.number().min(1).max(6e3).optional(),
3004
+ min_length: z8.number().min(0).max(6e3).optional()
3000
3005
  }).and(autocompleteOrStringChoicesMixinOptionPredicate);
3001
3006
  var baseChatInputCommandPredicate = sharedNameAndDescriptionPredicate.extend({
3002
3007
  contexts: z8.array(z8.enum(InteractionContextType)).optional(),
@@ -3006,8 +3011,12 @@ var baseChatInputCommandPredicate = sharedNameAndDescriptionPredicate.extend({
3006
3011
  });
3007
3012
  var chatInputCommandOptionsPredicate = z8.union([
3008
3013
  z8.object({ type: basicOptionTypesPredicate }).array(),
3009
- z8.object({ type: z8.literal(ApplicationCommandOptionType.Subcommand) }).array(),
3010
- z8.object({ type: z8.literal(ApplicationCommandOptionType.SubcommandGroup) }).array()
3014
+ z8.object({
3015
+ type: z8.union([
3016
+ z8.literal(ApplicationCommandOptionType.Subcommand),
3017
+ z8.literal(ApplicationCommandOptionType.SubcommandGroup)
3018
+ ])
3019
+ }).array()
3011
3020
  ]);
3012
3021
  var chatInputCommandPredicate = baseChatInputCommandPredicate.extend({
3013
3022
  options: chatInputCommandOptionsPredicate.optional()
@@ -3658,7 +3667,7 @@ var modalPredicate = z10.object({
3658
3667
  type: z10.literal(ComponentType26.ActionRow),
3659
3668
  components: z10.object({ type: z10.literal(ComponentType26.TextInput) }).array().length(1)
3660
3669
  }),
3661
- labelPredicate2,
3670
+ labelPredicate,
3662
3671
  textDisplayPredicate
3663
3672
  ]).array().min(1).max(5)
3664
3673
  });
@@ -3782,15 +3791,8 @@ var ModalBuilder = class {
3782
3791
  };
3783
3792
 
3784
3793
  // src/messages/embed/Assertions.ts
3794
+ import { embedLength } from "@discordjs/util";
3785
3795
  import { z as z11 } from "zod";
3786
-
3787
- // src/util/componentUtil.ts
3788
- function embedLength(data) {
3789
- return (data.title?.length ?? 0) + (data.description?.length ?? 0) + (data.fields?.reduce((prev, curr) => prev + curr.name.length + curr.value.length, 0) ?? 0) + (data.footer?.text.length ?? 0) + (data.author?.name.length ?? 0);
3790
- }
3791
- __name(embedLength, "embedLength");
3792
-
3793
- // src/messages/embed/Assertions.ts
3794
3796
  var namePredicate3 = z11.string().max(256);
3795
3797
  var URLPredicate = z11.url({ protocol: /^https?$/ });
3796
3798
  var URLWithAttachmentProtocolPredicate = z11.url({ protocol: /^(?:https?|attachment)$/ });
@@ -4645,10 +4647,19 @@ var PollBuilder = class {
4645
4647
  };
4646
4648
 
4647
4649
  // src/messages/Assertions.ts
4650
+ import { Buffer as Buffer2 } from "buffer";
4648
4651
  import { AllowedMentionsTypes, ComponentType as ComponentType27, MessageFlags, MessageReferenceType } from "discord-api-types/v10";
4649
4652
  import { z as z13 } from "zod";
4653
+ var fileKeyRegex = /^files\[(?<placeholder>\d+?)]$/;
4654
+ var rawFilePredicate = z13.object({
4655
+ data: z13.union([z13.instanceof(Buffer2), z13.instanceof(Uint8Array), z13.string()]),
4656
+ name: z13.string().min(1),
4657
+ contentType: z13.string().optional(),
4658
+ key: z13.string().regex(fileKeyRegex).optional()
4659
+ });
4650
4660
  var attachmentPredicate = z13.object({
4651
- id: z13.union([z13.string(), z13.number()]),
4661
+ // As a string it only makes sense for edits when we do have an attachment snowflake
4662
+ id: z13.union([snowflakePredicate, z13.number()]),
4652
4663
  description: z13.string().max(1024).optional(),
4653
4664
  duration_secs: z13.number().max(2 ** 31 - 1).optional(),
4654
4665
  filename: z13.string().max(1024).optional(),
@@ -4734,6 +4745,11 @@ var messageComponentsV2Predicate = baseMessagePredicate.extend({
4734
4745
  poll: z13.null().optional()
4735
4746
  });
4736
4747
  var messagePredicate = z13.union([messageNoComponentsV2Predicate, messageComponentsV2Predicate]);
4748
+ var fileBodyMessagePredicate = z13.object({
4749
+ body: messagePredicate,
4750
+ // No min length to support message edits
4751
+ files: rawFilePredicate.array().max(10)
4752
+ });
4737
4753
 
4738
4754
  // src/messages/AllowedMentions.ts
4739
4755
  var AllowedMentionsBuilder = class {
@@ -4918,13 +4934,29 @@ var AttachmentBuilder = class {
4918
4934
  * The API data associated with this attachment.
4919
4935
  */
4920
4936
  data;
4937
+ /**
4938
+ * This data is not included in the output of `toJSON()`. For this class specifically, this refers to binary data
4939
+ * that will wind up being included in the multipart/form-data request, if used with the `MessageBuilder`.
4940
+ * To retrieve this data, use {@link getRawFile}.
4941
+ *
4942
+ * @remarks This cannot be set via the constructor, primarily because of the behavior described
4943
+ * {@link https://discord.com/developers/docs/reference#editing-message-attachments | here}.
4944
+ * That is, when editing a message's attachments, you should only be providing file data for new attachments.
4945
+ */
4946
+ fileData;
4921
4947
  /**
4922
4948
  * Creates a new attachment builder.
4923
4949
  *
4924
4950
  * @param data - The API data to create this attachment with
4951
+ * @example
4952
+ * ```ts
4953
+ * const attachment = new AttachmentBuilder().setId(1).setFileData(':)').setFilename('smiley.txt')
4954
+ * ```
4955
+ * @remarks Please note that the `id` field is required, it's rather easy to miss!
4925
4956
  */
4926
4957
  constructor(data = {}) {
4927
4958
  this.data = structuredClone(data);
4959
+ this.fileData = {};
4928
4960
  }
4929
4961
  /**
4930
4962
  * Sets the id of the attachment.
@@ -4983,6 +5015,54 @@ var AttachmentBuilder = class {
4983
5015
  this.data.filename = void 0;
4984
5016
  return this;
4985
5017
  }
5018
+ /**
5019
+ * Sets the file data to upload with this attachment.
5020
+ *
5021
+ * @param data - The file data
5022
+ * @remarks Note that this data is NOT included in the {@link toJSON} output. To retrieve it, use {@link getRawFile}.
5023
+ */
5024
+ setFileData(data) {
5025
+ this.fileData.data = data;
5026
+ return this;
5027
+ }
5028
+ /**
5029
+ * Clears the file data from this attachment.
5030
+ */
5031
+ clearFileData() {
5032
+ this.fileData.data = void 0;
5033
+ return this;
5034
+ }
5035
+ /**
5036
+ * Sets the content type of the file data to upload with this attachment.
5037
+ *
5038
+ * @remarks Note that this data is NOT included in the {@link toJSON} output. To retrieve it, use {@link getRawFile}.
5039
+ */
5040
+ setFileContentType(contentType) {
5041
+ this.fileData.contentType = contentType;
5042
+ return this;
5043
+ }
5044
+ /**
5045
+ * Clears the content type of the file data from this attachment.
5046
+ */
5047
+ clearFileContentType() {
5048
+ this.fileData.contentType = void 0;
5049
+ return this;
5050
+ }
5051
+ /**
5052
+ * Converts this attachment to a {@link RawFile} for uploading.
5053
+ *
5054
+ * @returns A {@link RawFile} object, or `undefined` if no file data is set
5055
+ */
5056
+ getRawFile() {
5057
+ if (!this.fileData?.data) {
5058
+ return;
5059
+ }
5060
+ return {
5061
+ ...this.fileData,
5062
+ name: this.data.filename,
5063
+ key: this.data.id === void 0 ? void 0 : `files[${this.data.id}]`
5064
+ };
5065
+ }
4986
5066
  /**
4987
5067
  * Sets the title of this attachment.
4988
5068
  *
@@ -5287,7 +5367,7 @@ var MessageBuilder = class {
5287
5367
  *
5288
5368
  * @param allowedMentions - The allowed mentions to set
5289
5369
  */
5290
- setAllowedMentions(allowedMentions) {
5370
+ setAllowedMentions(allowedMentions = new AllowedMentionsBuilder()) {
5291
5371
  this.data.allowed_mentions = resolveBuilder(allowedMentions, AllowedMentionsBuilder);
5292
5372
  return this;
5293
5373
  }
@@ -5620,10 +5700,31 @@ var MessageBuilder = class {
5620
5700
  validate(messagePredicate, data, validationOverride);
5621
5701
  return data;
5622
5702
  }
5703
+ /**
5704
+ * Serializes this builder to both JSON body and file data for multipart/form-data requests.
5705
+ *
5706
+ * @param validationOverride - Force validation to run/not run regardless of your global preference
5707
+ * @remarks
5708
+ * This method extracts file data from attachments that have files set via {@link AttachmentBuilder.setFileData}.
5709
+ * The returned body includes attachment metadata, while files contains the binary data for upload.
5710
+ */
5711
+ toFileBody(validationOverride) {
5712
+ const body = this.toJSON(false);
5713
+ const files = [];
5714
+ for (const attachment of this.data.attachments) {
5715
+ const rawFile = attachment.getRawFile();
5716
+ if (rawFile?.data || rawFile?.contentType) {
5717
+ files.push(rawFile);
5718
+ }
5719
+ }
5720
+ const combined = { body, files };
5721
+ validate(fileBodyMessagePredicate, combined, validationOverride);
5722
+ return combined;
5723
+ }
5623
5724
  };
5624
5725
 
5625
5726
  // src/index.ts
5626
- var version = "2.0.0-djs-file-upload.1761302390-5ae769c9e";
5727
+ var version = "2.0.0-pr-11006.1765450224-e636950b2";
5627
5728
  export {
5628
5729
  ActionRowBuilder,
5629
5730
  AllowedMentionsBuilder,
@@ -5711,16 +5812,16 @@ export {
5711
5812
  embedAuthorPredicate,
5712
5813
  embedFieldPredicate,
5713
5814
  embedFooterPredicate,
5714
- embedLength,
5715
5815
  embedPredicate,
5716
5816
  emojiPredicate,
5717
5817
  enableValidators,
5818
+ fileBodyMessagePredicate,
5718
5819
  filePredicate,
5719
5820
  fileUploadPredicate,
5720
5821
  idPredicate,
5721
5822
  integerOptionPredicate,
5722
5823
  isValidationEnabled,
5723
- labelPredicate2 as labelPredicate,
5824
+ labelPredicate,
5724
5825
  localeMapPredicate,
5725
5826
  mediaGalleryItemPredicate,
5726
5827
  mediaGalleryPredicate,
@@ -5735,6 +5836,7 @@ export {
5735
5836
  pollAnswerPredicate,
5736
5837
  pollPredicate,
5737
5838
  pollQuestionPredicate,
5839
+ rawFilePredicate,
5738
5840
  resolveAccessoryComponent,
5739
5841
  resolveBuilder,
5740
5842
  sectionPredicate,
@@ -5745,6 +5847,7 @@ export {
5745
5847
  selectMenuStringPredicate,
5746
5848
  selectMenuUserPredicate,
5747
5849
  separatorPredicate,
5850
+ snowflakePredicate,
5748
5851
  stringOptionPredicate,
5749
5852
  textDisplayPredicate,
5750
5853
  textInputPredicate,