@discordkit/core 3.2.0 → 4.0.1

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 (247) hide show
  1. package/CHANGELOG.md +423 -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 +72 -0
  6. package/dist/requests/DiscordSession.d.mts.map +1 -0
  7. package/dist/requests/DiscordSession.mjs +262 -0
  8. package/dist/requests/DiscordSession.mjs.map +1 -0
  9. package/dist/requests/addParams.d.mts +16 -0
  10. package/dist/requests/addParams.d.mts.map +1 -0
  11. package/dist/requests/addParams.mjs +26 -0
  12. package/dist/requests/addParams.mjs.map +1 -0
  13. package/dist/requests/buildURL.d.mts +8 -0
  14. package/dist/requests/buildURL.d.mts.map +1 -0
  15. package/dist/requests/buildURL.mjs +9 -0
  16. package/dist/requests/buildURL.mjs.map +1 -0
  17. package/dist/requests/getAsset.d.mts +8 -0
  18. package/dist/requests/getAsset.d.mts.map +1 -0
  19. package/dist/requests/getAsset.mjs +8 -0
  20. package/dist/requests/getAsset.mjs.map +1 -0
  21. package/dist/requests/index.d.mts +9 -0
  22. package/dist/requests/index.mjs +9 -0
  23. package/dist/requests/methods.d.mts +64 -0
  24. package/dist/requests/methods.d.mts.map +1 -0
  25. package/dist/requests/methods.mjs +12 -0
  26. package/dist/requests/methods.mjs.map +1 -0
  27. package/dist/requests/request.d.mts +28 -0
  28. package/dist/requests/request.d.mts.map +1 -0
  29. package/dist/requests/request.mjs +31 -0
  30. package/dist/requests/request.mjs.map +1 -0
  31. package/dist/requests/toProcedure.d.mts +41 -0
  32. package/dist/requests/toProcedure.d.mts.map +1 -0
  33. package/dist/requests/toProcedure.mjs +29 -0
  34. package/dist/requests/toProcedure.mjs.map +1 -0
  35. package/dist/requests/toQuery.d.mts +37 -0
  36. package/dist/requests/toQuery.d.mts.map +1 -0
  37. package/dist/requests/toQuery.mjs +10 -0
  38. package/dist/requests/toQuery.mjs.map +1 -0
  39. package/dist/requests/toValidated.d.mts +17 -0
  40. package/dist/requests/toValidated.d.mts.map +1 -0
  41. package/dist/requests/toValidated.mjs +27 -0
  42. package/dist/requests/toValidated.mjs.map +1 -0
  43. package/dist/requests/{verifyKey.d.ts → verifyKey.d.mts} +5 -1
  44. package/dist/requests/verifyKey.d.mts.map +1 -0
  45. package/dist/requests/verifyKey.mjs +64 -0
  46. package/dist/requests/verifyKey.mjs.map +1 -0
  47. package/dist/utils/isBetween.d.mts +5 -0
  48. package/dist/utils/isBetween.d.mts.map +1 -0
  49. package/dist/utils/isBetween.mjs +6 -0
  50. package/dist/utils/isBetween.mjs.map +1 -0
  51. package/dist/utils/{isNonNullable.js → isNonNullable.d.mts} +6 -2
  52. package/dist/utils/isNonNullable.d.mts.map +1 -0
  53. package/dist/utils/isNonNullable.mjs +24 -0
  54. package/dist/utils/isNonNullable.mjs.map +1 -0
  55. package/dist/utils/isNumericString.d.mts +5 -0
  56. package/dist/utils/isNumericString.d.mts.map +1 -0
  57. package/dist/utils/isNumericString.mjs +6 -0
  58. package/dist/utils/isNumericString.mjs.map +1 -0
  59. package/dist/utils/isObject.d.mts +5 -0
  60. package/dist/utils/isObject.d.mts.map +1 -0
  61. package/dist/utils/isObject.mjs +6 -0
  62. package/dist/utils/isObject.mjs.map +1 -0
  63. package/dist/utils/sleep.d.mts +8 -0
  64. package/dist/utils/sleep.d.mts.map +1 -0
  65. package/dist/utils/sleep.mjs +9 -0
  66. package/dist/utils/sleep.mjs.map +1 -0
  67. package/dist/utils/toCamelCase.d.mts +5 -0
  68. package/dist/utils/toCamelCase.d.mts.map +1 -0
  69. package/dist/utils/toCamelCase.mjs +6 -0
  70. package/dist/utils/toCamelCase.mjs.map +1 -0
  71. package/dist/utils/toCamelKeys.d.mts +20 -0
  72. package/dist/utils/toCamelKeys.d.mts.map +1 -0
  73. package/dist/utils/toCamelKeys.mjs +15 -0
  74. package/dist/utils/toCamelKeys.mjs.map +1 -0
  75. package/dist/utils/toSnakeCase.d.mts +5 -0
  76. package/dist/utils/toSnakeCase.d.mts.map +1 -0
  77. package/dist/utils/toSnakeCase.mjs +6 -0
  78. package/dist/utils/toSnakeCase.mjs.map +1 -0
  79. package/dist/utils/toSnakeKeys.d.mts +24 -0
  80. package/dist/utils/toSnakeKeys.d.mts.map +1 -0
  81. package/dist/utils/toSnakeKeys.mjs +15 -0
  82. package/dist/utils/toSnakeKeys.mjs.map +1 -0
  83. package/dist/validations/asDigits.d.mts +13 -0
  84. package/dist/validations/asDigits.d.mts.map +1 -0
  85. package/dist/validations/asDigits.mjs +12 -0
  86. package/dist/validations/asDigits.mjs.map +1 -0
  87. package/dist/validations/asInteger.d.mts +13 -0
  88. package/dist/validations/asInteger.d.mts.map +1 -0
  89. package/dist/validations/asInteger.mjs +12 -0
  90. package/dist/validations/asInteger.mjs.map +1 -0
  91. package/dist/validations/bitfield.d.mts +24 -0
  92. package/dist/validations/bitfield.d.mts.map +1 -0
  93. package/dist/validations/bitfield.mjs +22 -0
  94. package/dist/validations/bitfield.mjs.map +1 -0
  95. package/dist/validations/boundedArray.d.mts +14 -0
  96. package/dist/validations/boundedArray.d.mts.map +1 -0
  97. package/dist/validations/boundedArray.mjs +11 -0
  98. package/dist/validations/boundedArray.mjs.map +1 -0
  99. package/dist/validations/boundedInteger.d.mts +14 -0
  100. package/dist/validations/boundedInteger.d.mts.map +1 -0
  101. package/dist/validations/boundedInteger.mjs +11 -0
  102. package/dist/validations/boundedInteger.mjs.map +1 -0
  103. package/dist/validations/boundedString.d.mts +15 -0
  104. package/dist/validations/boundedString.d.mts.map +1 -0
  105. package/dist/validations/boundedString.mjs +12 -0
  106. package/dist/validations/boundedString.mjs.map +1 -0
  107. package/dist/validations/datauri.d.mts +25 -0
  108. package/dist/validations/datauri.d.mts.map +1 -0
  109. package/dist/validations/datauri.mjs +19 -0
  110. package/dist/validations/datauri.mjs.map +1 -0
  111. package/dist/validations/fileUpload.d.mts +130 -0
  112. package/dist/validations/fileUpload.d.mts.map +1 -0
  113. package/dist/validations/fileUpload.mjs +116 -0
  114. package/dist/validations/fileUpload.mjs.map +1 -0
  115. package/dist/validations/hasMimeType.d.mts +17 -0
  116. package/dist/validations/hasMimeType.d.mts.map +1 -0
  117. package/dist/validations/hasMimeType.mjs +18 -0
  118. package/dist/validations/hasMimeType.mjs.map +1 -0
  119. package/dist/validations/hasSize.d.mts +11 -0
  120. package/dist/validations/hasSize.d.mts.map +1 -0
  121. package/dist/validations/hasSize.mjs +14 -0
  122. package/dist/validations/hasSize.mjs.map +1 -0
  123. package/dist/validations/index.d.mts +15 -0
  124. package/dist/validations/index.mjs +15 -0
  125. package/dist/validations/schema.d.mts +103 -0
  126. package/dist/validations/schema.d.mts.map +1 -0
  127. package/dist/validations/schema.mjs +111 -0
  128. package/dist/validations/schema.mjs.map +1 -0
  129. package/dist/validations/{snowflake.d.ts → snowflake.d.mts} +10 -7
  130. package/dist/validations/snowflake.d.mts.map +1 -0
  131. package/dist/validations/snowflake.mjs +30 -0
  132. package/dist/validations/snowflake.mjs.map +1 -0
  133. package/dist/validations/timestamp.d.mts +8 -0
  134. package/dist/validations/timestamp.d.mts.map +1 -0
  135. package/dist/validations/timestamp.mjs +8 -0
  136. package/dist/validations/timestamp.mjs.map +1 -0
  137. package/dist/validations/toBlob.d.mts +8 -0
  138. package/dist/validations/toBlob.d.mts.map +1 -0
  139. package/dist/validations/toBlob.mjs +19 -0
  140. package/dist/validations/toBlob.mjs.map +1 -0
  141. package/dist/validations/url.d.mts +7 -0
  142. package/dist/validations/url.d.mts.map +1 -0
  143. package/dist/validations/url.mjs +7 -0
  144. package/dist/validations/url.mjs.map +1 -0
  145. package/package.json +10 -23
  146. package/dist/index.d.ts +0 -2
  147. package/dist/index.js +0 -3
  148. package/dist/index.js.map +0 -1
  149. package/dist/requests/DiscordSession.d.ts +0 -25
  150. package/dist/requests/DiscordSession.js +0 -255
  151. package/dist/requests/DiscordSession.js.map +0 -1
  152. package/dist/requests/addParams.d.ts +0 -2
  153. package/dist/requests/addParams.js +0 -11
  154. package/dist/requests/addParams.js.map +0 -1
  155. package/dist/requests/buildURL.d.ts +0 -2
  156. package/dist/requests/buildURL.js +0 -4
  157. package/dist/requests/buildURL.js.map +0 -1
  158. package/dist/requests/getAsset.d.ts +0 -2
  159. package/dist/requests/getAsset.js +0 -3
  160. package/dist/requests/getAsset.js.map +0 -1
  161. package/dist/requests/index.d.ts +0 -8
  162. package/dist/requests/index.js +0 -9
  163. package/dist/requests/index.js.map +0 -1
  164. package/dist/requests/methods.d.ts +0 -13
  165. package/dist/requests/methods.js +0 -8
  166. package/dist/requests/methods.js.map +0 -1
  167. package/dist/requests/request.d.ts +0 -2
  168. package/dist/requests/request.js +0 -30
  169. package/dist/requests/request.js.map +0 -1
  170. package/dist/requests/toProcedure.d.ts +0 -31
  171. package/dist/requests/toProcedure.js +0 -36
  172. package/dist/requests/toProcedure.js.map +0 -1
  173. package/dist/requests/toQuery.d.ts +0 -28
  174. package/dist/requests/toQuery.js +0 -9
  175. package/dist/requests/toQuery.js.map +0 -1
  176. package/dist/requests/toValidated.d.ts +0 -13
  177. package/dist/requests/toValidated.js +0 -29
  178. package/dist/requests/toValidated.js.map +0 -1
  179. package/dist/requests/verifyKey.js +0 -91
  180. package/dist/requests/verifyKey.js.map +0 -1
  181. package/dist/utils/isBetween.d.ts +0 -1
  182. package/dist/utils/isBetween.js +0 -2
  183. package/dist/utils/isBetween.js.map +0 -1
  184. package/dist/utils/isNonNullable.d.ts +0 -20
  185. package/dist/utils/isNonNullable.js.map +0 -1
  186. package/dist/utils/isNumericString.d.ts +0 -1
  187. package/dist/utils/isNumericString.js +0 -2
  188. package/dist/utils/isNumericString.js.map +0 -1
  189. package/dist/utils/isObject.d.ts +0 -1
  190. package/dist/utils/isObject.js +0 -2
  191. package/dist/utils/isObject.js.map +0 -1
  192. package/dist/utils/sleep.d.ts +0 -4
  193. package/dist/utils/sleep.js +0 -5
  194. package/dist/utils/sleep.js.map +0 -1
  195. package/dist/utils/toCamelCase.d.ts +0 -1
  196. package/dist/utils/toCamelCase.js +0 -2
  197. package/dist/utils/toCamelCase.js.map +0 -1
  198. package/dist/utils/toCamelKeys.d.ts +0 -2
  199. package/dist/utils/toCamelKeys.js +0 -16
  200. package/dist/utils/toCamelKeys.js.map +0 -1
  201. package/dist/utils/toSnakeCase.d.ts +0 -1
  202. package/dist/utils/toSnakeCase.js +0 -4
  203. package/dist/utils/toSnakeCase.js.map +0 -1
  204. package/dist/utils/toSnakeKeys.d.ts +0 -2
  205. package/dist/utils/toSnakeKeys.js +0 -16
  206. package/dist/utils/toSnakeKeys.js.map +0 -1
  207. package/dist/validations/asDigits.d.ts +0 -6
  208. package/dist/validations/asDigits.js +0 -6
  209. package/dist/validations/asDigits.js.map +0 -1
  210. package/dist/validations/asInteger.d.ts +0 -6
  211. package/dist/validations/asInteger.js +0 -6
  212. package/dist/validations/asInteger.js.map +0 -1
  213. package/dist/validations/bitfield.d.ts +0 -17
  214. package/dist/validations/bitfield.js +0 -37
  215. package/dist/validations/bitfield.js.map +0 -1
  216. package/dist/validations/boundedArray.d.ts +0 -6
  217. package/dist/validations/boundedArray.js +0 -8
  218. package/dist/validations/boundedArray.js.map +0 -1
  219. package/dist/validations/boundedInteger.d.ts +0 -6
  220. package/dist/validations/boundedInteger.js +0 -8
  221. package/dist/validations/boundedInteger.js.map +0 -1
  222. package/dist/validations/boundedString.d.ts +0 -6
  223. package/dist/validations/boundedString.js +0 -8
  224. package/dist/validations/boundedString.js.map +0 -1
  225. package/dist/validations/datauri.d.ts +0 -20
  226. package/dist/validations/datauri.js +0 -20
  227. package/dist/validations/datauri.js.map +0 -1
  228. package/dist/validations/hasMimeType.d.ts +0 -10
  229. package/dist/validations/hasMimeType.js +0 -18
  230. package/dist/validations/hasMimeType.js.map +0 -1
  231. package/dist/validations/hasSize.d.ts +0 -5
  232. package/dist/validations/hasSize.js +0 -13
  233. package/dist/validations/hasSize.js.map +0 -1
  234. package/dist/validations/index.d.ts +0 -12
  235. package/dist/validations/index.js +0 -13
  236. package/dist/validations/index.js.map +0 -1
  237. package/dist/validations/snowflake.js +0 -39
  238. package/dist/validations/snowflake.js.map +0 -1
  239. package/dist/validations/timestamp.d.ts +0 -3
  240. package/dist/validations/timestamp.js +0 -4
  241. package/dist/validations/timestamp.js.map +0 -1
  242. package/dist/validations/toBlob.d.ts +0 -4
  243. package/dist/validations/toBlob.js +0 -19
  244. package/dist/validations/toBlob.js.map +0 -1
  245. package/dist/validations/url.d.ts +0 -2
  246. package/dist/validations/url.js +0 -3
  247. package/dist/validations/url.js.map +0 -1
@@ -0,0 +1,41 @@
1
+ import { Fetcher } from "./methods.mjs";
2
+ import * as v from "valibot";
3
+ import { AnyProcedureBuilder, MutationProcedure, ProcedureType, QueryProcedure, SubscriptionProcedure } from "@trpc/server/unstable-core-do-not-import";
4
+
5
+ //#region src/requests/toProcedure.d.ts
6
+ type Result<T = void> = T extends v.GenericSchema | v.GenericSchemaAsync ? v.InferOutput<T> : T;
7
+ type Schema = v.GenericSchema | v.GenericSchemaAsync;
8
+ type ProvedureDef<I extends Schema | null = null, O extends Schema | null = null> = I extends Schema ? O extends Schema ? {
9
+ input: v.InferInput<I>;
10
+ output: v.InferOutput<O>;
11
+ meta: unknown;
12
+ } : {
13
+ input: v.InferInput<I>;
14
+ output: undefined;
15
+ meta: unknown;
16
+ } : O extends Schema ? {
17
+ input: undefined;
18
+ output: v.InferOutput<O>;
19
+ meta: unknown;
20
+ } : {
21
+ input: undefined;
22
+ output: undefined;
23
+ meta: unknown;
24
+ };
25
+ type BaseProcedure<T extends ProcedureType, I extends Schema | null = null, O extends Schema | null = null> = T extends `query` ? QueryProcedure<ProvedureDef<I, O>> : T extends `mutation` ? MutationProcedure<ProvedureDef<I, O>> : SubscriptionProcedure<ProvedureDef<I, O>>;
26
+ /**
27
+ * Given a {@link Fetcher | Fetcher} function and it's associated input and
28
+ * output Zod schemas, this produces a function which accepts a tRPC procedure
29
+ * builder of the given procedure type. This can then be used in a tRPC router
30
+ * to scaffold an API route to forward a request to Discord's API.
31
+ *
32
+ * Capability-free fetchers only — endpoints that require `{ anonymous: true }`
33
+ * or accept `{ reason: string }` cannot currently be wrapped via this helper,
34
+ * because tRPC has no natural channel for those per-call options.
35
+ *
36
+ * @__NO_SIDE_EFFECTS__
37
+ */
38
+ declare const toProcedure: <T extends ProcedureType, I extends Schema | null = null, O extends Schema | null = null>(type: T, fn: Fetcher<I extends Schema ? I : null, Result<O>>, input?: I, output?: O) => (procedure: AnyProcedureBuilder, errorHandler?: (error: unknown) => void) => BaseProcedure<T, I, O>;
39
+ //#endregion
40
+ export { toProcedure };
41
+ //# sourceMappingURL=toProcedure.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toProcedure.d.mts","names":[],"sources":["../../src/requests/toProcedure.ts"],"mappings":";;;;;KAWK,MAAA,aAAmB,CAAA,SAAU,CAAA,CAAE,aAAA,GAAgB,CAAA,CAAE,kBAAA,GAClD,CAAA,CAAE,WAAA,CAAY,CAAA,IACd,CAAA;AAAA,KAEC,MAAA,GAAS,CAAA,CAAE,aAAA,GAAgB,CAAA,CAAE,kBAAkB;AAAA,KAE/C,YAAA,WACO,MAAA,0BACA,MAAA,kBACR,CAAA,SAAU,MAAA,GACV,CAAA,SAAU,MAAA;EAEN,KAAA,EAAO,CAAA,CAAE,UAAA,CAAW,CAAA;EACpB,MAAA,EAAQ,CAAA,CAAE,WAAA,CAAY,CAAA;EACtB,IAAA;AAAA;EAEA,KAAA,EAAO,CAAA,CAAE,UAAA,CAAW,CAAA;EAAI,MAAA;EAAmB,IAAA;AAAA,IAC/C,CAAA,SAAU,MAAA;EACN,KAAA;EAAkB,MAAA,EAAQ,CAAA,CAAE,WAAA,CAAY,CAAA;EAAI,IAAA;AAAA;EAE5C,KAAA;EACA,MAAA;EACA,IAAA;AAAA;AAAA,KAGH,aAAA,WACO,aAAA,YACA,MAAA,0BACA,MAAA,kBACR,CAAA,mBACA,cAAA,CAAe,YAAA,CAAa,CAAA,EAAG,CAAA,KAC/B,CAAA,sBACE,iBAAA,CAAkB,YAAA,CAAa,CAAA,EAAG,CAAA,KAClC,qBAAA,CAAsB,YAAA,CAAa,CAAA,EAAG,CAAA;;;;;AA/BvC;AAAA;;;;;;;cA6CQ,WAAA,aAEC,aAAA,YACA,MAAA,0BACA,MAAA,gBAEV,IAAA,EAAM,CAAA,EACN,EAAA,EAAI,OAAA,CAAQ,CAAA,SAAU,MAAA,GAAS,CAAA,SAAU,MAAA,CAAO,CAAA,IAChD,KAAA,GAAQ,CAAA,EACR,MAAA,GAAS,CAAA,MAGT,SAAA,EAAW,mBAAA,EACX,YAAA,IAAgB,KAAA,uBACf,aAAA,CAAc,CAAA,EAAG,CAAA,EAAG,CAAA"}
@@ -0,0 +1,29 @@
1
+ import { isNonNullable } from "../utils/isNonNullable.mjs";
2
+ //#region src/requests/toProcedure.ts
3
+ /**
4
+ * Given a {@link Fetcher | Fetcher} function and it's associated input and
5
+ * output Zod schemas, this produces a function which accepts a tRPC procedure
6
+ * builder of the given procedure type. This can then be used in a tRPC router
7
+ * to scaffold an API route to forward a request to Discord's API.
8
+ *
9
+ * Capability-free fetchers only — endpoints that require `{ anonymous: true }`
10
+ * or accept `{ reason: string }` cannot currently be wrapped via this helper,
11
+ * because tRPC has no natural channel for those per-call options.
12
+ *
13
+ * @__NO_SIDE_EFFECTS__
14
+ */
15
+ const toProcedure = (type, fn, input, output) => (procedure, errorHandler) => {
16
+ try {
17
+ if (isNonNullable(input) && isNonNullable(output)) return procedure.input(input).output(output)[type](async (opts) => fn(opts.input));
18
+ if (isNonNullable(input) && !isNonNullable(output)) return procedure.input(input)[type](async (opts) => fn(opts.input));
19
+ if (!isNonNullable(input) && isNonNullable(output)) return procedure.output(output)[type](async () => fn());
20
+ return procedure[type](async () => fn());
21
+ } catch (error) {
22
+ if (typeof errorHandler === `function`) errorHandler(error);
23
+ throw new Error(`Unhandled Procedure Error!`, { cause: error });
24
+ }
25
+ };
26
+ //#endregion
27
+ export { toProcedure };
28
+
29
+ //# sourceMappingURL=toProcedure.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toProcedure.mjs","names":[],"sources":["../../src/requests/toProcedure.ts"],"sourcesContent":["import type * as v from \"valibot\";\nimport type {\n AnyProcedureBuilder,\n MutationProcedure,\n ProcedureType,\n QueryProcedure,\n SubscriptionProcedure\n} from \"@trpc/server/unstable-core-do-not-import\";\nimport { isNonNullable } from \"../utils/isNonNullable.js\";\nimport type { Fetcher } from \"./methods.js\";\n\ntype Result<T = void> = T extends v.GenericSchema | v.GenericSchemaAsync\n ? v.InferOutput<T>\n : T;\n\ntype Schema = v.GenericSchema | v.GenericSchemaAsync;\n\ntype ProvedureDef<\n I extends Schema | null = null,\n O extends Schema | null = null\n> = I extends Schema\n ? O extends Schema\n ? {\n input: v.InferInput<I>;\n output: v.InferOutput<O>;\n meta: unknown;\n }\n : { input: v.InferInput<I>; output: undefined; meta: unknown }\n : O extends Schema\n ? { input: undefined; output: v.InferOutput<O>; meta: unknown }\n : {\n input: undefined;\n output: undefined;\n meta: unknown;\n };\n\ntype BaseProcedure<\n T extends ProcedureType,\n I extends Schema | null = null,\n O extends Schema | null = null\n> = T extends `query`\n ? QueryProcedure<ProvedureDef<I, O>>\n : T extends `mutation`\n ? MutationProcedure<ProvedureDef<I, O>>\n : SubscriptionProcedure<ProvedureDef<I, O>>;\n\n/**\n * Given a {@link Fetcher | Fetcher} function and it's associated input and\n * output Zod schemas, this produces a function which accepts a tRPC procedure\n * builder of the given procedure type. This can then be used in a tRPC router\n * to scaffold an API route to forward a request to Discord's API.\n *\n * Capability-free fetchers only — endpoints that require `{ anonymous: true }`\n * or accept `{ reason: string }` cannot currently be wrapped via this helper,\n * because tRPC has no natural channel for those per-call options.\n *\n * @__NO_SIDE_EFFECTS__\n */\nexport const toProcedure =\n <\n T extends ProcedureType,\n I extends Schema | null = null,\n O extends Schema | null = null\n >(\n type: T,\n fn: Fetcher<I extends Schema ? I : null, Result<O>>,\n input?: I,\n output?: O\n ) =>\n (\n procedure: AnyProcedureBuilder,\n errorHandler?: (error: unknown) => void\n ): BaseProcedure<T, I, O> => {\n try {\n if (isNonNullable(input) && isNonNullable(output)) {\n // @ts-expect-error\n return procedure\n .input(input)\n .output(output)\n [type](\n // oxlint-disable-next-line @typescript-eslint/no-unsafe-argument\n async (opts: { input: unknown }) => fn(opts.input as never)\n );\n }\n if (isNonNullable(input) && !isNonNullable(output)) {\n // @ts-expect-error\n return procedure.input(input)[type](\n // oxlint-disable-next-line @typescript-eslint/no-unsafe-argument\n async (opts: { input: unknown }) => fn(opts.input as never)\n );\n }\n if (!isNonNullable(input) && isNonNullable(output)) {\n // @ts-expect-error\n return procedure\n .output(output)\n [type](async () => (fn as () => Promise<Result<O>>)());\n }\n // @ts-expect-error\n return procedure[type](async () => (fn as () => Promise<Result<O>>)());\n } catch (error: unknown) {\n if (typeof errorHandler === `function`) {\n errorHandler(error);\n }\n throw new Error(`Unhandled Procedure Error!`, {\n cause: error\n });\n }\n };\n"],"mappings":";;;;;;;;;;;;;;AA0DA,MAAa,eAMT,MACA,IACA,OACA,YAGA,WACA,iBAC2B;CAC3B,IAAI;EACF,IAAI,cAAc,KAAK,KAAK,cAAc,MAAM,GAE9C,OAAO,UACJ,MAAM,KAAK,EACX,OAAO,MAAM,EACb,MAEC,OAAO,SAA6B,GAAG,KAAK,KAAc,CAC5D;EAEJ,IAAI,cAAc,KAAK,KAAK,CAAC,cAAc,MAAM,GAE/C,OAAO,UAAU,MAAM,KAAK,EAAE,MAE5B,OAAO,SAA6B,GAAG,KAAK,KAAc,CAC5D;EAEF,IAAI,CAAC,cAAc,KAAK,KAAK,cAAc,MAAM,GAE/C,OAAO,UACJ,OAAO,MAAM,EACb,MAAM,YAAa,GAAgC,CAAC;EAGzD,OAAO,UAAU,MAAM,YAAa,GAAgC,CAAC;CACvE,SAAS,OAAgB;EACvB,IAAI,OAAO,iBAAiB,YAC1B,aAAa,KAAK;EAEpB,MAAM,IAAI,MAAM,8BAA8B,EAC5C,OAAO,MACT,CAAC;CACH;AACF"}
@@ -0,0 +1,37 @@
1
+ import { Fetcher } from "./methods.mjs";
2
+
3
+ //#region src/requests/toQuery.d.ts
4
+ interface Register {}
5
+ type QueryKey = readonly unknown[];
6
+ type QueryMeta = Register extends {
7
+ queryMeta: infer TQueryMeta;
8
+ } ? TQueryMeta extends Record<string, unknown> ? TQueryMeta : Record<string, unknown> : Record<string, unknown>;
9
+ type FetchDirection = `backward` | `forward`;
10
+ type QueryFunctionContext<TQueryKey extends QueryKey = QueryKey, TPageParam = never> = [TPageParam] extends [never] ? {
11
+ queryKey: TQueryKey;
12
+ signal: AbortSignal;
13
+ meta: QueryMeta | undefined;
14
+ } : {
15
+ queryKey: TQueryKey;
16
+ signal: AbortSignal;
17
+ pageParam: TPageParam;
18
+ direction: FetchDirection;
19
+ meta: QueryMeta | undefined;
20
+ };
21
+ type QueryFunction<T = unknown, TQueryKey extends QueryKey = QueryKey, TPageParam = never> = (context: QueryFunctionContext<TQueryKey, TPageParam>) => Promise<T> | T;
22
+ /**
23
+ * Given a {@link Fetcher | Fetcher} function, transforms it into a curried function
24
+ * which can then be used with React-Query as a query function without
25
+ * the need for any additional boilerplate.
26
+ *
27
+ * Capability-free fetchers only — endpoints that require `{ anonymous: true }`
28
+ * or accept `{ reason: string }` cannot currently be wrapped via this helper,
29
+ * because react-query has no natural channel for those per-call options.
30
+ *
31
+ * @__NO_SIDE_EFFECTS__
32
+ */
33
+ declare function toQuery<R>(fn: Fetcher<null, R>): () => QueryFunction<R>;
34
+ declare function toQuery<TConfig, R>(fn: (config: TConfig, options?: never) => Promise<R>): (config: TConfig) => QueryFunction<R>;
35
+ //#endregion
36
+ export { QueryFunction, toQuery };
37
+ //# sourceMappingURL=toQuery.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toQuery.d.mts","names":[],"sources":["../../src/requests/toQuery.ts"],"mappings":";;;UAMU,QAAA;AAAA,KACL,QAAA;AAAA,KACA,SAAA,GAAY,QAAA;EACf,SAAA;AAAA,IAEE,UAAA,SAAmB,MAAA,oBACjB,UAAA,GACA,MAAA,oBACF,MAAA;AAAA,KACC,cAAA;AAAA,KACA,oBAAA,mBACe,QAAA,GAAW,QAAA,yBAE1B,UAAA;EAEC,QAAA,EAAU,SAAA;EACV,MAAA,EAAQ,WAAA;EACR,IAAA,EAAM,SAAA;AAAA;EAGN,QAAA,EAAU,SAAA;EACV,MAAA,EAAQ,WAAA;EACR,SAAA,EAAW,UAAA;EACX,SAAA,EAAW,cAAA;EACX,IAAA,EAAM,SAAA;AAAA;AAAA,KAEA,aAAA,gCAEQ,QAAA,GAAW,QAAA,yBAE1B,OAAA,EAAS,oBAAA,CAAqB,SAAA,EAAW,UAAA,MAAgB,OAAA,CAAQ,CAAA,IAAK,CAAA;;;;;;;;;;;;iBA4B3D,OAAA,IAAW,EAAA,EAAI,OAAA,OAAc,CAAA,UAAW,aAAA,CAAc,CAAA;AAAA,iBACtD,OAAA,aACd,EAAA,GAAK,MAAA,EAAQ,OAAA,EAAS,OAAA,aAAoB,OAAA,CAAQ,CAAA,KAChD,MAAA,EAAQ,OAAA,KAAY,aAAA,CAAc,CAAA"}
@@ -0,0 +1,10 @@
1
+ //#region src/requests/toQuery.ts
2
+ function toQuery(fn) {
3
+ return (...config) => async () => {
4
+ return fn(...config);
5
+ };
6
+ }
7
+ //#endregion
8
+ export { toQuery };
9
+
10
+ //# sourceMappingURL=toQuery.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toQuery.mjs","names":["call"],"sources":["../../src/requests/toQuery.ts"],"sourcesContent":["import type { Fetcher } from \"./methods.js\";\n\n/* Lifted from @tanstack/react-query */\n// Intentional declaration-merging surface: consumers extend `Register`\n// to override `queryMeta` and other framework-wide types.\n// oxlint-disable-next-line typescript/no-empty-object-type\ninterface Register {}\ntype QueryKey = readonly unknown[];\ntype QueryMeta = Register extends {\n queryMeta: infer TQueryMeta;\n}\n ? TQueryMeta extends Record<string, unknown>\n ? TQueryMeta\n : Record<string, unknown>\n : Record<string, unknown>;\ntype FetchDirection = `backward` | `forward`;\ntype QueryFunctionContext<\n TQueryKey extends QueryKey = QueryKey,\n TPageParam = never\n> = [TPageParam] extends [never]\n ? {\n queryKey: TQueryKey;\n signal: AbortSignal;\n meta: QueryMeta | undefined;\n }\n : {\n queryKey: TQueryKey;\n signal: AbortSignal;\n pageParam: TPageParam;\n direction: FetchDirection;\n meta: QueryMeta | undefined;\n };\nexport type QueryFunction<\n T = unknown,\n TQueryKey extends QueryKey = QueryKey,\n TPageParam = never\n> = (context: QueryFunctionContext<TQueryKey, TPageParam>) => Promise<T> | T;\n\n/**\n * Given a {@link Fetcher | Fetcher} function, transforms it into a curried function\n * which can then be used with React-Query as a query function without\n * the need for any additional boilerplate.\n *\n * Capability-free fetchers only — endpoints that require `{ anonymous: true }`\n * or accept `{ reason: string }` cannot currently be wrapped via this helper,\n * because react-query has no natural channel for those per-call options.\n *\n * @__NO_SIDE_EFFECTS__\n */\n// Two overloads disambiguate the no-input vs input-accepting Fetcher\n// shapes. Under strict mode, a single signature with a conditional return\n// type forces TS to check the argument against the union of both branches\n// at the call site, which fails on contravariant param positions.\n// Overloads let inference pick one branch at a time.\n//\n// The second overload uses a structural shape `(config: TConfig, options?:\n// unknown) => Promise<R>` rather than `Fetcher<S, R>` so TS can infer\n// `TConfig` directly from the supplied callback's first parameter — going\n// through `Fetcher<S, R>` would require TS to first invert the conditional\n// type `S extends null ? ... : ...` to recover `S`, which it gives up on.\n// The runtime check is unchanged (the implementation casts internally), so\n// the looser structural type doesn't widen what consumers can pass in any\n// meaningful way — every endpoint Fetcher in the codebase is shaped this\n// way already.\nexport function toQuery<R>(fn: Fetcher<null, R>): () => QueryFunction<R>;\nexport function toQuery<TConfig, R>(\n fn: (config: TConfig, options?: never) => Promise<R>\n): (config: TConfig) => QueryFunction<R>;\nexport function toQuery<R>(\n fn: (...args: never[]) => Promise<R>\n): (...config: [unknown]) => QueryFunction<R> {\n return (...config: [unknown]) =>\n async () => {\n const call = fn as unknown as (...args: unknown[]) => Promise<R>;\n return call(...config);\n };\n}\n"],"mappings":";AAoEA,SAAgB,QACd,IAC4C;CAC5C,QAAQ,GAAG,WACT,YAAY;EAEV,OAAOA,GAAK,GAAG,MAAM;CACvB;AACJ"}
@@ -0,0 +1,17 @@
1
+ import { Fetcher, FetcherCapabilities } from "./methods.mjs";
2
+ import { GenericSchema, GenericSchemaAsync } from "valibot";
3
+
4
+ //#region src/requests/toValidated.d.ts
5
+ /**
6
+ * Given a {@link Fetcher | Fetcher} function and it's associated input
7
+ * and output Zod schemas, this returns a new validated {@link Fetcher | Fetcher} function which will validate it's input and result at runtime.
8
+ * This is useful in contexts where you want strong guarantees on runtime
9
+ * type-safety when dealing with raw user input in a framework agnostic
10
+ * environment.
11
+ *
12
+ * @__NO_SIDE_EFFECTS__
13
+ */
14
+ declare const toValidated: <S extends GenericSchema | GenericSchemaAsync | null = null, R = void, C extends FetcherCapabilities = {}>(fn: Fetcher<S, R, C>, input?: S | null, output?: GenericSchema<unknown, R> | GenericSchemaAsync<unknown, R>) => Fetcher<S, R, C>;
15
+ //#endregion
16
+ export { toValidated };
17
+ //# sourceMappingURL=toValidated.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toValidated.d.mts","names":[],"sources":["../../src/requests/toValidated.ts"],"mappings":";;;;;;AAkBA;;;;;;;cAAa,WAAA,aACD,aAAA,GAAgB,kBAAA,oCAGhB,mBAAA,OAEV,EAAA,EAAI,OAAA,CAAQ,CAAA,EAAG,CAAA,EAAG,CAAA,GAClB,KAAA,GAAQ,CAAA,SACR,MAAA,GAAS,aAAA,UAAuB,CAAA,IAAK,kBAAA,UAA4B,CAAA,MAChE,OAAA,CAAQ,CAAA,EAAG,CAAA,EAAG,CAAA"}
@@ -0,0 +1,27 @@
1
+ import { isOfKind, safeParseAsync, summarize } from "valibot";
2
+ //#region src/requests/toValidated.ts
3
+ /**
4
+ * Given a {@link Fetcher | Fetcher} function and it's associated input
5
+ * and output Zod schemas, this returns a new validated {@link Fetcher | Fetcher} function which will validate it's input and result at runtime.
6
+ * This is useful in contexts where you want strong guarantees on runtime
7
+ * type-safety when dealing with raw user input in a framework agnostic
8
+ * environment.
9
+ *
10
+ * @__NO_SIDE_EFFECTS__
11
+ */
12
+ const toValidated = (fn, input, output) => new Proxy(fn, { async apply(target, _, [config, options]) {
13
+ if (input && isOfKind(`schema`, input)) {
14
+ const { issues } = await safeParseAsync(input, config);
15
+ if (issues) throw new Error(`Failed to parse input schema: ${input.reference.name}\n\n${summarize(issues)}`);
16
+ }
17
+ const result = await target(config, options);
18
+ if (output && isOfKind(`schema`, output)) {
19
+ const { issues } = await safeParseAsync(output, result);
20
+ if (issues) throw new Error(`Failed to parse input schema: ${output.reference.name}\n\n${summarize(issues)}`);
21
+ }
22
+ return result;
23
+ } });
24
+ //#endregion
25
+ export { toValidated };
26
+
27
+ //# sourceMappingURL=toValidated.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toValidated.mjs","names":["call"],"sources":["../../src/requests/toValidated.ts"],"sourcesContent":["import {\n type GenericSchema,\n type GenericSchemaAsync,\n isOfKind,\n safeParseAsync,\n summarize\n} from \"valibot\";\nimport type { Fetcher, FetcherCapabilities } from \"./methods.js\";\n\n/**\n * Given a {@link Fetcher | Fetcher} function and it's associated input\n * and output Zod schemas, this returns a new validated {@link Fetcher | Fetcher} function which will validate it's input and result at runtime.\n * This is useful in contexts where you want strong guarantees on runtime\n * type-safety when dealing with raw user input in a framework agnostic\n * environment.\n *\n * @__NO_SIDE_EFFECTS__\n */\nexport const toValidated = <\n S extends GenericSchema | GenericSchemaAsync | null = null,\n R = void,\n // oxlint-disable-next-line typescript/no-empty-object-type\n C extends FetcherCapabilities = {}\n>(\n fn: Fetcher<S, R, C>,\n input?: S | null,\n output?: GenericSchema<unknown, R> | GenericSchemaAsync<unknown, R>\n): Fetcher<S, R, C> =>\n new Proxy<Fetcher<S, R, C>>(fn, {\n async apply(target, _, [config, options]): Promise<R> {\n // Validate the fetcher args before fetching\n if (input && isOfKind(`schema`, input)) {\n const { issues } = await safeParseAsync(input, config);\n if (issues) {\n throw new Error(\n `Failed to parse input schema: ${input.reference.name}\\n\\n${summarize(issues)}`\n );\n }\n }\n\n // Forward the per-call options (anonymous, reason) to the underlying\n // fetcher. The proxy was previously dropping the second argument.\n const call = target as unknown as (\n ...args: unknown[]\n ) => Promise<unknown>;\n const result = (await call(config, options)) as R;\n\n // Validate the result of the fetch call before returning\n if (output && isOfKind(`schema`, output)) {\n const { issues } = await safeParseAsync(output, result);\n if (issues) {\n throw new Error(\n `Failed to parse input schema: ${output.reference.name}\\n\\n${summarize(issues)}`\n );\n }\n }\n\n return result;\n }\n });\n"],"mappings":";;;;;;;;;;;AAkBA,MAAa,eAMX,IACA,OACA,WAEA,IAAI,MAAwB,IAAI,EAC9B,MAAM,MAAM,QAAQ,GAAG,CAAC,QAAQ,UAAsB;CAEpD,IAAI,SAAS,SAAS,UAAU,KAAK,GAAG;EACtC,MAAM,EAAE,WAAW,MAAM,eAAe,OAAO,MAAM;EACrD,IAAI,QACF,MAAM,IAAI,MACR,iCAAiC,MAAM,UAAU,KAAK,MAAM,UAAU,MAAM,GAC9E;CAEJ;CAOA,MAAM,SAAU,MAAMA,OAAK,QAAQ,OAAO;CAG1C,IAAI,UAAU,SAAS,UAAU,MAAM,GAAG;EACxC,MAAM,EAAE,WAAW,MAAM,eAAe,QAAQ,MAAM;EACtD,IAAI,QACF,MAAM,IAAI,MACR,iCAAiC,OAAO,UAAU,KAAK,MAAM,UAAU,MAAM,GAC/E;CAEJ;CAEA,OAAO;AACT,EACF,CAAC"}
@@ -1,3 +1,4 @@
1
+ //#region src/requests/verifyKey.d.ts
1
2
  /**
2
3
  * Validates a payload from Discord against its signature and key.
3
4
  *
@@ -7,4 +8,7 @@
7
8
  * @param clientPublicKey - The public key from the Discord developer dashboard
8
9
  * @returns Whether or not validation was successful
9
10
  */
10
- export declare function verifyKey(rawBody: Uint8Array | ArrayBuffer | Buffer | string, signature: string, timestamp: string, clientPublicKey: string | CryptoKey): Promise<boolean>;
11
+ declare function verifyKey(rawBody: Uint8Array | ArrayBuffer | Buffer | string, signature: string, timestamp: string, clientPublicKey: string | CryptoKey): Promise<boolean>;
12
+ //#endregion
13
+ export { verifyKey };
14
+ //# sourceMappingURL=verifyKey.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifyKey.d.mts","names":[],"sources":["../../src/requests/verifyKey.ts"],"mappings":";;AAqGA;;;;;;;;iBAAsB,SAAA,CACpB,OAAA,EAAS,UAAA,GAAa,WAAA,GAAc,MAAA,WACpC,SAAA,UACA,SAAA,UACA,eAAA,WAA0B,SAAA,GACzB,OAAA"}
@@ -0,0 +1,64 @@
1
+ //#region src/requests/verifyKey.ts
2
+ const getSubtleCrypto = () => {
3
+ if (typeof globalThis.crypto !== `undefined`) return globalThis.crypto.subtle;
4
+ const maybeGlobal = typeof global !== `undefined` ? global : void 0;
5
+ if (maybeGlobal?.crypto?.subtle) return maybeGlobal.crypto.subtle;
6
+ const maybeWindow = typeof window !== `undefined` ? window : void 0;
7
+ if (maybeWindow?.crypto?.subtle) return maybeWindow.crypto.subtle;
8
+ throw new Error(`SubtleCrypto is not available in this environment`);
9
+ };
10
+ const subtleCrypto = getSubtleCrypto();
11
+ /**
12
+ * Convert various input types to Uint8Array
13
+ */
14
+ function valueToUint8Array(value, encoding) {
15
+ if (value instanceof Uint8Array) return value;
16
+ if (value instanceof ArrayBuffer) return new Uint8Array(value);
17
+ if (typeof Buffer !== `undefined` && Buffer.isBuffer(value)) return new Uint8Array(value);
18
+ if (typeof value === `string`) {
19
+ if (encoding === `hex`) {
20
+ const matches = value.match(/.{1,2}/g);
21
+ if (!matches) throw new Error(`Invalid hex string`);
22
+ return new Uint8Array(matches.map((byte) => parseInt(byte, 16)));
23
+ }
24
+ return new TextEncoder().encode(value);
25
+ }
26
+ throw new Error(`Unsupported value type`);
27
+ }
28
+ /**
29
+ * Concatenate multiple Uint8Arrays into a single Uint8Array
30
+ */
31
+ function concatUint8Arrays(...arrays) {
32
+ const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
33
+ const result = new Uint8Array(totalLength);
34
+ let offset = 0;
35
+ for (const arr of arrays) {
36
+ result.set(arr, offset);
37
+ offset += arr.length;
38
+ }
39
+ return result;
40
+ }
41
+ /**
42
+ * Validates a payload from Discord against its signature and key.
43
+ *
44
+ * @param rawBody - The raw payload data
45
+ * @param signature - The signature from the `X-Signature-Ed25519` header
46
+ * @param timestamp - The timestamp from the `X-Signature-Timestamp` header
47
+ * @param clientPublicKey - The public key from the Discord developer dashboard
48
+ * @returns Whether or not validation was successful
49
+ */
50
+ async function verifyKey(rawBody, signature, timestamp, clientPublicKey) {
51
+ try {
52
+ return await subtleCrypto.verify({ name: `ed25519` }, typeof clientPublicKey === `string` ? await subtleCrypto.importKey(`raw`, Buffer.from(valueToUint8Array(clientPublicKey, `hex`)), {
53
+ name: `ed25519`,
54
+ namedCurve: `ed25519`
55
+ }, false, [`verify`]) : clientPublicKey, Buffer.from(valueToUint8Array(signature, `hex`)), Buffer.from(concatUint8Arrays(valueToUint8Array(timestamp), valueToUint8Array(rawBody))));
56
+ } catch (err) {
57
+ console.error(`Signature verification failed:`, err);
58
+ return false;
59
+ }
60
+ }
61
+ //#endregion
62
+ export { verifyKey };
63
+
64
+ //# sourceMappingURL=verifyKey.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifyKey.mjs","names":[],"sources":["../../src/requests/verifyKey.ts"],"sourcesContent":["/**\n * Get the SubtleCrypto interface for the current environment.\n * Modern Node and browsers both expose `globalThis.crypto.subtle`;\n * the older Node fallback and the browser-specific `window.crypto`\n * branches handle environments where that's not the case.\n */\ninterface MaybeCrypto {\n crypto?: { subtle?: SubtleCrypto };\n}\n\nconst getSubtleCrypto = (): SubtleCrypto => {\n // Modern Node.js / browsers / workers\n if (typeof globalThis.crypto !== `undefined`) {\n return globalThis.crypto.subtle;\n }\n\n // Older Node.js versions where `crypto` lives on `global`, not `globalThis`.\n const maybeGlobal: MaybeCrypto | undefined =\n typeof global !== `undefined` ? (global as MaybeCrypto) : undefined;\n if (maybeGlobal?.crypto?.subtle) {\n return maybeGlobal.crypto.subtle;\n }\n\n // Browser environment where `window.crypto` is the only path.\n const maybeWindow: MaybeCrypto | undefined =\n typeof window !== `undefined` ? (window as MaybeCrypto) : undefined;\n if (maybeWindow?.crypto?.subtle) {\n return maybeWindow.crypto.subtle;\n }\n\n throw new Error(`SubtleCrypto is not available in this environment`);\n};\n\nconst subtleCrypto = getSubtleCrypto();\n\n/**\n * Convert various input types to Uint8Array\n */\nfunction valueToUint8Array(\n value: Uint8Array | ArrayBuffer | Buffer | string,\n encoding?: `hex` | `utf-8`\n): Uint8Array {\n // Already a Uint8Array\n if (value instanceof Uint8Array) {\n return value;\n }\n\n // ArrayBuffer\n if (value instanceof ArrayBuffer) {\n return new Uint8Array(value);\n }\n\n // Buffer (Node.js)\n if (typeof Buffer !== `undefined` && Buffer.isBuffer(value)) {\n return new Uint8Array(value);\n }\n\n // String\n if (typeof value === `string`) {\n if (encoding === `hex`) {\n // Convert hex string to Uint8Array\n const matches = value.match(/.{1,2}/g);\n if (!matches) {\n throw new Error(`Invalid hex string`);\n }\n return new Uint8Array(matches.map((byte) => parseInt(byte, 16)));\n }\n\n // Default to UTF-8 encoding\n const encoder = new TextEncoder();\n return encoder.encode(value);\n }\n\n throw new Error(`Unsupported value type`);\n}\n\n/**\n * Concatenate multiple Uint8Arrays into a single Uint8Array\n */\nfunction concatUint8Arrays(...arrays: Uint8Array[]): Uint8Array {\n const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);\n const result = new Uint8Array(totalLength);\n\n let offset = 0;\n for (const arr of arrays) {\n result.set(arr, offset);\n offset += arr.length;\n }\n\n return result;\n}\n\n/**\n * Validates a payload from Discord against its signature and key.\n *\n * @param rawBody - The raw payload data\n * @param signature - The signature from the `X-Signature-Ed25519` header\n * @param timestamp - The timestamp from the `X-Signature-Timestamp` header\n * @param clientPublicKey - The public key from the Discord developer dashboard\n * @returns Whether or not validation was successful\n */\nexport async function verifyKey(\n rawBody: Uint8Array | ArrayBuffer | Buffer | string,\n signature: string,\n timestamp: string,\n clientPublicKey: string | CryptoKey\n): Promise<boolean> {\n try {\n return await subtleCrypto.verify(\n {\n name: `ed25519`\n } as AlgorithmIdentifier,\n typeof clientPublicKey === `string`\n ? await subtleCrypto.importKey(\n `raw`,\n Buffer.from(valueToUint8Array(clientPublicKey, `hex`)),\n {\n name: `ed25519`,\n namedCurve: `ed25519`\n } as EcKeyImportParams, // Type assertion for Ed25519\n false,\n [`verify`]\n )\n : clientPublicKey,\n Buffer.from(valueToUint8Array(signature, `hex`)),\n Buffer.from(\n concatUint8Arrays(\n valueToUint8Array(timestamp),\n valueToUint8Array(rawBody)\n )\n )\n );\n } catch (err) {\n console.error(`Signature verification failed:`, err);\n return false;\n }\n}\n"],"mappings":";AAUA,MAAM,wBAAsC;CAE1C,IAAI,OAAO,WAAW,WAAW,aAC/B,OAAO,WAAW,OAAO;CAI3B,MAAM,cACJ,OAAO,WAAW,cAAe,SAAyB,KAAA;CAC5D,IAAI,aAAa,QAAQ,QACvB,OAAO,YAAY,OAAO;CAI5B,MAAM,cACJ,OAAO,WAAW,cAAe,SAAyB,KAAA;CAC5D,IAAI,aAAa,QAAQ,QACvB,OAAO,YAAY,OAAO;CAG5B,MAAM,IAAI,MAAM,mDAAmD;AACrE;AAEA,MAAM,eAAe,gBAAgB;;;;AAKrC,SAAS,kBACP,OACA,UACY;CAEZ,IAAI,iBAAiB,YACnB,OAAO;CAIT,IAAI,iBAAiB,aACnB,OAAO,IAAI,WAAW,KAAK;CAI7B,IAAI,OAAO,WAAW,eAAe,OAAO,SAAS,KAAK,GACxD,OAAO,IAAI,WAAW,KAAK;CAI7B,IAAI,OAAO,UAAU,UAAU;EAC7B,IAAI,aAAa,OAAO;GAEtB,MAAM,UAAU,MAAM,MAAM,SAAS;GACrC,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,oBAAoB;GAEtC,OAAO,IAAI,WAAW,QAAQ,KAAK,SAAS,SAAS,MAAM,EAAE,CAAC,CAAC;EACjE;EAIA,OAAO,IADa,YACP,EAAE,OAAO,KAAK;CAC7B;CAEA,MAAM,IAAI,MAAM,wBAAwB;AAC1C;;;;AAKA,SAAS,kBAAkB,GAAG,QAAkC;CAC9D,MAAM,cAAc,OAAO,QAAQ,KAAK,QAAQ,MAAM,IAAI,QAAQ,CAAC;CACnE,MAAM,SAAS,IAAI,WAAW,WAAW;CAEzC,IAAI,SAAS;CACb,KAAK,MAAM,OAAO,QAAQ;EACxB,OAAO,IAAI,KAAK,MAAM;EACtB,UAAU,IAAI;CAChB;CAEA,OAAO;AACT;;;;;;;;;;AAWA,eAAsB,UACpB,SACA,WACA,WACA,iBACkB;CAClB,IAAI;EACF,OAAO,MAAM,aAAa,OACxB,EACE,MAAM,UACR,GACA,OAAO,oBAAoB,WACvB,MAAM,aAAa,UACjB,OACA,OAAO,KAAK,kBAAkB,iBAAiB,KAAK,CAAC,GACrD;GACE,MAAM;GACN,YAAY;EACd,GACA,OACA,CAAC,QAAQ,CACX,IACA,iBACJ,OAAO,KAAK,kBAAkB,WAAW,KAAK,CAAC,GAC/C,OAAO,KACL,kBACE,kBAAkB,SAAS,GAC3B,kBAAkB,OAAO,CAC3B,CACF,CACF;CACF,SAAS,KAAK;EACZ,QAAQ,MAAM,kCAAkC,GAAG;EACnD,OAAO;CACT;AACF"}
@@ -0,0 +1,5 @@
1
+ //#region src/utils/isBetween.d.ts
2
+ declare const isBetween: (val: number, min: number, max: number) => boolean;
3
+ //#endregion
4
+ export { isBetween };
5
+ //# sourceMappingURL=isBetween.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isBetween.d.mts","names":[],"sources":["../../src/utils/isBetween.ts"],"mappings":";cAAa,SAAA,GAAa,GAAA,UAAa,GAAA,UAAa,GAAA"}
@@ -0,0 +1,6 @@
1
+ //#region src/utils/isBetween.ts
2
+ const isBetween = (val, min, max) => val >= min && val <= max;
3
+ //#endregion
4
+ export { isBetween };
5
+
6
+ //# sourceMappingURL=isBetween.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isBetween.mjs","names":[],"sources":["../../src/utils/isBetween.ts"],"sourcesContent":["export const isBetween = (val: number, min: number, max: number): boolean =>\n val >= min && val <= max;\n"],"mappings":";AAAA,MAAa,aAAa,KAAa,KAAa,QAClD,OAAO,OAAO,OAAO"}
@@ -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,7 @@
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 };
24
+ //# sourceMappingURL=isNonNullable.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isNonNullable.d.mts","names":[],"sources":["../../src/utils/isNonNullable.ts"],"mappings":";KAAY,KAAA,MAAW,CAAC;AAAxB;;;;AAAwB;AAoBxB;;;;;;;;;;;;;AApBA,cAoBa,aAAA,aAA2B,KAAA,WACtC,GAAA,GAAM,CAAA,KACL,GAAA,IAAO,WAAA,CAAY,CAAA"}
@@ -0,0 +1,24 @@
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 };
23
+
24
+ //# sourceMappingURL=isNonNullable.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isNonNullable.mjs","names":[],"sources":["../../src/utils/isNonNullable.ts"],"sourcesContent":["export type Maybe<T> = T | null | undefined;\n\n/**\n * Used to test whether a `Maybe` typed value is `null` or `undefined`.\n *\n * When called, the given value's type is narrowed to `NonNullable<T>`.\n *\n * ### Example Usage:\n *\n * ```ts\n * const fn = (str: Maybe<string>) => {\n * if (!isNonNullable(str)) {\n * // typeof str = null | undefined\n * // ...\n * }\n * // typeof str = string\n * // ...\n * }\n * ```\n */\nexport const isNonNullable = <T extends Maybe<unknown>>(\n val?: T\n): val is NonNullable<T> => typeof val !== `undefined` && val !== null;\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoBA,MAAa,iBACX,QAC0B,OAAO,QAAQ,eAAe,QAAQ"}
@@ -0,0 +1,5 @@
1
+ //#region src/utils/isNumericString.d.ts
2
+ declare const isNumericString: (val: unknown) => val is string;
3
+ //#endregion
4
+ export { isNumericString };
5
+ //# sourceMappingURL=isNumericString.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isNumericString.d.mts","names":[],"sources":["../../src/utils/isNumericString.ts"],"mappings":";cAAa,eAAA,GAAmB,GAAA,cAAe,GAAG"}
@@ -0,0 +1,6 @@
1
+ //#region src/utils/isNumericString.ts
2
+ const isNumericString = (val) => typeof val === `string` && /^\d+$/.test(val);
3
+ //#endregion
4
+ export { isNumericString };
5
+
6
+ //# sourceMappingURL=isNumericString.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isNumericString.mjs","names":[],"sources":["../../src/utils/isNumericString.ts"],"sourcesContent":["export const isNumericString = (val: unknown): val is string =>\n typeof val === `string` && /^\\d+$/.test(val);\n"],"mappings":";AAAA,MAAa,mBAAmB,QAC9B,OAAO,QAAQ,YAAY,QAAQ,KAAK,GAAG"}
@@ -0,0 +1,5 @@
1
+ //#region src/utils/isObject.d.ts
2
+ declare const isObject: (val: unknown) => val is Record<string, unknown>;
3
+ //#endregion
4
+ export { isObject };
5
+ //# sourceMappingURL=isObject.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isObject.d.mts","names":[],"sources":["../../src/utils/isObject.ts"],"mappings":";cAAa,QAAA,GAAY,GAAA,cAAe,GAAA,IAAO,MAAM"}
@@ -0,0 +1,6 @@
1
+ //#region src/utils/isObject.ts
2
+ const isObject = (val) => Boolean(val) && typeof val === `object` && !Array.isArray(val);
3
+ //#endregion
4
+ export { isObject };
5
+
6
+ //# sourceMappingURL=isObject.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isObject.mjs","names":[],"sources":["../../src/utils/isObject.ts"],"sourcesContent":["export const isObject = (val: unknown): val is Record<string, unknown> =>\n Boolean(val) && typeof val === `object` && !Array.isArray(val);\n"],"mappings":";AAAA,MAAa,YAAY,QACvB,QAAQ,GAAG,KAAK,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,GAAG"}
@@ -0,0 +1,8 @@
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 };
8
+ //# sourceMappingURL=sleep.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sleep.d.mts","names":[],"sources":["../../src/utils/sleep.ts"],"mappings":";;AAGA;;cAAa,KAAA,GAAe,EAAA,aAAa,OAAO"}
@@ -0,0 +1,9 @@
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 };
8
+
9
+ //# sourceMappingURL=sleep.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sleep.mjs","names":[],"sources":["../../src/utils/sleep.ts"],"sourcesContent":["/**\n * Sleep for a given number of milliseconds\n */\nexport const sleep = async (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));\n"],"mappings":";;;;AAGA,MAAa,QAAQ,OAAO,OAC1B,IAAI,SAAS,YAAY,WAAW,SAAS,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ //#region src/utils/toCamelCase.d.ts
2
+ declare const toCamelCase: (str: string) => string;
3
+ //#endregion
4
+ export { toCamelCase };
5
+ //# sourceMappingURL=toCamelCase.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toCamelCase.d.mts","names":[],"sources":["../../src/utils/toCamelCase.ts"],"mappings":";cAAa,WAAA,GAAe,GAAW"}
@@ -0,0 +1,6 @@
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 };
5
+
6
+ //# sourceMappingURL=toCamelCase.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toCamelCase.mjs","names":[],"sources":["../../src/utils/toCamelCase.ts"],"sourcesContent":["export const toCamelCase = (str: string): string =>\n str.replace(/_(?<char>[a-zA-Z])/g, (g) => g[1].toUpperCase());\n"],"mappings":";AAAA,MAAa,eAAe,QAC1B,IAAI,QAAQ,wBAAwB,MAAM,EAAE,GAAG,YAAY,CAAC"}
@@ -0,0 +1,20 @@
1
+ //#region src/utils/toCamelKeys.d.ts
2
+ /**
3
+ * Convert a `snake_case` string-literal type to `camelCase`, matching exactly
4
+ * what {@link toCamelCase} does at runtime: each `_x` becomes `X`. Self-contained
5
+ * (no general word-splitting); we only ever convert underscore-delimited Discord
6
+ * API keys, so this is all the casing we need.
7
+ */
8
+ type CamelCase<S extends string> = S extends `${infer Head}_${infer Tail}` ? `${Head}${CamelCase<Capitalize<Tail>>}` : S;
9
+ /**
10
+ * Recursively camel-case the keys of an object/array type. Mirrors
11
+ * {@link toCamelKeys}'s runtime: arrays map element-wise, plain objects remap
12
+ * their keys, and leaf values pass through unchanged. Replaces type-fest's
13
+ * `CamelCasedPropertiesDeep` — narrower (no Set/tuple/options handling) because
14
+ * the only inputs are plain nested Discord API JSON.
15
+ */
16
+ type CamelKeys<T> = T extends ReadonlyArray<infer U> ? Array<CamelKeys<U>> : T extends object ? { [K in keyof T as K extends string ? CamelCase<K> : K]: CamelKeys<T[K]> } : T;
17
+ declare const toCamelKeys: <T extends object>(o: T) => CamelKeys<T>;
18
+ //#endregion
19
+ export { CamelKeys, toCamelKeys };
20
+ //# sourceMappingURL=toCamelKeys.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toCamelKeys.d.mts","names":[],"sources":["../../src/utils/toCamelKeys.ts"],"mappings":";;;;;;;KASK,SAAA,qBAA8B,CAAA,4CAC5B,IAAA,GAAO,SAAA,CAAU,UAAA,CAAW,IAAA,OAC/B,CAAA;;;;;;;;KASQ,SAAA,MACV,CAAA,SAAU,aAAA,YACN,KAAA,CAAM,SAAA,CAAU,CAAA,KAChB,CAAA,gCAEgB,CAAA,IAAK,CAAA,kBAAmB,SAAA,CAAU,CAAA,IAAK,CAAA,GAAI,SAAA,CACrD,CAAA,CAAE,CAAA,OAGN,CAAA;AAAA,cAEK,WAAA,qBAAiC,CAAA,EAAG,CAAA,KAAI,SAAA,CAAU,CAAA"}
@@ -0,0 +1,15 @@
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 };
14
+
15
+ //# sourceMappingURL=toCamelKeys.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toCamelKeys.mjs","names":[],"sources":["../../src/utils/toCamelKeys.ts"],"sourcesContent":["import { isObject } from \"./isObject.js\";\nimport { toCamelCase } from \"./toCamelCase.js\";\n\n/**\n * Convert a `snake_case` string-literal type to `camelCase`, matching exactly\n * what {@link toCamelCase} does at runtime: each `_x` becomes `X`. Self-contained\n * (no general word-splitting); we only ever convert underscore-delimited Discord\n * API keys, so this is all the casing we need.\n */\ntype CamelCase<S extends string> = S extends `${infer Head}_${infer Tail}`\n ? `${Head}${CamelCase<Capitalize<Tail>>}`\n : S;\n\n/**\n * Recursively camel-case the keys of an object/array type. Mirrors\n * {@link toCamelKeys}'s runtime: arrays map element-wise, plain objects remap\n * their keys, and leaf values pass through unchanged. Replaces type-fest's\n * `CamelCasedPropertiesDeep` — narrower (no Set/tuple/options handling) because\n * the only inputs are plain nested Discord API JSON.\n */\nexport type CamelKeys<T> =\n T extends ReadonlyArray<infer U>\n ? Array<CamelKeys<U>>\n : T extends object\n ? {\n [K in keyof T as K extends string ? CamelCase<K> : K]: CamelKeys<\n T[K]\n >;\n }\n : T;\n\nexport const toCamelKeys = <T extends object>(o: T): CamelKeys<T> => {\n if (Array.isArray(o)) {\n return o.map(toCamelKeys) as CamelKeys<T>;\n } else if (isObject(o)) {\n return Object.entries(o).reduce((acc, [key, value]) => {\n // @ts-expect-error\n acc[toCamelCase(key)] = toCamelKeys(value);\n return acc;\n }, {}) as CamelKeys<T>;\n }\n\n return o as CamelKeys<T>;\n};\n"],"mappings":";;;AA+BA,MAAa,eAAiC,MAAuB;CACnE,IAAI,MAAM,QAAQ,CAAC,GACjB,OAAO,EAAE,IAAI,WAAW;MACnB,IAAI,SAAS,CAAC,GACnB,OAAO,OAAO,QAAQ,CAAC,EAAE,QAAQ,KAAK,CAAC,KAAK,WAAW;EAErD,IAAI,YAAY,GAAG,KAAK,YAAY,KAAK;EACzC,OAAO;CACT,GAAG,CAAC,CAAC;CAGP,OAAO;AACT"}
@@ -0,0 +1,5 @@
1
+ //#region src/utils/toSnakeCase.d.ts
2
+ declare const toSnakeCase: (str: string) => string;
3
+ //#endregion
4
+ export { toSnakeCase };
5
+ //# sourceMappingURL=toSnakeCase.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toSnakeCase.d.mts","names":[],"sources":["../../src/utils/toSnakeCase.ts"],"mappings":";cAAa,WAAA,GAAe,GAAW"}
@@ -0,0 +1,6 @@
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 };
5
+
6
+ //# sourceMappingURL=toSnakeCase.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toSnakeCase.mjs","names":[],"sources":["../../src/utils/toSnakeCase.ts"],"sourcesContent":["export const toSnakeCase = (str: string): string =>\n str\n .replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)\n .substring(str.slice(0, 1).match(/(?<char>[A-Z])/g) ? 1 : 0);\n"],"mappings":";AAAA,MAAa,eAAe,QAC1B,IACG,QAAQ,WAAW,WAAW,IAAI,OAAO,YAAY,GAAG,EACxD,UAAU,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,iBAAiB,IAAI,IAAI,CAAC"}
@@ -0,0 +1,24 @@
1
+ //#region src/utils/toSnakeKeys.d.ts
2
+ /** The uppercase ASCII letters, for the camel→snake split. */
3
+ type Upper = `A` | `B` | `C` | `D` | `E` | `F` | `G` | `H` | `I` | `J` | `K` | `L` | `M` | `N` | `O` | `P` | `Q` | `R` | `S` | `T` | `U` | `V` | `W` | `X` | `Y` | `Z`;
4
+ /**
5
+ * Walk a `camelCase` literal, inserting `_` before each uppercase letter and
6
+ * lowercasing it — matching {@link toSnakeCase}'s runtime. `Started` tracks
7
+ * whether we've emitted any character yet, so a leading capital (e.g. `Foo`)
8
+ * doesn't get a leading underscore (→ `foo`, not `_foo`).
9
+ */
10
+ type SnakeWalk<S extends string, Started extends boolean = false> = S extends `${infer Head}${infer Tail}` ? Head extends Upper ? `${Started extends true ? `_` : ``}${Lowercase<Head>}${SnakeWalk<Tail, true>}` : `${Head}${SnakeWalk<Tail, true>}` : S;
11
+ /** Convert a `camelCase` string-literal type to `snake_case`. Self-contained;
12
+ * mirrors {@link toSnakeCase} (the only transform we apply to API keys). */
13
+ type SnakeCase<S extends string> = SnakeWalk<S>;
14
+ /**
15
+ * Recursively snake-case the keys of an object/array type. Mirrors
16
+ * {@link toSnakeKeys}'s runtime. Replaces type-fest's `SnakeCasedPropertiesDeep`
17
+ * — narrower (no Set/tuple/options handling) because the only inputs are plain
18
+ * nested Discord API JSON.
19
+ */
20
+ type SnakeKeys<T> = T extends ReadonlyArray<infer U> ? Array<SnakeKeys<U>> : T extends object ? { [K in keyof T as K extends string ? SnakeCase<K> : K]: SnakeKeys<T[K]> } : T;
21
+ declare const toSnakeKeys: <T extends object>(o: T) => SnakeKeys<T>;
22
+ //#endregion
23
+ export { SnakeKeys, toSnakeKeys };
24
+ //# sourceMappingURL=toSnakeKeys.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toSnakeKeys.d.mts","names":[],"sources":["../../src/utils/toSnakeKeys.ts"],"mappings":";;KAIK,KAAA;;;;AAAK;AAAA;;KAkCL,SAAA,sDAGD,CAAA,wCACA,IAAA,SAAa,KAAA,MACR,OAAA,2BAAkC,SAAA,CAAU,IAAA,IAAQ,SAAA,CAAU,IAAA,eAC9D,IAAA,GAAO,SAAA,CAAU,IAAA,YACtB,CAAA;;;KAIC,SAAA,qBAA8B,SAAS,CAAC,CAAA;;;;;;;KAQjC,SAAA,MACV,CAAA,SAAU,aAAA,YACN,KAAA,CAAM,SAAA,CAAU,CAAA,KAChB,CAAA,gCAEgB,CAAA,IAAK,CAAA,kBAAmB,SAAA,CAAU,CAAA,IAAK,CAAA,GAAI,SAAA,CACrD,CAAA,CAAE,CAAA,OAGN,CAAA;AAAA,cAEK,WAAA,qBAAiC,CAAA,EAAG,CAAA,KAAI,SAAA,CAAU,CAAA"}
@@ -0,0 +1,15 @@
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 };
14
+
15
+ //# sourceMappingURL=toSnakeKeys.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toSnakeKeys.mjs","names":[],"sources":["../../src/utils/toSnakeKeys.ts"],"sourcesContent":["import { isObject } from \"./isObject.js\";\nimport { toSnakeCase } from \"./toSnakeCase.js\";\n\n/** The uppercase ASCII letters, for the camel→snake split. */\ntype Upper =\n | `A`\n | `B`\n | `C`\n | `D`\n | `E`\n | `F`\n | `G`\n | `H`\n | `I`\n | `J`\n | `K`\n | `L`\n | `M`\n | `N`\n | `O`\n | `P`\n | `Q`\n | `R`\n | `S`\n | `T`\n | `U`\n | `V`\n | `W`\n | `X`\n | `Y`\n | `Z`;\n\n/**\n * Walk a `camelCase` literal, inserting `_` before each uppercase letter and\n * lowercasing it — matching {@link toSnakeCase}'s runtime. `Started` tracks\n * whether we've emitted any character yet, so a leading capital (e.g. `Foo`)\n * doesn't get a leading underscore (→ `foo`, not `_foo`).\n */\ntype SnakeWalk<\n S extends string,\n Started extends boolean = false\n> = S extends `${infer Head}${infer Tail}`\n ? Head extends Upper\n ? `${Started extends true ? `_` : ``}${Lowercase<Head>}${SnakeWalk<Tail, true>}`\n : `${Head}${SnakeWalk<Tail, true>}`\n : S;\n\n/** Convert a `camelCase` string-literal type to `snake_case`. Self-contained;\n * mirrors {@link toSnakeCase} (the only transform we apply to API keys). */\ntype SnakeCase<S extends string> = SnakeWalk<S>;\n\n/**\n * Recursively snake-case the keys of an object/array type. Mirrors\n * {@link toSnakeKeys}'s runtime. Replaces type-fest's `SnakeCasedPropertiesDeep`\n * — narrower (no Set/tuple/options handling) because the only inputs are plain\n * nested Discord API JSON.\n */\nexport type SnakeKeys<T> =\n T extends ReadonlyArray<infer U>\n ? Array<SnakeKeys<U>>\n : T extends object\n ? {\n [K in keyof T as K extends string ? SnakeCase<K> : K]: SnakeKeys<\n T[K]\n >;\n }\n : T;\n\nexport const toSnakeKeys = <T extends object>(o: T): SnakeKeys<T> => {\n if (Array.isArray(o)) {\n return o.map(toSnakeKeys) as SnakeKeys<T>;\n } else if (isObject(o)) {\n return Object.entries(o).reduce((acc, [key, value]) => {\n // @ts-expect-error\n acc[toSnakeCase(key)] = toSnakeKeys(value);\n return acc;\n }, {}) as SnakeKeys<T>;\n }\n\n return o as SnakeKeys<T>;\n};\n"],"mappings":";;;AAoEA,MAAa,eAAiC,MAAuB;CACnE,IAAI,MAAM,QAAQ,CAAC,GACjB,OAAO,EAAE,IAAI,WAAW;MACnB,IAAI,SAAS,CAAC,GACnB,OAAO,OAAO,QAAQ,CAAC,EAAE,QAAQ,KAAK,CAAC,KAAK,WAAW;EAErD,IAAI,YAAY,GAAG,KAAK,YAAY,KAAK;EACzC,OAAO;CACT,GAAG,CAAC,CAAC;CAGP,OAAO;AACT"}