@discordkit/core 3.2.0 → 4.0.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.
Files changed (178) hide show
  1. package/CHANGELOG.md +416 -0
  2. package/README.md +52 -0
  3. package/dist/index.d.mts +23 -0
  4. package/dist/index.mjs +23 -0
  5. package/dist/requests/DiscordSession.d.mts +30 -0
  6. package/dist/requests/DiscordSession.mjs +202 -0
  7. package/dist/requests/addParams.d.mts +15 -0
  8. package/dist/requests/addParams.mjs +24 -0
  9. package/dist/requests/buildURL.d.mts +7 -0
  10. package/dist/requests/buildURL.mjs +7 -0
  11. package/dist/requests/getAsset.d.mts +7 -0
  12. package/dist/requests/getAsset.mjs +6 -0
  13. package/dist/requests/index.d.mts +9 -0
  14. package/dist/requests/index.mjs +9 -0
  15. package/dist/requests/methods.d.mts +63 -0
  16. package/dist/requests/methods.mjs +10 -0
  17. package/dist/requests/request.d.mts +27 -0
  18. package/dist/requests/request.mjs +29 -0
  19. package/dist/requests/toProcedure.d.mts +40 -0
  20. package/dist/requests/toProcedure.mjs +27 -0
  21. package/dist/requests/toQuery.d.mts +36 -0
  22. package/dist/requests/toQuery.mjs +17 -0
  23. package/dist/requests/toValidated.d.mts +16 -0
  24. package/dist/requests/toValidated.mjs +25 -0
  25. package/dist/requests/{verifyKey.d.ts → verifyKey.d.mts} +4 -1
  26. package/dist/requests/verifyKey.mjs +63 -0
  27. package/dist/utils/isBetween.d.mts +4 -0
  28. package/dist/utils/isBetween.mjs +4 -0
  29. package/dist/utils/{isNonNullable.js → isNonNullable.d.mts} +5 -2
  30. package/dist/utils/isNonNullable.mjs +22 -0
  31. package/dist/utils/isNumericString.d.mts +4 -0
  32. package/dist/utils/isNumericString.mjs +4 -0
  33. package/dist/utils/isObject.d.mts +4 -0
  34. package/dist/utils/isObject.mjs +4 -0
  35. package/dist/utils/sleep.d.mts +7 -0
  36. package/dist/utils/sleep.mjs +7 -0
  37. package/dist/utils/toCamelCase.d.mts +4 -0
  38. package/dist/utils/toCamelCase.mjs +4 -0
  39. package/dist/utils/toCamelKeys.d.mts +6 -0
  40. package/dist/utils/toCamelKeys.mjs +13 -0
  41. package/dist/utils/toSnakeCase.d.mts +4 -0
  42. package/dist/utils/toSnakeCase.mjs +4 -0
  43. package/dist/utils/toSnakeKeys.d.mts +6 -0
  44. package/dist/utils/toSnakeKeys.mjs +13 -0
  45. package/dist/validations/asDigits.d.mts +12 -0
  46. package/dist/validations/asDigits.mjs +10 -0
  47. package/dist/validations/asInteger.d.mts +12 -0
  48. package/dist/validations/asInteger.mjs +10 -0
  49. package/dist/validations/bitfield.d.mts +23 -0
  50. package/dist/validations/bitfield.mjs +20 -0
  51. package/dist/validations/boundedArray.d.mts +13 -0
  52. package/dist/validations/boundedArray.mjs +9 -0
  53. package/dist/validations/boundedInteger.d.mts +13 -0
  54. package/dist/validations/boundedInteger.mjs +9 -0
  55. package/dist/validations/boundedString.d.mts +14 -0
  56. package/dist/validations/boundedString.mjs +10 -0
  57. package/dist/validations/datauri.d.mts +24 -0
  58. package/dist/validations/datauri.mjs +17 -0
  59. package/dist/validations/fileUpload.d.mts +129 -0
  60. package/dist/validations/fileUpload.mjs +114 -0
  61. package/dist/validations/hasMimeType.d.mts +16 -0
  62. package/dist/validations/hasMimeType.mjs +16 -0
  63. package/dist/validations/hasSize.d.mts +10 -0
  64. package/dist/validations/hasSize.mjs +12 -0
  65. package/dist/validations/index.d.mts +15 -0
  66. package/dist/validations/index.mjs +15 -0
  67. package/dist/validations/schema.d.mts +102 -0
  68. package/dist/validations/schema.mjs +109 -0
  69. package/dist/validations/{snowflake.d.ts → snowflake.d.mts} +9 -7
  70. package/dist/validations/snowflake.mjs +28 -0
  71. package/dist/validations/{timestamp.d.ts → timestamp.d.mts} +5 -1
  72. package/dist/validations/timestamp.mjs +6 -0
  73. package/dist/validations/toBlob.d.mts +9 -0
  74. package/dist/validations/toBlob.mjs +17 -0
  75. package/dist/validations/url.d.mts +6 -0
  76. package/dist/validations/url.mjs +5 -0
  77. package/package.json +13 -23
  78. package/dist/index.d.ts +0 -2
  79. package/dist/index.js +0 -3
  80. package/dist/index.js.map +0 -1
  81. package/dist/requests/DiscordSession.d.ts +0 -25
  82. package/dist/requests/DiscordSession.js +0 -255
  83. package/dist/requests/DiscordSession.js.map +0 -1
  84. package/dist/requests/addParams.d.ts +0 -2
  85. package/dist/requests/addParams.js +0 -11
  86. package/dist/requests/addParams.js.map +0 -1
  87. package/dist/requests/buildURL.d.ts +0 -2
  88. package/dist/requests/buildURL.js +0 -4
  89. package/dist/requests/buildURL.js.map +0 -1
  90. package/dist/requests/getAsset.d.ts +0 -2
  91. package/dist/requests/getAsset.js +0 -3
  92. package/dist/requests/getAsset.js.map +0 -1
  93. package/dist/requests/index.d.ts +0 -8
  94. package/dist/requests/index.js +0 -9
  95. package/dist/requests/index.js.map +0 -1
  96. package/dist/requests/methods.d.ts +0 -13
  97. package/dist/requests/methods.js +0 -8
  98. package/dist/requests/methods.js.map +0 -1
  99. package/dist/requests/request.d.ts +0 -2
  100. package/dist/requests/request.js +0 -30
  101. package/dist/requests/request.js.map +0 -1
  102. package/dist/requests/toProcedure.d.ts +0 -31
  103. package/dist/requests/toProcedure.js +0 -36
  104. package/dist/requests/toProcedure.js.map +0 -1
  105. package/dist/requests/toQuery.d.ts +0 -28
  106. package/dist/requests/toQuery.js +0 -9
  107. package/dist/requests/toQuery.js.map +0 -1
  108. package/dist/requests/toValidated.d.ts +0 -13
  109. package/dist/requests/toValidated.js +0 -29
  110. package/dist/requests/toValidated.js.map +0 -1
  111. package/dist/requests/verifyKey.js +0 -91
  112. package/dist/requests/verifyKey.js.map +0 -1
  113. package/dist/utils/isBetween.d.ts +0 -1
  114. package/dist/utils/isBetween.js +0 -2
  115. package/dist/utils/isBetween.js.map +0 -1
  116. package/dist/utils/isNonNullable.d.ts +0 -20
  117. package/dist/utils/isNonNullable.js.map +0 -1
  118. package/dist/utils/isNumericString.d.ts +0 -1
  119. package/dist/utils/isNumericString.js +0 -2
  120. package/dist/utils/isNumericString.js.map +0 -1
  121. package/dist/utils/isObject.d.ts +0 -1
  122. package/dist/utils/isObject.js +0 -2
  123. package/dist/utils/isObject.js.map +0 -1
  124. package/dist/utils/sleep.d.ts +0 -4
  125. package/dist/utils/sleep.js +0 -5
  126. package/dist/utils/sleep.js.map +0 -1
  127. package/dist/utils/toCamelCase.d.ts +0 -1
  128. package/dist/utils/toCamelCase.js +0 -2
  129. package/dist/utils/toCamelCase.js.map +0 -1
  130. package/dist/utils/toCamelKeys.d.ts +0 -2
  131. package/dist/utils/toCamelKeys.js +0 -16
  132. package/dist/utils/toCamelKeys.js.map +0 -1
  133. package/dist/utils/toSnakeCase.d.ts +0 -1
  134. package/dist/utils/toSnakeCase.js +0 -4
  135. package/dist/utils/toSnakeCase.js.map +0 -1
  136. package/dist/utils/toSnakeKeys.d.ts +0 -2
  137. package/dist/utils/toSnakeKeys.js +0 -16
  138. package/dist/utils/toSnakeKeys.js.map +0 -1
  139. package/dist/validations/asDigits.d.ts +0 -6
  140. package/dist/validations/asDigits.js +0 -6
  141. package/dist/validations/asDigits.js.map +0 -1
  142. package/dist/validations/asInteger.d.ts +0 -6
  143. package/dist/validations/asInteger.js +0 -6
  144. package/dist/validations/asInteger.js.map +0 -1
  145. package/dist/validations/bitfield.d.ts +0 -17
  146. package/dist/validations/bitfield.js +0 -37
  147. package/dist/validations/bitfield.js.map +0 -1
  148. package/dist/validations/boundedArray.d.ts +0 -6
  149. package/dist/validations/boundedArray.js +0 -8
  150. package/dist/validations/boundedArray.js.map +0 -1
  151. package/dist/validations/boundedInteger.d.ts +0 -6
  152. package/dist/validations/boundedInteger.js +0 -8
  153. package/dist/validations/boundedInteger.js.map +0 -1
  154. package/dist/validations/boundedString.d.ts +0 -6
  155. package/dist/validations/boundedString.js +0 -8
  156. package/dist/validations/boundedString.js.map +0 -1
  157. package/dist/validations/datauri.d.ts +0 -20
  158. package/dist/validations/datauri.js +0 -20
  159. package/dist/validations/datauri.js.map +0 -1
  160. package/dist/validations/hasMimeType.d.ts +0 -10
  161. package/dist/validations/hasMimeType.js +0 -18
  162. package/dist/validations/hasMimeType.js.map +0 -1
  163. package/dist/validations/hasSize.d.ts +0 -5
  164. package/dist/validations/hasSize.js +0 -13
  165. package/dist/validations/hasSize.js.map +0 -1
  166. package/dist/validations/index.d.ts +0 -12
  167. package/dist/validations/index.js +0 -13
  168. package/dist/validations/index.js.map +0 -1
  169. package/dist/validations/snowflake.js +0 -39
  170. package/dist/validations/snowflake.js.map +0 -1
  171. package/dist/validations/timestamp.js +0 -4
  172. package/dist/validations/timestamp.js.map +0 -1
  173. package/dist/validations/toBlob.d.ts +0 -4
  174. package/dist/validations/toBlob.js +0 -19
  175. package/dist/validations/toBlob.js.map +0 -1
  176. package/dist/validations/url.d.ts +0 -2
  177. package/dist/validations/url.js +0 -3
  178. package/dist/validations/url.js.map +0 -1
@@ -0,0 +1,63 @@
1
+ //#region src/requests/verifyKey.ts
2
+ /**
3
+ * Get the SubtleCrypto interface for the current environment
4
+ */
5
+ const getSubtleCrypto = () => {
6
+ if (typeof globalThis.crypto !== `undefined`) return globalThis.crypto.subtle;
7
+ if (typeof global !== `undefined` && global.crypto?.subtle) return global.crypto.subtle;
8
+ if (typeof window !== `undefined` && window.crypto?.subtle) return window.crypto.subtle;
9
+ throw new Error(`SubtleCrypto is not available in this environment`);
10
+ };
11
+ const subtleCrypto = getSubtleCrypto();
12
+ /**
13
+ * Convert various input types to Uint8Array
14
+ */
15
+ function valueToUint8Array(value, encoding) {
16
+ if (value instanceof Uint8Array) return value;
17
+ if (value instanceof ArrayBuffer) return new Uint8Array(value);
18
+ if (typeof Buffer !== `undefined` && Buffer.isBuffer(value)) return new Uint8Array(value);
19
+ if (typeof value === `string`) {
20
+ if (encoding === `hex`) {
21
+ const matches = value.match(/.{1,2}/g);
22
+ if (!matches) throw new Error(`Invalid hex string`);
23
+ return new Uint8Array(matches.map((byte) => parseInt(byte, 16)));
24
+ }
25
+ return new TextEncoder().encode(value);
26
+ }
27
+ throw new Error(`Unsupported value type`);
28
+ }
29
+ /**
30
+ * Concatenate multiple Uint8Arrays into a single Uint8Array
31
+ */
32
+ function concatUint8Arrays(...arrays) {
33
+ const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
34
+ const result = new Uint8Array(totalLength);
35
+ let offset = 0;
36
+ for (const arr of arrays) {
37
+ result.set(arr, offset);
38
+ offset += arr.length;
39
+ }
40
+ return result;
41
+ }
42
+ /**
43
+ * Validates a payload from Discord against its signature and key.
44
+ *
45
+ * @param rawBody - The raw payload data
46
+ * @param signature - The signature from the `X-Signature-Ed25519` header
47
+ * @param timestamp - The timestamp from the `X-Signature-Timestamp` header
48
+ * @param clientPublicKey - The public key from the Discord developer dashboard
49
+ * @returns Whether or not validation was successful
50
+ */
51
+ async function verifyKey(rawBody, signature, timestamp, clientPublicKey) {
52
+ try {
53
+ return await subtleCrypto.verify({ name: `ed25519` }, typeof clientPublicKey === `string` ? await subtleCrypto.importKey(`raw`, Buffer.from(valueToUint8Array(clientPublicKey, `hex`)), {
54
+ name: `ed25519`,
55
+ namedCurve: `ed25519`
56
+ }, false, [`verify`]) : clientPublicKey, Buffer.from(valueToUint8Array(signature, `hex`)), Buffer.from(concatUint8Arrays(valueToUint8Array(timestamp), valueToUint8Array(rawBody))));
57
+ } catch (err) {
58
+ console.error(`Signature verification failed:`, err);
59
+ return false;
60
+ }
61
+ }
62
+ //#endregion
63
+ export { verifyKey };
@@ -0,0 +1,4 @@
1
+ //#region src/utils/isBetween.d.ts
2
+ declare const isBetween: (val: number, min: number, max: number) => boolean;
3
+ //#endregion
4
+ export { isBetween };
@@ -0,0 +1,4 @@
1
+ //#region src/utils/isBetween.ts
2
+ const isBetween = (val, min, max) => val >= min && val <= max;
3
+ //#endregion
4
+ export { isBetween };
@@ -1,3 +1,5 @@
1
+ //#region src/utils/isNonNullable.d.ts
2
+ type Maybe<T> = T | null | undefined;
1
3
  /**
2
4
  * Used to test whether a `Maybe` typed value is `null` or `undefined`.
3
5
  *
@@ -16,5 +18,6 @@
16
18
  * }
17
19
  * ```
18
20
  */
19
- export const isNonNullable = (val) => typeof val !== `undefined` && val !== null;
20
- //# sourceMappingURL=isNonNullable.js.map
21
+ declare const isNonNullable: <T extends Maybe<unknown>>(val?: T) => val is NonNullable<T>;
22
+ //#endregion
23
+ export { Maybe, isNonNullable };
@@ -0,0 +1,22 @@
1
+ //#region src/utils/isNonNullable.ts
2
+ /**
3
+ * Used to test whether a `Maybe` typed value is `null` or `undefined`.
4
+ *
5
+ * When called, the given value's type is narrowed to `NonNullable<T>`.
6
+ *
7
+ * ### Example Usage:
8
+ *
9
+ * ```ts
10
+ * const fn = (str: Maybe<string>) => {
11
+ * if (!isNonNullable(str)) {
12
+ * // typeof str = null | undefined
13
+ * // ...
14
+ * }
15
+ * // typeof str = string
16
+ * // ...
17
+ * }
18
+ * ```
19
+ */
20
+ const isNonNullable = (val) => typeof val !== `undefined` && val !== null;
21
+ //#endregion
22
+ export { isNonNullable };
@@ -0,0 +1,4 @@
1
+ //#region src/utils/isNumericString.d.ts
2
+ declare const isNumericString: (val: unknown) => val is string;
3
+ //#endregion
4
+ export { isNumericString };
@@ -0,0 +1,4 @@
1
+ //#region src/utils/isNumericString.ts
2
+ const isNumericString = (val) => typeof val === `string` && /^\d+$/.test(val);
3
+ //#endregion
4
+ export { isNumericString };
@@ -0,0 +1,4 @@
1
+ //#region src/utils/isObject.d.ts
2
+ declare const isObject: (val: unknown) => val is object;
3
+ //#endregion
4
+ export { isObject };
@@ -0,0 +1,4 @@
1
+ //#region src/utils/isObject.ts
2
+ const isObject = (val) => Boolean(val) && typeof val === `object` && !Array.isArray(val);
3
+ //#endregion
4
+ export { isObject };
@@ -0,0 +1,7 @@
1
+ //#region src/utils/sleep.d.ts
2
+ /**
3
+ * Sleep for a given number of milliseconds
4
+ */
5
+ declare const sleep: (ms: number) => Promise<void>;
6
+ //#endregion
7
+ export { sleep };
@@ -0,0 +1,7 @@
1
+ //#region src/utils/sleep.ts
2
+ /**
3
+ * Sleep for a given number of milliseconds
4
+ */
5
+ const sleep = async (ms) => new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
6
+ //#endregion
7
+ export { sleep };
@@ -0,0 +1,4 @@
1
+ //#region src/utils/toCamelCase.d.ts
2
+ declare const toCamelCase: (str: string) => string;
3
+ //#endregion
4
+ export { toCamelCase };
@@ -0,0 +1,4 @@
1
+ //#region src/utils/toCamelCase.ts
2
+ const toCamelCase = (str) => str.replace(/_(?<char>[a-zA-Z])/g, (g) => g[1].toUpperCase());
3
+ //#endregion
4
+ export { toCamelCase };
@@ -0,0 +1,6 @@
1
+ import { CamelCasedPropertiesDeep } from "type-fest";
2
+
3
+ //#region src/utils/toCamelKeys.d.ts
4
+ declare const toCamelKeys: <T extends object>(o: T) => CamelCasedPropertiesDeep<T>;
5
+ //#endregion
6
+ export { toCamelKeys };
@@ -0,0 +1,13 @@
1
+ import { isObject } from "./isObject.mjs";
2
+ import { toCamelCase } from "./toCamelCase.mjs";
3
+ //#region src/utils/toCamelKeys.ts
4
+ const toCamelKeys = (o) => {
5
+ if (Array.isArray(o)) return o.map(toCamelKeys);
6
+ else if (isObject(o)) return Object.entries(o).reduce((acc, [key, value]) => {
7
+ acc[toCamelCase(key)] = toCamelKeys(value);
8
+ return acc;
9
+ }, {});
10
+ return o;
11
+ };
12
+ //#endregion
13
+ export { toCamelKeys };
@@ -0,0 +1,4 @@
1
+ //#region src/utils/toSnakeCase.d.ts
2
+ declare const toSnakeCase: (str: string) => string;
3
+ //#endregion
4
+ export { toSnakeCase };
@@ -0,0 +1,4 @@
1
+ //#region src/utils/toSnakeCase.ts
2
+ const toSnakeCase = (str) => str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`).substring(str.slice(0, 1).match(/(?<char>[A-Z])/g) ? 1 : 0);
3
+ //#endregion
4
+ export { toSnakeCase };
@@ -0,0 +1,6 @@
1
+ import { SnakeCasedPropertiesDeep } from "type-fest";
2
+
3
+ //#region src/utils/toSnakeKeys.d.ts
4
+ declare const toSnakeKeys: <T extends object>(o: T) => SnakeCasedPropertiesDeep<T>;
5
+ //#endregion
6
+ export { toSnakeKeys };
@@ -0,0 +1,13 @@
1
+ import { toSnakeCase } from "./toSnakeCase.mjs";
2
+ import { isObject } from "./isObject.mjs";
3
+ //#region src/utils/toSnakeKeys.ts
4
+ const toSnakeKeys = (o) => {
5
+ if (Array.isArray(o)) return o.map(toSnakeKeys);
6
+ else if (isObject(o)) return Object.entries(o).reduce((acc, [key, value]) => {
7
+ acc[toSnakeCase(key)] = toSnakeKeys(value);
8
+ return acc;
9
+ }, {});
10
+ return o;
11
+ };
12
+ //#endregion
13
+ export { toSnakeKeys };
@@ -0,0 +1,12 @@
1
+ import { bitfield } from "./bitfield.mjs";
2
+ import * as v from "valibot";
3
+
4
+ //#region src/validations/asDigits.d.ts
5
+ /**
6
+ * Transforms a `bitfield` schema into a numeric string
7
+ *
8
+ * @__NO_SIDE_EFFECTS__
9
+ */
10
+ declare const asDigits: (schema: ReturnType<typeof bitfield>) => v.GenericSchema<string>;
11
+ //#endregion
12
+ export { asDigits };
@@ -0,0 +1,10 @@
1
+ import * as v from "valibot";
2
+ //#region src/validations/asDigits.ts
3
+ /**
4
+ * Transforms a `bitfield` schema into a numeric string
5
+ *
6
+ * @__NO_SIDE_EFFECTS__
7
+ */
8
+ const asDigits = (schema) => v.pipe(schema, v.transform((val) => val.toString()), v.digits());
9
+ //#endregion
10
+ export { asDigits };
@@ -0,0 +1,12 @@
1
+ import { bitfield } from "./bitfield.mjs";
2
+ import * as v from "valibot";
3
+
4
+ //#region src/validations/asInteger.d.ts
5
+ /**
6
+ * Transforms a `bitfield` schema into an integer
7
+ *
8
+ * @__NO_SIDE_EFFECTS__
9
+ */
10
+ declare const asInteger: (schema: ReturnType<typeof bitfield>) => v.GenericSchema<number>;
11
+ //#endregion
12
+ export { asInteger };
@@ -0,0 +1,10 @@
1
+ import * as v from "valibot";
2
+ //#region src/validations/asInteger.ts
3
+ /**
4
+ * Transforms a `bitfield` schema into an integer
5
+ *
6
+ * @__NO_SIDE_EFFECTS__
7
+ */
8
+ const asInteger = (schema) => v.pipe(schema, v.transform((val) => parseInt(val.toString(), 10)), v.integer());
9
+ //#endregion
10
+ export { asInteger };
@@ -0,0 +1,23 @@
1
+ import { CustomSchema, SchemaWithPipe, TitleAction } from "valibot";
2
+
3
+ //#region src/validations/bitfield.d.ts
4
+ interface Flags {
5
+ [key: string]: number | bigint | string;
6
+ }
7
+ /**
8
+ * Given an enum of bitwise flags, creates a new schema that
9
+ * can validate a [bitfield](https://en.wikipedia.org/wiki/Bit_field)
10
+ * numeric value (a data structure for efficiently serializing a
11
+ * group of boolean values).
12
+ *
13
+ * @__NO_SIDE_EFFECTS__
14
+ */
15
+ declare const bitfield: <TName extends string>(/** A name to differentiate this custom schema */
16
+
17
+ name: TName, /** An enum of bitwise flags */
18
+
19
+ flags: Flags, /** An optional error message to display in the event an invalid value is parsed */
20
+
21
+ message?: string) => SchemaWithPipe<readonly [CustomSchema<string | number | bigint, string>, TitleAction<string | number | bigint, TName>]>;
22
+ //#endregion
23
+ export { Flags, bitfield };
@@ -0,0 +1,20 @@
1
+ import { isNonNullable } from "../utils/isNonNullable.mjs";
2
+ import { isNumericString } from "../utils/isNumericString.mjs";
3
+ import { custom, pipe, title } from "valibot";
4
+ //#region src/validations/bitfield.ts
5
+ /**
6
+ * Given an enum of bitwise flags, creates a new schema that
7
+ * can validate a [bitfield](https://en.wikipedia.org/wiki/Bit_field)
8
+ * numeric value (a data structure for efficiently serializing a
9
+ * group of boolean values).
10
+ *
11
+ * @__NO_SIDE_EFFECTS__
12
+ */
13
+ const bitfield = (name, flags, message = `Invalid Bitfield`) => {
14
+ const flagValues = Object.values(flags).filter((flag) => !isNaN(Number(flag)));
15
+ if (!flagValues.every((flag) => typeof flag === typeof flagValues[0])) throw new Error(`Provided Flags enum must contain values of the same type`);
16
+ const mask = flagValues.reduce((total, flag) => total | BigInt(flag), 0n);
17
+ return pipe(custom((val) => isNonNullable(val) && (typeof val === `number` || typeof val === `bigint` || isNumericString(val)) ? (BigInt(val) & mask) === BigInt(val) : false, message), title(name));
18
+ };
19
+ //#endregion
20
+ export { bitfield };
@@ -0,0 +1,13 @@
1
+ import * as v from "valibot";
2
+
3
+ //#region src/validations/boundedArray.d.ts
4
+ /** A non-empty array with a length within the given bounds
5
+ *
6
+ * @__NO_SIDE_EFFECTS__
7
+ */
8
+ declare const boundedArray: <TItem>(items: v.GenericSchema<TItem>, req?: number | {
9
+ min?: number;
10
+ max?: number;
11
+ }) => v.GenericSchema<TItem[]>;
12
+ //#endregion
13
+ export { boundedArray };
@@ -0,0 +1,9 @@
1
+ import * as v from "valibot";
2
+ //#region src/validations/boundedArray.ts
3
+ /** A non-empty array with a length within the given bounds
4
+ *
5
+ * @__NO_SIDE_EFFECTS__
6
+ */
7
+ const boundedArray = (items, req = {}) => v.message(typeof req === `number` ? v.pipe(v.array(items), v.length(req)) : typeof req.max === `number` ? v.pipe(v.array(items), v.minLength(req.min ?? 1), v.maxLength(req.max)) : v.pipe(v.array(items), v.minLength(req.min ?? 1)), (issue) => `Expected an array with a legnth ${typeof req === `number` ? req : `>= ${req.min ?? 0}${req.max ? `&& <= ${req.max}` : ``}`}, received has length: ${issue.received.length}`);
8
+ //#endregion
9
+ export { boundedArray };
@@ -0,0 +1,13 @@
1
+ import * as v from "valibot";
2
+
3
+ //#region src/validations/boundedInteger.d.ts
4
+ /** An integer with a value within the given bounds
5
+ *
6
+ * @__NO_SIDE_EFFECTS__
7
+ */
8
+ declare const boundedInteger: (req?: number | {
9
+ min?: number;
10
+ max?: number;
11
+ }) => v.GenericSchema<number>;
12
+ //#endregion
13
+ export { boundedInteger };
@@ -0,0 +1,9 @@
1
+ import * as v from "valibot";
2
+ //#region src/validations/boundedInteger.ts
3
+ /** An integer with a value within the given bounds
4
+ *
5
+ * @__NO_SIDE_EFFECTS__
6
+ */
7
+ const boundedInteger = (req = {}) => v.message(typeof req === `number` ? v.pipe(v.number(), v.integer(), v.value(req)) : typeof req.max === `number` ? v.pipe(v.number(), v.integer(), v.minValue(req.min ?? 0), v.maxValue(req.max)) : v.pipe(v.number(), v.integer(), v.minValue(req.min ?? 0)), (issue) => `Expected an integer with a value ${typeof req === `number` ? `of ${req}` : `>= ${req.min ?? 0}${req.max ? `&& <= ${req.max}` : ``}`}, received has value: ${issue.received.length}`);
8
+ //#endregion
9
+ export { boundedInteger };
@@ -0,0 +1,14 @@
1
+ import * as v from "valibot";
2
+
3
+ //#region src/validations/boundedString.d.ts
4
+ /**
5
+ * A non-empty string with a length within the given bounds.
6
+ *
7
+ * @__NO_SIDE_EFFECTS__
8
+ */
9
+ declare const boundedString: (req?: number | {
10
+ min?: number;
11
+ max?: number;
12
+ }) => v.GenericSchema<string>;
13
+ //#endregion
14
+ export { boundedString };
@@ -0,0 +1,10 @@
1
+ import * as v from "valibot";
2
+ //#region src/validations/boundedString.ts
3
+ /**
4
+ * A non-empty string with a length within the given bounds.
5
+ *
6
+ * @__NO_SIDE_EFFECTS__
7
+ */
8
+ const boundedString = (req = {}) => v.message(typeof req === `number` ? v.pipe(v.string(), v.length(req)) : typeof req.max === `number` ? v.pipe(v.string(), v.minLength(req.min ?? 1), v.maxLength(req.max)) : v.pipe(v.string(), v.minLength(req.min ?? 1)), (issue) => `Expected a string with a legnth ${typeof req === `number` ? req : `>= ${req.min ?? 0}${req.max ? `&& <= ${req.max}` : ``}`}, received has length: ${issue.received.length}`);
9
+ //#endregion
10
+ export { boundedString };
@@ -0,0 +1,24 @@
1
+ import * as v from "valibot";
2
+
3
+ //#region src/validations/datauri.d.ts
4
+ declare const datauriRegex: RegExp;
5
+ /**
6
+ * Extracts metadata from a given Data URI such as it's
7
+ * MIME type, params, and encoding
8
+ *
9
+ * Returns an empty object when given an invalid Data URI
10
+ */
11
+ declare const extractDataURIMetadata: (val: string) => Partial<{
12
+ mediaType: string;
13
+ mimeType: `${string}/${string}`;
14
+ params: string;
15
+ encoding: string;
16
+ data: string;
17
+ }>;
18
+ declare const toBase64: (data: string) => string;
19
+ /**
20
+ * Validates that a string is a [data URI scheme](https://en.wikipedia.org/wiki/Data_URI_scheme)
21
+ */
22
+ declare const datauri: v.GenericSchema<string>;
23
+ //#endregion
24
+ export { datauri, datauriRegex, extractDataURIMetadata, toBase64 };
@@ -0,0 +1,17 @@
1
+ import * as v from "valibot";
2
+ //#region src/validations/datauri.ts
3
+ const datauriRegex = /^data:((?<mediaType>(?<mimeType>[a-z]+\/[a-z0-9-+.]+)(?<params>;[a-z0-9-.!#$%*+.{}|~`]+=[a-z0-9-.!#$%*+.{}()_|~`]+)*))?(?<encoding>;base64)?,(?<data>[a-z0-9!$&',()*+;=\-._~:@/?%\s<>]*?)$/i;
4
+ /**
5
+ * Extracts metadata from a given Data URI such as it's
6
+ * MIME type, params, and encoding
7
+ *
8
+ * Returns an empty object when given an invalid Data URI
9
+ */
10
+ const extractDataURIMetadata = (val) => datauriRegex.exec(val)?.groups ?? {};
11
+ const toBase64 = (data) => typeof Buffer !== `undefined` ? Buffer.from(data, `base64`).toString() : atob(btoa(String.fromCharCode(...new TextEncoder().encode(data))).replace(/\+/g, `-`).replace(/\//g, `_`).replace(/=/g, ``));
12
+ /**
13
+ * Validates that a string is a [data URI scheme](https://en.wikipedia.org/wiki/Data_URI_scheme)
14
+ */
15
+ const datauri = v.pipe(v.custom((val) => typeof val === `string` && val.length > 0 && datauriRegex.test(val), `Invalid Data URI`), v.title(`datauri`));
16
+ //#endregion
17
+ export { datauri, datauriRegex, extractDataURIMetadata, toBase64 };
@@ -0,0 +1,129 @@
1
+ import * as v from "valibot";
2
+
3
+ //#region src/validations/fileUpload.d.ts
4
+ /**
5
+ * The shape of a single file upload — used wherever a Discord endpoint
6
+ * accepts an attached file via `multipart/form-data`.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * await executeWebhook({
11
+ * webhook: "...",
12
+ * token: "...",
13
+ * body: {
14
+ * content: "Look at this!",
15
+ * files: [
16
+ * { filename: "photo.png", content: new Blob([bytes], { type: "image/png" }) }
17
+ * ]
18
+ * }
19
+ * });
20
+ * ```
21
+ */
22
+ interface FileUpload {
23
+ /** Filename including extension. Required for the multipart `Content-Disposition` header. */
24
+ filename: string;
25
+ /** The binary content. Accepts a web-standard `Blob` or `File`. */
26
+ content: Blob;
27
+ /** Optional MIME type. If omitted, taken from the `Blob`'s `type` property. */
28
+ contentType?: string;
29
+ }
30
+ /** Type guard — true if `val` looks like a {@link FileUpload}. */
31
+ declare const isFileUpload: (val: unknown) => val is FileUpload;
32
+ /**
33
+ * Valibot schema for a single file upload. Validates the shape and
34
+ * surfaces a clean TypeScript type to consumers.
35
+ */
36
+ declare const fileUpload: v.GenericSchema<FileUpload>;
37
+ /**
38
+ * Walks a value and returns all {@link FileUpload}s within it, along
39
+ * with the path each one occupies.
40
+ */
41
+ declare const collectFileUploads: (val: unknown, path?: ReadonlyArray<string | number>) => ReadonlyArray<{
42
+ readonly path: ReadonlyArray<string | number>;
43
+ readonly file: FileUpload;
44
+ }>;
45
+ /**
46
+ * Given a body that contains one or more {@link FileUpload}s, produce
47
+ * a `FormData` payload Discord can consume.
48
+ *
49
+ * Files are appended as `files[n]` parts; the rest of the body is
50
+ * snake_cased and JSON-stringified into a `payload_json` part.
51
+ *
52
+ * Each FileUpload in the body is replaced by its attachment placeholder
53
+ * `{ id: n }` so that an `attachments` array (if present) can reference
54
+ * uploads by index. Discord matches these placeholders to the
55
+ * corresponding `files[n]` parts.
56
+ */
57
+ declare const toMultipartBody: (body: unknown, toSnakeKeys: (val: object) => unknown) => FormData;
58
+ /**
59
+ * Sentinel symbol used to mark a validated body as multipart-eligible.
60
+ * Read by the request layer at serialization time.
61
+ *
62
+ * The marker is attached as a non-enumerable property on the parsed
63
+ * body so it doesn't leak into JSON serialization or the TypeScript
64
+ * output type.
65
+ */
66
+ declare const MULTIPART_MARKER: unique symbol;
67
+ /**
68
+ * Returns true if `body` should be serialized as `multipart/form-data`.
69
+ *
70
+ * Two signals trigger multipart serialization:
71
+ *
72
+ * 1. **Schema-tagged** — the body was parsed by a {@link multipart}-wrapped
73
+ * schema and at least one {@link FileUpload} was present. The wrapper
74
+ * stamps a non-enumerable {@link MULTIPART_MARKER} on the parsed value.
75
+ * This is the fast path for the validated flow (e.g., `toValidated`).
76
+ *
77
+ * 2. **Value-detected** — the body contains a {@link FileUpload} anywhere
78
+ * in its shape, regardless of whether it was validated. This safety net
79
+ * keeps consumers who bypass validation from silently dropping their
80
+ * files into a JSON body where `Blob` would serialize as `{}`.
81
+ *
82
+ * Either signal switches the request to multipart.
83
+ */
84
+ declare const shouldSerializeAsMultipart: (body: unknown) => boolean;
85
+ /**
86
+ * Wraps an object schema to mark its body as a potential multipart payload.
87
+ *
88
+ * Use {@link multipart} instead of `v.object` whenever an endpoint's body
89
+ * may contain one or more {@link fileUpload} fields (or arrays of them,
90
+ * or optional uploads). The wrapper validates the same shape as
91
+ * `v.object(entries)`. At validation time, the wrapper inspects the
92
+ * parsed body for {@link FileUpload}s. If any are present, it stamps a
93
+ * non-enumerable {@link MULTIPART_MARKER} on the result; the request
94
+ * layer reads that marker at serialization time to choose between
95
+ * `multipart/form-data` (marker present) and `application/json`
96
+ * (marker absent).
97
+ *
98
+ * Pass `{ partial: true }` for endpoints where every field is optional —
99
+ * the wrapper applies `v.partial(...)` to the inner object before piping
100
+ * the transform. `v.partial` itself can't wrap the piped result (it only
101
+ * accepts plain object schemas), so the option lives here.
102
+ *
103
+ * @example
104
+ * ```ts
105
+ * import { multipart, fileUpload } from "@discordkit/core";
106
+ * import * as v from "valibot";
107
+ *
108
+ * export const updateAvatarSchema = v.object({
109
+ * body: multipart({
110
+ * avatar: v.exactOptional(fileUpload),
111
+ * bio: v.exactOptional(v.string())
112
+ * })
113
+ * });
114
+ *
115
+ * // Every field optional:
116
+ * export const editMessageSchema = v.object({
117
+ * body: multipart(
118
+ * { content: v.string(), files: v.array(fileUpload) },
119
+ * { partial: true }
120
+ * )
121
+ * });
122
+ * ```
123
+ */
124
+ declare function multipart<TEntries extends v.ObjectEntries>(entries: TEntries): v.GenericSchema<v.InferOutput<v.ObjectSchema<TEntries, undefined>>>;
125
+ declare function multipart<TEntries extends v.ObjectEntries>(entries: TEntries, options: {
126
+ partial: true;
127
+ }): v.GenericSchema<v.InferOutput<v.SchemaWithPartial<v.ObjectSchema<TEntries, undefined>, undefined>>>;
128
+ //#endregion
129
+ export { FileUpload, MULTIPART_MARKER, collectFileUploads, fileUpload, isFileUpload, multipart, shouldSerializeAsMultipart, toMultipartBody };