@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.
- package/CHANGELOG.md +423 -0
- package/README.md +52 -0
- package/dist/index.d.mts +23 -0
- package/dist/index.mjs +23 -0
- package/dist/requests/DiscordSession.d.mts +72 -0
- package/dist/requests/DiscordSession.d.mts.map +1 -0
- package/dist/requests/DiscordSession.mjs +262 -0
- package/dist/requests/DiscordSession.mjs.map +1 -0
- package/dist/requests/addParams.d.mts +16 -0
- package/dist/requests/addParams.d.mts.map +1 -0
- package/dist/requests/addParams.mjs +26 -0
- package/dist/requests/addParams.mjs.map +1 -0
- package/dist/requests/buildURL.d.mts +8 -0
- package/dist/requests/buildURL.d.mts.map +1 -0
- package/dist/requests/buildURL.mjs +9 -0
- package/dist/requests/buildURL.mjs.map +1 -0
- package/dist/requests/getAsset.d.mts +8 -0
- package/dist/requests/getAsset.d.mts.map +1 -0
- package/dist/requests/getAsset.mjs +8 -0
- package/dist/requests/getAsset.mjs.map +1 -0
- package/dist/requests/index.d.mts +9 -0
- package/dist/requests/index.mjs +9 -0
- package/dist/requests/methods.d.mts +64 -0
- package/dist/requests/methods.d.mts.map +1 -0
- package/dist/requests/methods.mjs +12 -0
- package/dist/requests/methods.mjs.map +1 -0
- package/dist/requests/request.d.mts +28 -0
- package/dist/requests/request.d.mts.map +1 -0
- package/dist/requests/request.mjs +31 -0
- package/dist/requests/request.mjs.map +1 -0
- package/dist/requests/toProcedure.d.mts +41 -0
- package/dist/requests/toProcedure.d.mts.map +1 -0
- package/dist/requests/toProcedure.mjs +29 -0
- package/dist/requests/toProcedure.mjs.map +1 -0
- package/dist/requests/toQuery.d.mts +37 -0
- package/dist/requests/toQuery.d.mts.map +1 -0
- package/dist/requests/toQuery.mjs +10 -0
- package/dist/requests/toQuery.mjs.map +1 -0
- package/dist/requests/toValidated.d.mts +17 -0
- package/dist/requests/toValidated.d.mts.map +1 -0
- package/dist/requests/toValidated.mjs +27 -0
- package/dist/requests/toValidated.mjs.map +1 -0
- package/dist/requests/{verifyKey.d.ts → verifyKey.d.mts} +5 -1
- package/dist/requests/verifyKey.d.mts.map +1 -0
- package/dist/requests/verifyKey.mjs +64 -0
- package/dist/requests/verifyKey.mjs.map +1 -0
- package/dist/utils/isBetween.d.mts +5 -0
- package/dist/utils/isBetween.d.mts.map +1 -0
- package/dist/utils/isBetween.mjs +6 -0
- package/dist/utils/isBetween.mjs.map +1 -0
- package/dist/utils/{isNonNullable.js → isNonNullable.d.mts} +6 -2
- package/dist/utils/isNonNullable.d.mts.map +1 -0
- package/dist/utils/isNonNullable.mjs +24 -0
- package/dist/utils/isNonNullable.mjs.map +1 -0
- package/dist/utils/isNumericString.d.mts +5 -0
- package/dist/utils/isNumericString.d.mts.map +1 -0
- package/dist/utils/isNumericString.mjs +6 -0
- package/dist/utils/isNumericString.mjs.map +1 -0
- package/dist/utils/isObject.d.mts +5 -0
- package/dist/utils/isObject.d.mts.map +1 -0
- package/dist/utils/isObject.mjs +6 -0
- package/dist/utils/isObject.mjs.map +1 -0
- package/dist/utils/sleep.d.mts +8 -0
- package/dist/utils/sleep.d.mts.map +1 -0
- package/dist/utils/sleep.mjs +9 -0
- package/dist/utils/sleep.mjs.map +1 -0
- package/dist/utils/toCamelCase.d.mts +5 -0
- package/dist/utils/toCamelCase.d.mts.map +1 -0
- package/dist/utils/toCamelCase.mjs +6 -0
- package/dist/utils/toCamelCase.mjs.map +1 -0
- package/dist/utils/toCamelKeys.d.mts +20 -0
- package/dist/utils/toCamelKeys.d.mts.map +1 -0
- package/dist/utils/toCamelKeys.mjs +15 -0
- package/dist/utils/toCamelKeys.mjs.map +1 -0
- package/dist/utils/toSnakeCase.d.mts +5 -0
- package/dist/utils/toSnakeCase.d.mts.map +1 -0
- package/dist/utils/toSnakeCase.mjs +6 -0
- package/dist/utils/toSnakeCase.mjs.map +1 -0
- package/dist/utils/toSnakeKeys.d.mts +24 -0
- package/dist/utils/toSnakeKeys.d.mts.map +1 -0
- package/dist/utils/toSnakeKeys.mjs +15 -0
- package/dist/utils/toSnakeKeys.mjs.map +1 -0
- package/dist/validations/asDigits.d.mts +13 -0
- package/dist/validations/asDigits.d.mts.map +1 -0
- package/dist/validations/asDigits.mjs +12 -0
- package/dist/validations/asDigits.mjs.map +1 -0
- package/dist/validations/asInteger.d.mts +13 -0
- package/dist/validations/asInteger.d.mts.map +1 -0
- package/dist/validations/asInteger.mjs +12 -0
- package/dist/validations/asInteger.mjs.map +1 -0
- package/dist/validations/bitfield.d.mts +24 -0
- package/dist/validations/bitfield.d.mts.map +1 -0
- package/dist/validations/bitfield.mjs +22 -0
- package/dist/validations/bitfield.mjs.map +1 -0
- package/dist/validations/boundedArray.d.mts +14 -0
- package/dist/validations/boundedArray.d.mts.map +1 -0
- package/dist/validations/boundedArray.mjs +11 -0
- package/dist/validations/boundedArray.mjs.map +1 -0
- package/dist/validations/boundedInteger.d.mts +14 -0
- package/dist/validations/boundedInteger.d.mts.map +1 -0
- package/dist/validations/boundedInteger.mjs +11 -0
- package/dist/validations/boundedInteger.mjs.map +1 -0
- package/dist/validations/boundedString.d.mts +15 -0
- package/dist/validations/boundedString.d.mts.map +1 -0
- package/dist/validations/boundedString.mjs +12 -0
- package/dist/validations/boundedString.mjs.map +1 -0
- package/dist/validations/datauri.d.mts +25 -0
- package/dist/validations/datauri.d.mts.map +1 -0
- package/dist/validations/datauri.mjs +19 -0
- package/dist/validations/datauri.mjs.map +1 -0
- package/dist/validations/fileUpload.d.mts +130 -0
- package/dist/validations/fileUpload.d.mts.map +1 -0
- package/dist/validations/fileUpload.mjs +116 -0
- package/dist/validations/fileUpload.mjs.map +1 -0
- package/dist/validations/hasMimeType.d.mts +17 -0
- package/dist/validations/hasMimeType.d.mts.map +1 -0
- package/dist/validations/hasMimeType.mjs +18 -0
- package/dist/validations/hasMimeType.mjs.map +1 -0
- package/dist/validations/hasSize.d.mts +11 -0
- package/dist/validations/hasSize.d.mts.map +1 -0
- package/dist/validations/hasSize.mjs +14 -0
- package/dist/validations/hasSize.mjs.map +1 -0
- package/dist/validations/index.d.mts +15 -0
- package/dist/validations/index.mjs +15 -0
- package/dist/validations/schema.d.mts +103 -0
- package/dist/validations/schema.d.mts.map +1 -0
- package/dist/validations/schema.mjs +111 -0
- package/dist/validations/schema.mjs.map +1 -0
- package/dist/validations/{snowflake.d.ts → snowflake.d.mts} +10 -7
- package/dist/validations/snowflake.d.mts.map +1 -0
- package/dist/validations/snowflake.mjs +30 -0
- package/dist/validations/snowflake.mjs.map +1 -0
- package/dist/validations/timestamp.d.mts +8 -0
- package/dist/validations/timestamp.d.mts.map +1 -0
- package/dist/validations/timestamp.mjs +8 -0
- package/dist/validations/timestamp.mjs.map +1 -0
- package/dist/validations/toBlob.d.mts +8 -0
- package/dist/validations/toBlob.d.mts.map +1 -0
- package/dist/validations/toBlob.mjs +19 -0
- package/dist/validations/toBlob.mjs.map +1 -0
- package/dist/validations/url.d.mts +7 -0
- package/dist/validations/url.d.mts.map +1 -0
- package/dist/validations/url.mjs +7 -0
- package/dist/validations/url.mjs.map +1 -0
- package/package.json +10 -23
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -3
- package/dist/index.js.map +0 -1
- package/dist/requests/DiscordSession.d.ts +0 -25
- package/dist/requests/DiscordSession.js +0 -255
- package/dist/requests/DiscordSession.js.map +0 -1
- package/dist/requests/addParams.d.ts +0 -2
- package/dist/requests/addParams.js +0 -11
- package/dist/requests/addParams.js.map +0 -1
- package/dist/requests/buildURL.d.ts +0 -2
- package/dist/requests/buildURL.js +0 -4
- package/dist/requests/buildURL.js.map +0 -1
- package/dist/requests/getAsset.d.ts +0 -2
- package/dist/requests/getAsset.js +0 -3
- package/dist/requests/getAsset.js.map +0 -1
- package/dist/requests/index.d.ts +0 -8
- package/dist/requests/index.js +0 -9
- package/dist/requests/index.js.map +0 -1
- package/dist/requests/methods.d.ts +0 -13
- package/dist/requests/methods.js +0 -8
- package/dist/requests/methods.js.map +0 -1
- package/dist/requests/request.d.ts +0 -2
- package/dist/requests/request.js +0 -30
- package/dist/requests/request.js.map +0 -1
- package/dist/requests/toProcedure.d.ts +0 -31
- package/dist/requests/toProcedure.js +0 -36
- package/dist/requests/toProcedure.js.map +0 -1
- package/dist/requests/toQuery.d.ts +0 -28
- package/dist/requests/toQuery.js +0 -9
- package/dist/requests/toQuery.js.map +0 -1
- package/dist/requests/toValidated.d.ts +0 -13
- package/dist/requests/toValidated.js +0 -29
- package/dist/requests/toValidated.js.map +0 -1
- package/dist/requests/verifyKey.js +0 -91
- package/dist/requests/verifyKey.js.map +0 -1
- package/dist/utils/isBetween.d.ts +0 -1
- package/dist/utils/isBetween.js +0 -2
- package/dist/utils/isBetween.js.map +0 -1
- package/dist/utils/isNonNullable.d.ts +0 -20
- package/dist/utils/isNonNullable.js.map +0 -1
- package/dist/utils/isNumericString.d.ts +0 -1
- package/dist/utils/isNumericString.js +0 -2
- package/dist/utils/isNumericString.js.map +0 -1
- package/dist/utils/isObject.d.ts +0 -1
- package/dist/utils/isObject.js +0 -2
- package/dist/utils/isObject.js.map +0 -1
- package/dist/utils/sleep.d.ts +0 -4
- package/dist/utils/sleep.js +0 -5
- package/dist/utils/sleep.js.map +0 -1
- package/dist/utils/toCamelCase.d.ts +0 -1
- package/dist/utils/toCamelCase.js +0 -2
- package/dist/utils/toCamelCase.js.map +0 -1
- package/dist/utils/toCamelKeys.d.ts +0 -2
- package/dist/utils/toCamelKeys.js +0 -16
- package/dist/utils/toCamelKeys.js.map +0 -1
- package/dist/utils/toSnakeCase.d.ts +0 -1
- package/dist/utils/toSnakeCase.js +0 -4
- package/dist/utils/toSnakeCase.js.map +0 -1
- package/dist/utils/toSnakeKeys.d.ts +0 -2
- package/dist/utils/toSnakeKeys.js +0 -16
- package/dist/utils/toSnakeKeys.js.map +0 -1
- package/dist/validations/asDigits.d.ts +0 -6
- package/dist/validations/asDigits.js +0 -6
- package/dist/validations/asDigits.js.map +0 -1
- package/dist/validations/asInteger.d.ts +0 -6
- package/dist/validations/asInteger.js +0 -6
- package/dist/validations/asInteger.js.map +0 -1
- package/dist/validations/bitfield.d.ts +0 -17
- package/dist/validations/bitfield.js +0 -37
- package/dist/validations/bitfield.js.map +0 -1
- package/dist/validations/boundedArray.d.ts +0 -6
- package/dist/validations/boundedArray.js +0 -8
- package/dist/validations/boundedArray.js.map +0 -1
- package/dist/validations/boundedInteger.d.ts +0 -6
- package/dist/validations/boundedInteger.js +0 -8
- package/dist/validations/boundedInteger.js.map +0 -1
- package/dist/validations/boundedString.d.ts +0 -6
- package/dist/validations/boundedString.js +0 -8
- package/dist/validations/boundedString.js.map +0 -1
- package/dist/validations/datauri.d.ts +0 -20
- package/dist/validations/datauri.js +0 -20
- package/dist/validations/datauri.js.map +0 -1
- package/dist/validations/hasMimeType.d.ts +0 -10
- package/dist/validations/hasMimeType.js +0 -18
- package/dist/validations/hasMimeType.js.map +0 -1
- package/dist/validations/hasSize.d.ts +0 -5
- package/dist/validations/hasSize.js +0 -13
- package/dist/validations/hasSize.js.map +0 -1
- package/dist/validations/index.d.ts +0 -12
- package/dist/validations/index.js +0 -13
- package/dist/validations/index.js.map +0 -1
- package/dist/validations/snowflake.js +0 -39
- package/dist/validations/snowflake.js.map +0 -1
- package/dist/validations/timestamp.d.ts +0 -3
- package/dist/validations/timestamp.js +0 -4
- package/dist/validations/timestamp.js.map +0 -1
- package/dist/validations/toBlob.d.ts +0 -4
- package/dist/validations/toBlob.js +0 -19
- package/dist/validations/toBlob.js.map +0 -1
- package/dist/validations/url.d.ts +0 -2
- package/dist/validations/url.js +0 -3
- 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 @@
|
|
|
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
|
-
|
|
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 @@
|
|
|
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 @@
|
|
|
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
|
-
|
|
20
|
-
//#
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"isNumericString.d.mts","names":[],"sources":["../../src/utils/isNumericString.ts"],"mappings":";cAAa,eAAA,GAAmB,GAAA,cAAe,GAAG"}
|
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"sleep.d.mts","names":[],"sources":["../../src/utils/sleep.ts"],"mappings":";;AAGA;;cAAa,KAAA,GAAe,EAAA,aAAa,OAAO"}
|
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"toCamelCase.d.mts","names":[],"sources":["../../src/utils/toCamelCase.ts"],"mappings":";cAAa,WAAA,GAAe,GAAW"}
|
|
@@ -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 @@
|
|
|
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"}
|