

























@@ -0,0 +1,121 @@
1+export class CredentialPayloadValidationError extends Error {
2+code: string;
3+httpStatus: number;
4+5+constructor(httpStatus: number, code: string, message: string) {
6+super(message);
7+this.name = "CredentialPayloadValidationError";
8+this.httpStatus = httpStatus;
9+this.code = code;
10+}
11+}
12+13+type PayloadValidationFailureFactory = (httpStatus: number, code: string, message: string) => Error;
14+15+const DISCORD_SNOWFLAKE_RE = /^\d{17,20}$/u;
16+const TELEGRAM_CHAT_ID_RE = /^-?\d+$/u;
17+18+function createCredentialPayloadValidationError(httpStatus: number, code: string, message: string) {
19+return new CredentialPayloadValidationError(httpStatus, code, message);
20+}
21+22+function throwPayloadError(createFailure: PayloadValidationFailureFactory, message: string): never {
23+throw createFailure(400, "INVALID_PAYLOAD", message);
24+}
25+26+function requirePayloadString(
27+payload: Record<string, unknown>,
28+key: string,
29+kind: string,
30+createFailure: PayloadValidationFailureFactory,
31+): string {
32+const raw = payload[key];
33+if (typeof raw !== "string") {
34+throwPayloadError(
35+createFailure,
36+`Credential payload for kind "${kind}" must include "${key}" as a string.`,
37+);
38+}
39+const value = raw.trim();
40+if (!value) {
41+throwPayloadError(
42+createFailure,
43+`Credential payload for kind "${kind}" must include a non-empty "${key}" value.`,
44+);
45+}
46+return value;
47+}
48+49+function requireDiscordSnowflakePayloadString(
50+payload: Record<string, unknown>,
51+key: string,
52+createFailure: PayloadValidationFailureFactory,
53+) {
54+const value = requirePayloadString(payload, key, "discord", createFailure);
55+if (!DISCORD_SNOWFLAKE_RE.test(value)) {
56+throwPayloadError(
57+createFailure,
58+`Credential payload for kind "discord" must include "${key}" as a Discord snowflake string.`,
59+);
60+}
61+return value;
62+}
63+64+function normalizeTelegramCredentialPayload(
65+payload: Record<string, unknown>,
66+createFailure: PayloadValidationFailureFactory,
67+) {
68+const groupId = requirePayloadString(payload, "groupId", "telegram", createFailure);
69+if (!TELEGRAM_CHAT_ID_RE.test(groupId)) {
70+throwPayloadError(
71+createFailure,
72+'Credential payload for kind "telegram" must include a numeric "groupId" string.',
73+);
74+}
75+76+const driverToken = requirePayloadString(payload, "driverToken", "telegram", createFailure);
77+const sutToken = requirePayloadString(payload, "sutToken", "telegram", createFailure);
78+79+return {
80+ groupId,
81+ driverToken,
82+ sutToken,
83+} satisfies Record<string, unknown>;
84+}
85+86+function normalizeDiscordCredentialPayload(
87+payload: Record<string, unknown>,
88+createFailure: PayloadValidationFailureFactory,
89+) {
90+const guildId = requireDiscordSnowflakePayloadString(payload, "guildId", createFailure);
91+const channelId = requireDiscordSnowflakePayloadString(payload, "channelId", createFailure);
92+const sutApplicationId = requireDiscordSnowflakePayloadString(
93+payload,
94+"sutApplicationId",
95+createFailure,
96+);
97+const driverBotToken = requirePayloadString(payload, "driverBotToken", "discord", createFailure);
98+const sutBotToken = requirePayloadString(payload, "sutBotToken", "discord", createFailure);
99+100+return {
101+ guildId,
102+ channelId,
103+ driverBotToken,
104+ sutBotToken,
105+ sutApplicationId,
106+} satisfies Record<string, unknown>;
107+}
108+109+export function normalizeCredentialPayloadForKind(
110+kind: string,
111+payload: Record<string, unknown>,
112+createFailure: PayloadValidationFailureFactory = createCredentialPayloadValidationError,
113+) {
114+if (kind === "telegram") {
115+return normalizeTelegramCredentialPayload(payload, createFailure);
116+}
117+if (kind === "discord") {
118+return normalizeDiscordCredentialPayload(payload, createFailure);
119+}
120+return payload;
121+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。