Some checks failed
Deploy MineGeo to Dokploy / deploy (push) Failing after 3m40s
77 lines
2.2 KiB
TypeScript
77 lines
2.2 KiB
TypeScript
import {
|
|
parseReleasePost,
|
|
RELEASE_NEWS_CHANNEL,
|
|
RELEASE_WEBHOOK_ID,
|
|
type ReleasePost,
|
|
} from "../shared/changelog";
|
|
|
|
export async function readChangelogFeed({
|
|
token,
|
|
channel = RELEASE_NEWS_CHANNEL,
|
|
webhookId = RELEASE_WEBHOOK_ID,
|
|
before,
|
|
request = fetch,
|
|
}: {
|
|
token: string;
|
|
channel?: string;
|
|
webhookId?: string;
|
|
before?: string;
|
|
request?: typeof fetch;
|
|
}) {
|
|
if (!/^\d{17,20}$/.test(channel) || (before && !/^\d{17,20}$/.test(before)))
|
|
throw new Error("Invalid news channel or cursor");
|
|
const url = new URL(
|
|
`https://discord.com/api/v10/channels/${channel}/messages`,
|
|
);
|
|
url.searchParams.set("limit", "100");
|
|
if (before) url.searchParams.set("before", before);
|
|
// Reading history only. No Discord write endpoint is used by this feature.
|
|
const response = await request(url.toString(), {
|
|
method: "GET",
|
|
headers: { Authorization: `Bot ${token}` },
|
|
next: { revalidate: 60 },
|
|
signal: AbortSignal.timeout(10_000),
|
|
redirect: "error",
|
|
});
|
|
if (!response.ok)
|
|
throw new Error(`News feed unavailable (${response.status})`);
|
|
const posts: ReleasePost[] = await response.json();
|
|
if (
|
|
!Array.isArray(posts) ||
|
|
posts.some(
|
|
(post) =>
|
|
typeof post.content !== "string" ||
|
|
post.channel_id !== channel ||
|
|
!/^\d{17,20}$/.test(post.id),
|
|
)
|
|
)
|
|
throw new Error("Invalid news response");
|
|
if (
|
|
posts.some((post) => post.webhook_id === webhookId) &&
|
|
posts
|
|
.filter((post) => post.webhook_id === webhookId)
|
|
.every((post) => !post.content.trim())
|
|
)
|
|
throw new Error(
|
|
"Release text is unavailable; check Discord Message Content access",
|
|
);
|
|
const entries = posts
|
|
.flatMap((post) => {
|
|
const entry = parseReleasePost(post, webhookId);
|
|
return entry ? [entry] : [];
|
|
})
|
|
.sort(
|
|
(a, b) =>
|
|
b.publishedAt.localeCompare(a.publishedAt) ||
|
|
(BigInt(a.id) > BigInt(b.id) ? -1 : 1),
|
|
);
|
|
const oldest = posts.reduce<string | undefined>(
|
|
(id, post) => (!id || BigInt(post.id) < BigInt(id) ? post.id : id),
|
|
undefined,
|
|
);
|
|
return {
|
|
entries,
|
|
before: posts.length === 100 && oldest !== before ? oldest : undefined,
|
|
};
|
|
}
|