mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 04:55:42 +09:00
fix(guild): import all template channel types, fetch on desktop (#3473)
This commit is contained in:
1 parent
00249f9b4d
commit
99be186fa1
50 files changed
+2008
-111
No files matched your search
@@ -0,0 +1,38 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
export const DESKTOP_OTHER_PLATFORM_TEMPLATE_CHANNELS = Object.freeze({
|
||||
fetch: 'desktop-other-platform-template:fetch',
|
||||
} as const);
|
||||
|
||||
const OTHER_PLATFORM_TEMPLATE_CODE_PATTERN = /^[A-Za-z0-9]{1,64}$/;
|
||||
|
||||
export function isOtherPlatformTemplateCode(value: unknown): value is string {
|
||||
return typeof value === 'string' && OTHER_PLATFORM_TEMPLATE_CODE_PATTERN.test(value);
|
||||
}
|
||||
|
||||
export const OtherPlatformTemplateFetchFailure = Object.freeze({
|
||||
INVALID_CODE: 'invalid_code',
|
||||
NOT_FOUND: 'not_found',
|
||||
RATE_LIMITED: 'rate_limited',
|
||||
NETWORK: 'network',
|
||||
INVALID_RESPONSE: 'invalid_response',
|
||||
} as const);
|
||||
|
||||
export type OtherPlatformTemplateFetchFailure =
|
||||
(typeof OtherPlatformTemplateFetchFailure)[keyof typeof OtherPlatformTemplateFetchFailure];
|
||||
|
||||
export interface OtherPlatformTemplateFetchSuccess {
|
||||
readonly ok: true;
|
||||
readonly template: Readonly<Record<string, unknown>>;
|
||||
}
|
||||
|
||||
export interface OtherPlatformTemplateFetchError {
|
||||
readonly ok: false;
|
||||
readonly failure: OtherPlatformTemplateFetchFailure;
|
||||
}
|
||||
|
||||
export type OtherPlatformTemplateFetchResult = OtherPlatformTemplateFetchSuccess | OtherPlatformTemplateFetchError;
|
||||
|
||||
export interface OtherPlatformTemplateAPI {
|
||||
fetch: (code: string) => Promise<OtherPlatformTemplateFetchResult>;
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
import {
|
||||
CHANNEL_RATE_LIMIT_PER_USER_MAX,
|
||||
CHANNEL_RATE_LIMIT_PER_USER_MIN,
|
||||
CHANNEL_TOPIC_MAX_LENGTH,
|
||||
VOICE_CHANNEL_CONNECTION_LIMIT_MAX,
|
||||
VOICE_CHANNEL_CONNECTION_LIMIT_MIN,
|
||||
VOICE_CHANNEL_USER_LIMIT_MIN,
|
||||
@@ -13,13 +12,8 @@ import {z} from 'zod';
|
||||
|
||||
const TEMPLATE_NAME_MAX_LENGTH = 100;
|
||||
const TEMPLATE_TOPIC_MAX_LENGTH = 4096;
|
||||
|
||||
function clipTopic(value: string): string {
|
||||
if (value.length <= CHANNEL_TOPIC_MAX_LENGTH) return value;
|
||||
const last = value.charCodeAt(CHANNEL_TOPIC_MAX_LENGTH - 1);
|
||||
const end = last >= 0xd800 && last <= 0xdbff ? CHANNEL_TOPIC_MAX_LENGTH - 1 : CHANNEL_TOPIC_MAX_LENGTH;
|
||||
return value.slice(0, end);
|
||||
}
|
||||
const TEMPLATE_FORUM_TAGS_MAX = 100;
|
||||
const TEMPLATE_EMOJI_NAME_MAX_LENGTH = 64;
|
||||
|
||||
const TemplateEntityId = z
|
||||
.union([
|
||||
@@ -42,6 +36,17 @@ const TemplateOverwriteType = z
|
||||
})
|
||||
.pipe(z.number())
|
||||
.describe('The type of overwrite (0/role = role, 1/member = member)');
|
||||
const TemplateEmojiReference = z.union([z.string().max(64), z.number().int().nonnegative()]);
|
||||
const TemplateForumTag = z.object({
|
||||
name: z.string().max(TEMPLATE_NAME_MAX_LENGTH).describe('The name of the tag'),
|
||||
moderated: z.boolean().nullish().describe('Whether only moderators can apply the tag'),
|
||||
emoji_id: TemplateEmojiReference.nullish().describe('A custom emoji reference, ignored on import'),
|
||||
emoji_name: z.string().max(TEMPLATE_EMOJI_NAME_MAX_LENGTH).nullish().describe('The unicode emoji of the tag'),
|
||||
});
|
||||
const TemplateReactionEmoji = z.object({
|
||||
emoji_id: TemplateEmojiReference.nullish().describe('A custom emoji reference, ignored on import'),
|
||||
emoji_name: z.string().max(TEMPLATE_EMOJI_NAME_MAX_LENGTH).nullish().describe('The unicode emoji'),
|
||||
});
|
||||
const TemplatePermissionOverwrite = z.object({
|
||||
id: TemplateEntityId.describe('The ID of the role or user for this overwrite'),
|
||||
type: TemplateOverwriteType,
|
||||
@@ -51,7 +56,11 @@ const TemplatePermissionOverwrite = z.object({
|
||||
|
||||
export const TemplateChannel = z.object({
|
||||
id: TemplateEntityId.describe('The template-local channel ID'),
|
||||
type: z.number().describe('The channel type (0 = text, 2 = voice, 4 = category)'),
|
||||
type: z
|
||||
.number()
|
||||
.describe(
|
||||
'The channel type (0 = text, 2 = voice, 4 = category, 5 = announcement, 13 = stage, 15 = forum, 16 = media)',
|
||||
),
|
||||
name: z
|
||||
.string()
|
||||
.max(TEMPLATE_NAME_MAX_LENGTH)
|
||||
@@ -61,9 +70,8 @@ export const TemplateChannel = z.object({
|
||||
topic: z
|
||||
.string()
|
||||
.max(TEMPLATE_TOPIC_MAX_LENGTH)
|
||||
.transform(clipTopic)
|
||||
.nullish()
|
||||
.describe('The channel topic, shortened to the Fluxer channel topic limit'),
|
||||
.describe('The channel topic or forum guidelines, shortened to the limit for the channel type'),
|
||||
position: Int32Type.describe('The position of the channel'),
|
||||
parent_id: TemplateEntityId.nullish().describe('The template-local ID of the parent category'),
|
||||
bitrate: z.number().int().nonnegative().nullish().describe('The bitrate for voice channels'),
|
||||
@@ -80,18 +88,38 @@ export const TemplateChannel = z.object({
|
||||
.max(VOICE_CHANNEL_CONNECTION_LIMIT_MAX)
|
||||
.nullish()
|
||||
.describe('The per-user voice connection limit for voice channels'),
|
||||
nsfw: z.boolean().optional().describe('Whether the channel is NSFW'),
|
||||
nsfw: z.boolean().nullish().describe('Whether the channel is NSFW'),
|
||||
rate_limit_per_user: z
|
||||
.number()
|
||||
.int()
|
||||
.min(CHANNEL_RATE_LIMIT_PER_USER_MIN)
|
||||
.max(CHANNEL_RATE_LIMIT_PER_USER_MAX)
|
||||
.optional()
|
||||
.nullish()
|
||||
.describe('Slowmode rate limit in seconds'),
|
||||
permission_overwrites: z
|
||||
.array(TemplatePermissionOverwrite)
|
||||
.optional()
|
||||
.nullish()
|
||||
.describe('Permission overwrites for this channel'),
|
||||
available_tags: z
|
||||
.array(TemplateForumTag)
|
||||
.max(TEMPLATE_FORUM_TAGS_MAX)
|
||||
.nullish()
|
||||
.describe('Tags for forum and media channels'),
|
||||
default_reaction_emoji: TemplateReactionEmoji.nullish().describe('Default reaction for forum and media posts'),
|
||||
default_sort_order: z.number().int().nullish().describe('Default post sort order for forum and media channels'),
|
||||
default_forum_layout: z.number().int().nullish().describe('Default layout for forum channels'),
|
||||
default_tag_setting: z.string().max(32).nullish().describe('How posts are filtered by several tags'),
|
||||
default_thread_rate_limit_per_user: z
|
||||
.number()
|
||||
.int()
|
||||
.nullish()
|
||||
.describe('Slowmode in seconds copied onto new threads'),
|
||||
default_auto_archive_duration: z
|
||||
.number()
|
||||
.int()
|
||||
.nullish()
|
||||
.describe('Default auto archive duration in minutes for new threads'),
|
||||
flags: z.number().int().nullish().describe('Channel flags'),
|
||||
});
|
||||
|
||||
export type TemplateChannel = z.infer<typeof TemplateChannel>;
|
||||
|
||||
Reference in new issue
Block a user