refactor progress
This commit is contained in:
114
packages/schema/src/domains/guild/GuildAuditLogSchemas.tsx
Normal file
114
packages/schema/src/domains/guild/GuildAuditLogSchemas.tsx
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {UserPartialResponse} from '@fluxer/schema/src/domains/user/UserResponseSchemas';
|
||||
import {AuditLogActionTypeSchema} from '@fluxer/schema/src/primitives/AuditLogValidators';
|
||||
import {
|
||||
coerceNumberFromString,
|
||||
Int32Type,
|
||||
SnowflakeStringType,
|
||||
SnowflakeType,
|
||||
} from '@fluxer/schema/src/primitives/SchemaPrimitives';
|
||||
import {WebhookTypeSchema} from '@fluxer/schema/src/primitives/WebhookValidators';
|
||||
import {z} from 'zod';
|
||||
|
||||
const PermissionsDiffSchema = z.object({
|
||||
added: z.array(z.string()),
|
||||
removed: z.array(z.string()),
|
||||
});
|
||||
|
||||
const AuditLogChangeValueSchema = z.union([
|
||||
z.string(),
|
||||
z.number(),
|
||||
z.boolean(),
|
||||
z.array(z.string()),
|
||||
z.array(z.number()),
|
||||
PermissionsDiffSchema,
|
||||
z.null(),
|
||||
]);
|
||||
|
||||
export const AuditLogChangeSchema = z.object({
|
||||
key: z.string().describe('The field that changed'),
|
||||
old_value: AuditLogChangeValueSchema.optional().describe('Value before the change'),
|
||||
new_value: AuditLogChangeValueSchema.optional().describe('Value after the change'),
|
||||
});
|
||||
|
||||
export type AuditLogChange = z.infer<typeof AuditLogChangeSchema>;
|
||||
|
||||
const AuditLogOptionsSchema = z.object({
|
||||
channel_id: z.string().optional().describe('Channel ID for relevant actions'),
|
||||
count: z.number().optional().describe('Count of items affected'),
|
||||
delete_member_days: z.string().optional().describe('Number of days of messages to delete on member ban'),
|
||||
id: z.string().optional().describe('ID of the affected entity'),
|
||||
integration_type: z.number().optional().describe('Type of integration'),
|
||||
message_id: z.string().optional().describe('Message ID for relevant actions'),
|
||||
members_removed: z.number().optional().describe('Number of members removed'),
|
||||
role_name: z.string().optional().describe('Name of the role'),
|
||||
type: z.number().optional().describe('Type identifier'),
|
||||
inviter_id: z.string().optional().describe('ID of the user who created the invite'),
|
||||
max_age: z.number().optional().describe('Maximum age of the invite in seconds'),
|
||||
max_uses: z.number().optional().describe('Maximum number of uses for the invite'),
|
||||
temporary: z.boolean().optional().describe('Whether the invite grants temporary membership'),
|
||||
uses: z.number().optional().describe('Number of times the invite has been used'),
|
||||
});
|
||||
|
||||
export const GuildAuditLogEntryResponse = z.object({
|
||||
id: SnowflakeStringType.describe('The unique identifier for this audit log entry'),
|
||||
action_type: AuditLogActionTypeSchema,
|
||||
user_id: SnowflakeStringType.nullish().describe('The user ID of the user who performed the action'),
|
||||
target_id: z.string().nullish().describe('The ID of the affected entity (user, channel, role, invite code, etc.)'),
|
||||
reason: z.string().optional().describe('The reason provided for the action'),
|
||||
options: AuditLogOptionsSchema.optional().describe('Additional options depending on action type'),
|
||||
changes: z.array(AuditLogChangeSchema).optional().describe('Changes made to the target'),
|
||||
});
|
||||
|
||||
export type GuildAuditLogEntryResponse = z.infer<typeof GuildAuditLogEntryResponse>;
|
||||
|
||||
export const AuditLogWebhookResponse = z.object({
|
||||
id: SnowflakeStringType.describe('The unique identifier for this webhook'),
|
||||
type: WebhookTypeSchema,
|
||||
guild_id: SnowflakeStringType.nullish().describe('The guild ID this webhook belongs to'),
|
||||
channel_id: SnowflakeStringType.nullish().describe('The channel ID this webhook posts to'),
|
||||
name: z.string().describe('The name of the webhook'),
|
||||
avatar_hash: z.string().nullish().describe('The hash of the webhook avatar'),
|
||||
});
|
||||
|
||||
export type AuditLogWebhookResponse = z.infer<typeof AuditLogWebhookResponse>;
|
||||
|
||||
export const GuildAuditLogListResponse = z.object({
|
||||
audit_log_entries: z.array(GuildAuditLogEntryResponse).max(100).describe('Array of audit log entries'),
|
||||
users: z.array(UserPartialResponse).max(100).describe('Users referenced in the audit log entries'),
|
||||
webhooks: z.array(AuditLogWebhookResponse).max(100).describe('Webhooks referenced in the audit log entries'),
|
||||
});
|
||||
|
||||
export type GuildAuditLogListResponse = z.infer<typeof GuildAuditLogListResponse>;
|
||||
|
||||
export const GuildAuditLogListQuery = z.object({
|
||||
limit: coerceNumberFromString(Int32Type.max(100))
|
||||
.optional()
|
||||
.describe('Maximum number of audit log entries to return (1-100)'),
|
||||
before: SnowflakeType.optional().describe('Get entries before this audit log entry ID'),
|
||||
after: SnowflakeType.optional().describe('Get entries after this audit log entry ID'),
|
||||
user_id: SnowflakeType.optional().describe('Filter entries by the user who performed the action'),
|
||||
action_type: coerceNumberFromString(AuditLogActionTypeSchema)
|
||||
.optional()
|
||||
.describe('Filter entries by the type of action'),
|
||||
});
|
||||
|
||||
export type GuildAuditLogListQuery = z.infer<typeof GuildAuditLogListQuery>;
|
||||
128
packages/schema/src/domains/guild/GuildDiscoverySchemas.tsx
Normal file
128
packages/schema/src/domains/guild/GuildDiscoverySchemas.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
DISCOVERY_DESCRIPTION_MAX_LENGTH,
|
||||
DISCOVERY_DESCRIPTION_MIN_LENGTH,
|
||||
} from '@fluxer/constants/src/DiscoveryConstants';
|
||||
import {SnowflakeStringType} from '@fluxer/schema/src/primitives/SchemaPrimitives';
|
||||
import {z} from 'zod';
|
||||
|
||||
export const DiscoveryApplicationRequest = z.object({
|
||||
description: z
|
||||
.string()
|
||||
.min(DISCOVERY_DESCRIPTION_MIN_LENGTH)
|
||||
.max(DISCOVERY_DESCRIPTION_MAX_LENGTH)
|
||||
.describe('Description for discovery listing'),
|
||||
category_id: z.number().int().min(0).max(8).describe('Discovery category ID'),
|
||||
});
|
||||
|
||||
export type DiscoveryApplicationRequest = z.infer<typeof DiscoveryApplicationRequest>;
|
||||
|
||||
export const DiscoveryApplicationPatchRequest = z.object({
|
||||
description: z
|
||||
.string()
|
||||
.min(DISCOVERY_DESCRIPTION_MIN_LENGTH)
|
||||
.max(DISCOVERY_DESCRIPTION_MAX_LENGTH)
|
||||
.optional()
|
||||
.describe('Updated description for discovery listing'),
|
||||
category_id: z.number().int().min(0).max(8).optional().describe('Updated discovery category ID'),
|
||||
});
|
||||
|
||||
export type DiscoveryApplicationPatchRequest = z.infer<typeof DiscoveryApplicationPatchRequest>;
|
||||
|
||||
export const DiscoverySearchQuery = z.object({
|
||||
query: z.string().max(100).optional().describe('Search query'),
|
||||
category: z.coerce.number().int().min(0).max(8).optional().describe('Filter by category'),
|
||||
sort_by: z.enum(['member_count', 'online_count', 'relevance']).optional().describe('Sort order'),
|
||||
limit: z.coerce.number().int().min(1).max(48).optional().default(24).describe('Number of results to return'),
|
||||
offset: z.coerce.number().int().min(0).optional().default(0).describe('Pagination offset'),
|
||||
});
|
||||
|
||||
export type DiscoverySearchQuery = z.infer<typeof DiscoverySearchQuery>;
|
||||
|
||||
export const DiscoveryGuildResponse = z.object({
|
||||
id: SnowflakeStringType.describe('Guild ID'),
|
||||
name: z.string().describe('Guild name'),
|
||||
icon: z.string().nullish().describe('Guild icon hash'),
|
||||
description: z.string().nullish().describe('Discovery description'),
|
||||
category_id: z.number().describe('Discovery category ID'),
|
||||
member_count: z.number().describe('Approximate member count'),
|
||||
online_count: z.number().describe('Approximate online member count'),
|
||||
features: z.array(z.string()).describe('Guild feature flags'),
|
||||
verification_level: z.number().describe('Verification level'),
|
||||
});
|
||||
|
||||
export type DiscoveryGuildResponse = z.infer<typeof DiscoveryGuildResponse>;
|
||||
|
||||
export const DiscoveryGuildListResponse = z.object({
|
||||
guilds: z.array(DiscoveryGuildResponse).describe('Discovery guild results'),
|
||||
total: z.number().describe('Total number of matching guilds'),
|
||||
});
|
||||
|
||||
export type DiscoveryGuildListResponse = z.infer<typeof DiscoveryGuildListResponse>;
|
||||
|
||||
export const DiscoveryApplicationResponse = z.object({
|
||||
guild_id: SnowflakeStringType.describe('Guild ID'),
|
||||
status: z.string().describe('Application status'),
|
||||
description: z.string().describe('Discovery description'),
|
||||
category_id: z.number().describe('Discovery category ID'),
|
||||
applied_at: z.string().describe('Application timestamp'),
|
||||
reviewed_at: z.string().nullish().describe('Review timestamp'),
|
||||
review_reason: z.string().nullish().describe('Review reason'),
|
||||
});
|
||||
|
||||
export type DiscoveryApplicationResponse = z.infer<typeof DiscoveryApplicationResponse>;
|
||||
|
||||
export const DiscoveryCategoryResponse = z.object({
|
||||
id: z.number().describe('Category ID'),
|
||||
name: z.string().describe('Category display name'),
|
||||
});
|
||||
|
||||
export type DiscoveryCategoryResponse = z.infer<typeof DiscoveryCategoryResponse>;
|
||||
|
||||
export const DiscoveryCategoryListResponse = z.array(DiscoveryCategoryResponse);
|
||||
|
||||
export type DiscoveryCategoryListResponse = z.infer<typeof DiscoveryCategoryListResponse>;
|
||||
|
||||
export const DiscoveryAdminReviewRequest = z.object({
|
||||
reason: z.string().max(500).optional().describe('Review reason'),
|
||||
});
|
||||
|
||||
export type DiscoveryAdminReviewRequest = z.infer<typeof DiscoveryAdminReviewRequest>;
|
||||
|
||||
export const DiscoveryAdminRejectRequest = z.object({
|
||||
reason: z.string().min(1).max(500).describe('Rejection reason'),
|
||||
});
|
||||
|
||||
export type DiscoveryAdminRejectRequest = z.infer<typeof DiscoveryAdminRejectRequest>;
|
||||
|
||||
export const DiscoveryAdminRemoveRequest = z.object({
|
||||
reason: z.string().min(1).max(500).describe('Removal reason'),
|
||||
});
|
||||
|
||||
export type DiscoveryAdminRemoveRequest = z.infer<typeof DiscoveryAdminRemoveRequest>;
|
||||
|
||||
export const DiscoveryAdminListQuery = z.object({
|
||||
status: z.enum(['pending', 'approved', 'rejected', 'removed']).optional().default('pending'),
|
||||
limit: z.coerce.number().int().min(1).max(100).optional().default(25),
|
||||
cursor: z.string().optional(),
|
||||
});
|
||||
|
||||
export type DiscoveryAdminListQuery = z.infer<typeof DiscoveryAdminListQuery>;
|
||||
122
packages/schema/src/domains/guild/GuildEmojiSchemas.tsx
Normal file
122
packages/schema/src/domains/guild/GuildEmojiSchemas.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {type UserPartial, UserPartialResponse} from '@fluxer/schema/src/domains/user/UserResponseSchemas';
|
||||
import {SnowflakeStringType} from '@fluxer/schema/src/primitives/SchemaPrimitives';
|
||||
import {z} from 'zod';
|
||||
|
||||
export const GuildEmojiResponse = z.object({
|
||||
id: SnowflakeStringType.describe('The unique identifier for this emoji'),
|
||||
name: z.string().describe('The name of the emoji'),
|
||||
animated: z.boolean().describe('Whether this emoji is animated'),
|
||||
});
|
||||
|
||||
export type GuildEmojiResponse = z.infer<typeof GuildEmojiResponse>;
|
||||
|
||||
export const GuildEmojiWithUserResponse = z.object({
|
||||
id: SnowflakeStringType.describe('The unique identifier for this emoji'),
|
||||
name: z.string().describe('The name of the emoji'),
|
||||
animated: z.boolean().describe('Whether this emoji is animated'),
|
||||
user: z.lazy(() => UserPartialResponse).describe('The user who uploaded this emoji'),
|
||||
});
|
||||
|
||||
export type GuildEmojiWithUserResponse = z.infer<typeof GuildEmojiWithUserResponse>;
|
||||
|
||||
export const GuildStickerResponse = z.object({
|
||||
id: SnowflakeStringType.describe('The unique identifier for this sticker'),
|
||||
name: z.string().describe('The name of the sticker'),
|
||||
description: z.string().describe('The description of the sticker'),
|
||||
tags: z.array(z.string()).max(100).describe('Autocomplete/suggestion tags for the sticker'),
|
||||
animated: z.boolean().describe('Whether this sticker is animated'),
|
||||
});
|
||||
|
||||
export type GuildStickerResponse = z.infer<typeof GuildStickerResponse>;
|
||||
|
||||
export const GuildStickerWithUserResponse = z.object({
|
||||
id: SnowflakeStringType.describe('The unique identifier for this sticker'),
|
||||
name: z.string().describe('The name of the sticker'),
|
||||
description: z.string().describe('The description of the sticker'),
|
||||
tags: z.array(z.string()).max(100).describe('Autocomplete/suggestion tags for the sticker'),
|
||||
animated: z.boolean().describe('Whether this sticker is animated'),
|
||||
user: z.lazy(() => UserPartialResponse).describe('The user who uploaded this sticker'),
|
||||
});
|
||||
|
||||
export type GuildStickerWithUserResponse = z.infer<typeof GuildStickerWithUserResponse>;
|
||||
|
||||
export const GuildEmojiBulkCreateResponse = z.object({
|
||||
success: z.array(GuildEmojiResponse).max(500).describe('Successfully created emojis'),
|
||||
failed: z
|
||||
.array(
|
||||
z.object({
|
||||
name: z.string().describe('The name of the emoji that failed to create'),
|
||||
error: z.string().describe('The error message explaining why the emoji failed to create'),
|
||||
}),
|
||||
)
|
||||
.max(500)
|
||||
.describe('Emojis that failed to create'),
|
||||
});
|
||||
|
||||
export type GuildEmojiBulkCreateResponse = z.infer<typeof GuildEmojiBulkCreateResponse>;
|
||||
|
||||
export const GuildStickerBulkCreateResponse = z.object({
|
||||
success: z.array(GuildStickerResponse).max(500).describe('Successfully created stickers'),
|
||||
failed: z
|
||||
.array(
|
||||
z.object({
|
||||
name: z.string().describe('The name of the sticker that failed to create'),
|
||||
error: z.string().describe('The error message explaining why the sticker failed to create'),
|
||||
}),
|
||||
)
|
||||
.max(500)
|
||||
.describe('Stickers that failed to create'),
|
||||
});
|
||||
|
||||
export type GuildStickerBulkCreateResponse = z.infer<typeof GuildStickerBulkCreateResponse>;
|
||||
|
||||
export const GuildEmojiWithUserListResponse = z.array(GuildEmojiWithUserResponse);
|
||||
|
||||
export type GuildEmojiWithUserListResponse = z.infer<typeof GuildEmojiWithUserListResponse>;
|
||||
|
||||
export const GuildStickerWithUserListResponse = z.array(GuildStickerWithUserResponse);
|
||||
|
||||
export type GuildStickerWithUserListResponse = z.infer<typeof GuildStickerWithUserListResponse>;
|
||||
|
||||
export interface GuildEmoji {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly animated: boolean;
|
||||
readonly user?: UserPartial;
|
||||
}
|
||||
|
||||
export interface GuildEmojiWithUser extends GuildEmoji {
|
||||
readonly user: UserPartial;
|
||||
}
|
||||
|
||||
export interface GuildSticker {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly description: string;
|
||||
readonly tags: Array<string>;
|
||||
readonly animated: boolean;
|
||||
readonly user?: UserPartial;
|
||||
}
|
||||
|
||||
export interface GuildStickerWithUser extends GuildSticker {
|
||||
readonly user: UserPartial;
|
||||
}
|
||||
77
packages/schema/src/domains/guild/GuildMemberSchemas.tsx
Normal file
77
packages/schema/src/domains/guild/GuildMemberSchemas.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {GuildMemberProfileFlags, GuildMemberProfileFlagsDescriptions} from '@fluxer/constants/src/GuildConstants';
|
||||
import {UserPartialResponse} from '@fluxer/schema/src/domains/user/UserResponseSchemas';
|
||||
import {createBitflagInt32Type, Int32Type, SnowflakeStringType} from '@fluxer/schema/src/primitives/SchemaPrimitives';
|
||||
import {z} from 'zod';
|
||||
|
||||
export const GuildMemberResponse = z.object({
|
||||
user: z.lazy(() => UserPartialResponse).describe('The user this guild member represents'),
|
||||
nick: z.string().nullish().describe('The nickname of the member in this guild'),
|
||||
avatar: z.string().nullish().describe('The hash of the member guild-specific avatar'),
|
||||
banner: z.string().nullish().describe('The hash of the member guild-specific banner'),
|
||||
accent_color: Int32Type.nullish().describe('The accent colour of the member guild profile as an integer'),
|
||||
roles: z.array(z.string()).max(250).describe('Array of role IDs the member has'),
|
||||
joined_at: z.iso.datetime().describe('ISO8601 timestamp of when the user joined the guild'),
|
||||
mute: z.boolean().describe('Whether the member is muted in voice channels'),
|
||||
deaf: z.boolean().describe('Whether the member is deafened in voice channels'),
|
||||
communication_disabled_until: z.iso
|
||||
.datetime()
|
||||
.nullish()
|
||||
.describe('ISO8601 timestamp until which the member is timed out'),
|
||||
profile_flags: createBitflagInt32Type(
|
||||
GuildMemberProfileFlags,
|
||||
GuildMemberProfileFlagsDescriptions,
|
||||
'Member profile flags',
|
||||
'GuildMemberProfileFlags',
|
||||
).nullish(),
|
||||
});
|
||||
|
||||
export type GuildMemberResponse = z.infer<typeof GuildMemberResponse>;
|
||||
|
||||
export const GuildBanResponse = z.object({
|
||||
user: z.lazy(() => UserPartialResponse).describe('The banned user'),
|
||||
reason: z.string().nullish().describe('The reason for the ban'),
|
||||
moderator_id: SnowflakeStringType.describe('The ID of the moderator who issued the ban'),
|
||||
banned_at: z.iso.datetime().describe('ISO8601 timestamp of when the ban was issued'),
|
||||
expires_at: z.iso.datetime().nullish().describe('ISO8601 timestamp of when the ban expires (null if permanent)'),
|
||||
});
|
||||
|
||||
export type GuildBanResponse = z.infer<typeof GuildBanResponse>;
|
||||
|
||||
export const GuildMemberListResponse = z.array(GuildMemberResponse).max(1000).describe('A list of guild members');
|
||||
export type GuildMemberListResponse = z.infer<typeof GuildMemberListResponse>;
|
||||
|
||||
export const GuildBanListResponse = z.array(GuildBanResponse).max(1000).describe('A list of guild bans');
|
||||
export type GuildBanListResponse = z.infer<typeof GuildBanListResponse>;
|
||||
|
||||
export interface GuildMemberData {
|
||||
readonly user: UserPartialResponse;
|
||||
readonly nick?: string | null;
|
||||
readonly avatar?: string | null;
|
||||
readonly banner?: string | null;
|
||||
readonly accent_color?: number | null;
|
||||
readonly roles: ReadonlyArray<string>;
|
||||
readonly joined_at: string;
|
||||
readonly mute?: boolean;
|
||||
readonly deaf?: boolean;
|
||||
readonly communication_disabled_until?: string | null;
|
||||
readonly profile_flags?: number | null;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {JoinSourceTypeSchema} from '@fluxer/schema/src/primitives/GuildValidators';
|
||||
import {z} from 'zod';
|
||||
|
||||
export const GuildMemberSearchRequest = z.object({
|
||||
query: z.string().max(100).optional().describe('Text to search for in usernames, global names, and nicknames'),
|
||||
limit: z.number().int().min(1).max(100).default(25).describe('Maximum number of results to return'),
|
||||
offset: z.number().int().min(0).default(0).describe('Number of results to skip for pagination'),
|
||||
role_ids: z
|
||||
.array(z.string())
|
||||
.max(10)
|
||||
.optional()
|
||||
.describe('Filter by role IDs (member must have all specified roles)'),
|
||||
joined_at_gte: z.number().int().optional().describe('Filter members who joined at or after this unix timestamp'),
|
||||
joined_at_lte: z.number().int().optional().describe('Filter members who joined at or before this unix timestamp'),
|
||||
join_source_type: z.array(z.number().int()).max(10).optional().describe('Filter by join source types'),
|
||||
source_invite_code: z.array(z.string()).max(10).optional().describe('Filter by invite codes used to join'),
|
||||
is_bot: z.boolean().optional().describe('Filter by bot status'),
|
||||
user_created_at_gte: z
|
||||
.number()
|
||||
.int()
|
||||
.optional()
|
||||
.describe('Filter members whose account was created at or after this unix timestamp'),
|
||||
user_created_at_lte: z
|
||||
.number()
|
||||
.int()
|
||||
.optional()
|
||||
.describe('Filter members whose account was created at or before this unix timestamp'),
|
||||
sort_by: z.enum(['joinedAt', 'relevance']).optional().describe('Sort results by field'),
|
||||
sort_order: z.enum(['asc', 'desc']).optional().describe('Sort order'),
|
||||
});
|
||||
|
||||
export type GuildMemberSearchRequest = z.infer<typeof GuildMemberSearchRequest>;
|
||||
|
||||
export const GuildMemberSearchSupplemental = z.object({
|
||||
join_source_type: JoinSourceTypeSchema.nullish().describe('How the member joined'),
|
||||
source_invite_code: z.string().nullable().describe('Invite code used to join'),
|
||||
inviter_id: z.string().nullable().describe('User ID of the member who sent the invite'),
|
||||
});
|
||||
|
||||
export type GuildMemberSearchSupplemental = z.infer<typeof GuildMemberSearchSupplemental>;
|
||||
|
||||
export const GuildMemberSearchResult = z.object({
|
||||
id: z.string().describe('Composite ID (guildId:userId)'),
|
||||
guild_id: z.string().describe('Guild ID'),
|
||||
user_id: z.string().describe('User ID'),
|
||||
username: z.string().describe('Username'),
|
||||
discriminator: z.string().describe('Zero-padded 4-digit discriminator'),
|
||||
global_name: z.string().nullable().describe('Global display name'),
|
||||
nickname: z.string().nullable().describe('Guild nickname'),
|
||||
role_ids: z.array(z.string()).describe('Role IDs'),
|
||||
joined_at: z.number().describe('Unix timestamp of when the member joined'),
|
||||
supplemental: GuildMemberSearchSupplemental.describe(
|
||||
'Supplemental members-search-only metadata that is not part of the base guild member payload',
|
||||
),
|
||||
is_bot: z.boolean().describe('Whether the user is a bot'),
|
||||
});
|
||||
|
||||
export type GuildMemberSearchResult = z.infer<typeof GuildMemberSearchResult>;
|
||||
|
||||
export const GuildMemberSearchResponse = z.object({
|
||||
guild_id: z.string().describe('Guild ID'),
|
||||
members: z.array(GuildMemberSearchResult).describe('Matching members'),
|
||||
page_result_count: z.number().int().describe('Number of results in this page'),
|
||||
total_result_count: z.number().int().describe('Total number of matching results'),
|
||||
indexing: z.boolean().describe('Whether the guild members are currently being indexed'),
|
||||
});
|
||||
|
||||
export type GuildMemberSearchResponse = z.infer<typeof GuildMemberSearchResponse>;
|
||||
335
packages/schema/src/domains/guild/GuildRequestSchemas.tsx
Normal file
335
packages/schema/src/domains/guild/GuildRequestSchemas.tsx
Normal file
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
GuildMemberProfileFlags,
|
||||
GuildMemberProfileFlagsDescriptions,
|
||||
SystemChannelFlags,
|
||||
SystemChannelFlagsDescriptions,
|
||||
} from '@fluxer/constants/src/GuildConstants';
|
||||
import {
|
||||
AVATAR_MAX_SIZE,
|
||||
EMOJI_MAX_SIZE,
|
||||
STICKER_MAX_SIZE,
|
||||
VALID_TEMP_BAN_DURATIONS,
|
||||
} from '@fluxer/constants/src/LimitConstants';
|
||||
import {SudoVerificationSchema} from '@fluxer/schema/src/domains/auth/AuthSchemas';
|
||||
import {VanityURLCodeType} from '@fluxer/schema/src/primitives/ChannelValidators';
|
||||
import {createBase64StringType} from '@fluxer/schema/src/primitives/FileValidators';
|
||||
import {
|
||||
DefaultMessageNotificationsSchema,
|
||||
GuildExplicitContentFilterSchema,
|
||||
GuildMFALevelSchema,
|
||||
GuildVerificationLevelSchema,
|
||||
NSFWLevelSchema,
|
||||
SplashCardAlignmentSchema,
|
||||
} from '@fluxer/schema/src/primitives/GuildValidators';
|
||||
import {QueryBooleanType} from '@fluxer/schema/src/primitives/QueryValidators';
|
||||
import {
|
||||
ColorType,
|
||||
createBitflagInt32Type,
|
||||
createStringType,
|
||||
SnowflakeType,
|
||||
UnsignedInt64Type,
|
||||
withFieldDescription,
|
||||
} from '@fluxer/schema/src/primitives/SchemaPrimitives';
|
||||
import {PasswordType} from '@fluxer/schema/src/primitives/UserValidators';
|
||||
import {z} from 'zod';
|
||||
|
||||
export const GuildCreateRequest = z.object({
|
||||
name: createStringType(1, 100).describe('The name of the guild (1-100 characters)'),
|
||||
icon: createBase64StringType(1, Math.ceil(AVATAR_MAX_SIZE * (4 / 3)))
|
||||
.nullish()
|
||||
.describe('Base64-encoded image data for the guild icon'),
|
||||
empty_features: z.boolean().optional().describe('Whether to create the guild without default features'),
|
||||
});
|
||||
|
||||
export type GuildCreateRequest = z.infer<typeof GuildCreateRequest>;
|
||||
|
||||
export const GuildUpdateRequest = z
|
||||
.object({
|
||||
name: createStringType(1, 100).describe('The name of the guild (1-100 characters)'),
|
||||
icon: createBase64StringType(1, Math.ceil(AVATAR_MAX_SIZE * (4 / 3)))
|
||||
.nullish()
|
||||
.describe('Base64-encoded image data for the guild icon'),
|
||||
system_channel_id: SnowflakeType.nullish().describe('The ID of the channel where system messages are sent'),
|
||||
system_channel_flags: createBitflagInt32Type(
|
||||
SystemChannelFlags,
|
||||
SystemChannelFlagsDescriptions,
|
||||
'Bitfield of system channel flags controlling which messages are suppressed',
|
||||
'SystemChannelFlags',
|
||||
),
|
||||
afk_channel_id: SnowflakeType.nullish().describe('The ID of the AFK voice channel'),
|
||||
afk_timeout: z
|
||||
.number()
|
||||
.int()
|
||||
.min(60)
|
||||
.max(3600)
|
||||
.describe('AFK timeout in seconds (60-3600) before moving users to the AFK channel'),
|
||||
default_message_notifications: withFieldDescription(
|
||||
DefaultMessageNotificationsSchema,
|
||||
'Default notification level for new members',
|
||||
),
|
||||
verification_level: withFieldDescription(
|
||||
GuildVerificationLevelSchema,
|
||||
'Required verification level for members to participate',
|
||||
),
|
||||
mfa_level: withFieldDescription(GuildMFALevelSchema, 'Required MFA level for moderation actions'),
|
||||
nsfw_level: withFieldDescription(NSFWLevelSchema, 'The NSFW level of the guild'),
|
||||
explicit_content_filter: withFieldDescription(
|
||||
GuildExplicitContentFilterSchema,
|
||||
'Level of content filtering for explicit media',
|
||||
),
|
||||
banner: createBase64StringType(1, Math.ceil(AVATAR_MAX_SIZE * (4 / 3)))
|
||||
.nullish()
|
||||
.describe('Base64-encoded image data for the guild banner'),
|
||||
splash: createBase64StringType(1, Math.ceil(AVATAR_MAX_SIZE * (4 / 3)))
|
||||
.nullish()
|
||||
.describe('Base64-encoded image data for the guild splash screen'),
|
||||
embed_splash: createBase64StringType(1, Math.ceil(AVATAR_MAX_SIZE * (4 / 3)))
|
||||
.nullish()
|
||||
.describe('Base64-encoded image data for the embedded invite splash'),
|
||||
splash_card_alignment: SplashCardAlignmentSchema.optional().describe(
|
||||
'Alignment of the splash card (center, left, or right)',
|
||||
),
|
||||
features: z.array(z.string()).describe('Array of guild feature strings'),
|
||||
message_history_cutoff: z.iso
|
||||
.datetime()
|
||||
.nullish()
|
||||
.describe(
|
||||
'ISO8601 timestamp controlling how far back members without Read Message History can access messages. Set to null to disable historical access.',
|
||||
),
|
||||
})
|
||||
.partial()
|
||||
.merge(SudoVerificationSchema);
|
||||
|
||||
export type GuildUpdateRequest = z.infer<typeof GuildUpdateRequest>;
|
||||
|
||||
export const GuildMemberUpdateRequest = z.object({
|
||||
nick: createStringType(1, 32).nullish().describe('The nickname to set for the member (1-32 characters)'),
|
||||
roles: z
|
||||
.array(SnowflakeType)
|
||||
.max(100, 'Maximum 100 roles allowed')
|
||||
.optional()
|
||||
.transform((ids) => (ids ? new Set(ids) : undefined))
|
||||
.describe('Array of role IDs to assign to the member (max 100)'),
|
||||
avatar: createBase64StringType(1, Math.ceil(AVATAR_MAX_SIZE * (4 / 3)))
|
||||
.nullish()
|
||||
.describe('Base64-encoded image data for the member guild avatar'),
|
||||
banner: createBase64StringType(1, Math.ceil(AVATAR_MAX_SIZE * (4 / 3)))
|
||||
.nullish()
|
||||
.describe('Base64-encoded image data for the member guild banner'),
|
||||
bio: createStringType(1, 320).nullish().describe('The member guild profile bio (1-320 characters)'),
|
||||
pronouns: createStringType(1, 40).nullish().describe('The member guild profile pronouns (1-40 characters)'),
|
||||
accent_color: ColorType.nullish().describe('The accent color for the member guild profile as an integer'),
|
||||
profile_flags: createBitflagInt32Type(
|
||||
GuildMemberProfileFlags,
|
||||
GuildMemberProfileFlagsDescriptions,
|
||||
'Bitfield of profile flags for the member',
|
||||
'GuildMemberProfileFlags',
|
||||
).nullish(),
|
||||
mute: z.boolean().optional().describe('Whether the member is muted in voice channels'),
|
||||
deaf: z.boolean().optional().describe('Whether the member is deafened in voice channels'),
|
||||
communication_disabled_until: z.iso
|
||||
.datetime()
|
||||
.nullish()
|
||||
.describe('ISO8601 timestamp until which the member is timed out'),
|
||||
timeout_reason: createStringType(1, 512)
|
||||
.nullish()
|
||||
.describe('The reason for timing out the member (1-512 characters)'),
|
||||
channel_id: SnowflakeType.nullish().describe('The voice channel ID to move the member to'),
|
||||
connection_id: createStringType(1, 32).nullish().describe('The voice connection ID for the member'),
|
||||
});
|
||||
|
||||
export type GuildMemberUpdateRequest = z.infer<typeof GuildMemberUpdateRequest>;
|
||||
|
||||
export const MyGuildMemberUpdateRequest = GuildMemberUpdateRequest.omit({roles: true}).partial();
|
||||
|
||||
export type MyGuildMemberUpdateRequest = z.infer<typeof MyGuildMemberUpdateRequest>;
|
||||
|
||||
export const GuildRoleCreateRequest = z.object({
|
||||
name: createStringType(1, 100).describe('The name of the role (1-100 characters)'),
|
||||
color: ColorType.default(0x000000).describe('The color of the role as an integer (default: 0)'),
|
||||
permissions: UnsignedInt64Type.optional().describe('fluxer:UnsignedInt64Type The permissions bitfield for the role'),
|
||||
});
|
||||
|
||||
export type GuildRoleCreateRequest = z.infer<typeof GuildRoleCreateRequest>;
|
||||
|
||||
export const GuildRoleUpdateRequest = z.object({
|
||||
name: createStringType(1, 100).optional().describe('The name of the role (1-100 characters)'),
|
||||
color: ColorType.optional().describe('The color of the role as an integer'),
|
||||
permissions: UnsignedInt64Type.optional().describe('fluxer:UnsignedInt64Type The permissions bitfield for the role'),
|
||||
hoist: z.boolean().optional().describe('Whether the role should be displayed separately in the member list'),
|
||||
hoist_position: z.number().int().nullish().describe('The position of the role in the hoisted member list'),
|
||||
mentionable: z.boolean().optional().describe('Whether the role can be mentioned by anyone'),
|
||||
});
|
||||
|
||||
export type GuildRoleUpdateRequest = z.infer<typeof GuildRoleUpdateRequest>;
|
||||
|
||||
export const GuildEmojiCreateRequest = z.object({
|
||||
name: createStringType(2, 32)
|
||||
.refine((value) => /^[a-zA-Z0-9_]+$/.test(value), 'Emoji name can only contain letters, numbers, and underscores')
|
||||
.describe('The name of the emoji (2-32 characters, alphanumeric and underscores only)'),
|
||||
image: createBase64StringType(1, Math.ceil(EMOJI_MAX_SIZE * (4 / 3))).describe(
|
||||
'Base64-encoded image data for the emoji',
|
||||
),
|
||||
});
|
||||
|
||||
export type GuildEmojiCreateRequest = z.infer<typeof GuildEmojiCreateRequest>;
|
||||
|
||||
export const GuildEmojiUpdateRequest = GuildEmojiCreateRequest.pick({name: true});
|
||||
|
||||
export type GuildEmojiUpdateRequest = z.infer<typeof GuildEmojiUpdateRequest>;
|
||||
|
||||
export const GuildEmojiBulkCreateRequest = z.object({
|
||||
emojis: z
|
||||
.array(GuildEmojiCreateRequest)
|
||||
.min(1, 'At least one emoji is required')
|
||||
.max(50, 'Maximum 50 emojis per batch')
|
||||
.describe('Array of emoji objects to create (1-50 emojis per batch)'),
|
||||
});
|
||||
|
||||
export type GuildEmojiBulkCreateRequest = z.infer<typeof GuildEmojiBulkCreateRequest>;
|
||||
|
||||
export const GuildStickerCreateRequest = z.object({
|
||||
name: createStringType(2, 30).describe('The name of the sticker (2-30 characters)'),
|
||||
description: createStringType(1, 500).nullish().describe('Description of the sticker (1-500 characters)'),
|
||||
tags: z
|
||||
.array(createStringType(1, 30))
|
||||
.min(0)
|
||||
.max(10)
|
||||
.optional()
|
||||
.default([])
|
||||
.describe('Array of autocomplete/suggestion tags (max 10 tags, each 1-30 characters)'),
|
||||
image: createBase64StringType(1, Math.ceil(STICKER_MAX_SIZE * (4 / 3))).describe(
|
||||
'Base64-encoded image data for the sticker',
|
||||
),
|
||||
});
|
||||
|
||||
export type GuildStickerCreateRequest = z.infer<typeof GuildStickerCreateRequest>;
|
||||
|
||||
export const GuildStickerUpdateRequest = GuildStickerCreateRequest.pick({
|
||||
name: true,
|
||||
description: true,
|
||||
tags: true,
|
||||
});
|
||||
|
||||
export type GuildStickerUpdateRequest = z.infer<typeof GuildStickerUpdateRequest>;
|
||||
|
||||
export const GuildStickerBulkCreateRequest = z.object({
|
||||
stickers: z
|
||||
.array(GuildStickerCreateRequest)
|
||||
.min(1, 'At least one sticker is required')
|
||||
.max(50, 'Maximum 50 stickers per batch')
|
||||
.describe('Array of sticker objects to create (1-50 stickers per batch)'),
|
||||
});
|
||||
|
||||
export type GuildStickerBulkCreateRequest = z.infer<typeof GuildStickerBulkCreateRequest>;
|
||||
|
||||
export const GuildTransferOwnershipRequest = z.object({
|
||||
new_owner_id: SnowflakeType.describe('The ID of the user to transfer ownership to'),
|
||||
password: PasswordType.optional().describe('The current owner password for verification'),
|
||||
});
|
||||
|
||||
export type GuildTransferOwnershipRequest = z.infer<typeof GuildTransferOwnershipRequest>;
|
||||
|
||||
export const GuildBanCreateRequest = z.object({
|
||||
delete_message_days: z
|
||||
.number()
|
||||
.int()
|
||||
.min(0)
|
||||
.max(7)
|
||||
.default(0)
|
||||
.describe('Number of days of messages to delete from the banned user (0-7)'),
|
||||
reason: createStringType(0, 512).nullish().describe('The reason for the ban (max 512 characters)'),
|
||||
ban_duration_seconds: z
|
||||
.number()
|
||||
.int()
|
||||
.refine((val) => val === 0 || VALID_TEMP_BAN_DURATIONS.has(val), {
|
||||
message: `Ban duration must be 0 (permanent) or one of the valid durations: ${Array.from(VALID_TEMP_BAN_DURATIONS).join(', ')} seconds`,
|
||||
})
|
||||
.optional()
|
||||
.describe('Duration of the ban in seconds (0 for permanent, or a valid temporary duration)'),
|
||||
});
|
||||
|
||||
export type GuildBanCreateRequest = z.infer<typeof GuildBanCreateRequest>;
|
||||
|
||||
export const GuildListQuery = z.object({
|
||||
before: SnowflakeType.optional().describe('Get guilds before this guild ID'),
|
||||
after: SnowflakeType.optional().describe('Get guilds after this guild ID'),
|
||||
limit: z.coerce.number().int().min(1).max(200).default(200).describe('Maximum number of guilds to return (1-200)'),
|
||||
with_counts: QueryBooleanType.describe('Include approximate member and presence counts'),
|
||||
});
|
||||
|
||||
export type GuildListQuery = z.infer<typeof GuildListQuery>;
|
||||
|
||||
export const GuildDeleteRequest = z
|
||||
.object({
|
||||
password: PasswordType.optional().describe('The owner password for verification'),
|
||||
})
|
||||
.merge(SudoVerificationSchema);
|
||||
|
||||
export type GuildDeleteRequest = z.infer<typeof GuildDeleteRequest>;
|
||||
|
||||
export const GuildVanityURLUpdateRequest = z.object({
|
||||
code: VanityURLCodeType.nullish().describe('The new vanity URL code (2-32 characters, alphanumeric and hyphens)'),
|
||||
});
|
||||
|
||||
export type GuildVanityURLUpdateRequest = z.infer<typeof GuildVanityURLUpdateRequest>;
|
||||
|
||||
export const GuildVanityURLUpdateResponse = z.object({
|
||||
code: createStringType(2, 32).describe('The new vanity URL code'),
|
||||
});
|
||||
|
||||
export type GuildVanityURLUpdateResponse = z.infer<typeof GuildVanityURLUpdateResponse>;
|
||||
|
||||
export const GuildRoleHoistPositionItem = z.object({
|
||||
id: SnowflakeType.describe('The ID of the role'),
|
||||
hoist_position: z.number().int().describe('The new hoist position for the role'),
|
||||
});
|
||||
|
||||
export type GuildRoleHoistPositionItem = z.infer<typeof GuildRoleHoistPositionItem>;
|
||||
|
||||
export const GuildRoleHoistPositionsRequest = z.array(GuildRoleHoistPositionItem);
|
||||
|
||||
export type GuildRoleHoistPositionsRequest = z.infer<typeof GuildRoleHoistPositionsRequest>;
|
||||
|
||||
export const GuildRolePositionItem = z.object({
|
||||
id: SnowflakeType.describe('The ID of the role'),
|
||||
position: z.number().int().optional().describe('The new position for the role'),
|
||||
});
|
||||
|
||||
export type GuildRolePositionItem = z.infer<typeof GuildRolePositionItem>;
|
||||
|
||||
export const GuildRolePositionsRequest = z.array(GuildRolePositionItem);
|
||||
|
||||
export type GuildRolePositionsRequest = z.infer<typeof GuildRolePositionsRequest>;
|
||||
|
||||
export const GuildMemberListQuery = z.object({
|
||||
limit: z.coerce
|
||||
.number()
|
||||
.int()
|
||||
.min(1)
|
||||
.max(1000)
|
||||
.default(1)
|
||||
.describe('Maximum number of members to return (1-1000, default 1)'),
|
||||
after: SnowflakeType.optional().describe('Get members after this user ID for pagination'),
|
||||
});
|
||||
|
||||
export type GuildMemberListQuery = z.infer<typeof GuildMemberListQuery>;
|
||||
218
packages/schema/src/domains/guild/GuildResponseSchemas.tsx
Normal file
218
packages/schema/src/domains/guild/GuildResponseSchemas.tsx
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type {GuildSplashCardAlignmentValue} from '@fluxer/constants/src/GuildConstants';
|
||||
import {
|
||||
GuildFeatures,
|
||||
GuildOperations,
|
||||
GuildOperationsDescriptions,
|
||||
SystemChannelFlags,
|
||||
SystemChannelFlagsDescriptions,
|
||||
} from '@fluxer/constants/src/GuildConstants';
|
||||
import {
|
||||
DefaultMessageNotificationsSchema,
|
||||
GuildExplicitContentFilterSchema,
|
||||
GuildMFALevelSchema,
|
||||
GuildVerificationLevelSchema,
|
||||
NSFWLevelSchema,
|
||||
SplashCardAlignmentSchema,
|
||||
} from '@fluxer/schema/src/primitives/GuildValidators';
|
||||
import {PermissionStringType} from '@fluxer/schema/src/primitives/PermissionValidators';
|
||||
import {
|
||||
createBitflagInt32Type,
|
||||
createFlexibleStringLiteralUnion,
|
||||
Int32Type,
|
||||
SnowflakeStringType,
|
||||
withFieldDescription,
|
||||
withOpenApiType,
|
||||
} from '@fluxer/schema/src/primitives/SchemaPrimitives';
|
||||
import {z} from 'zod';
|
||||
|
||||
function normalizeGuildFeatures(features: Array<string>): Array<string> {
|
||||
return Array.from(new Set(features)).sort((first, second) => first.localeCompare(second));
|
||||
}
|
||||
|
||||
export const GuildFeatureSchema = withOpenApiType(
|
||||
createFlexibleStringLiteralUnion(
|
||||
[
|
||||
[GuildFeatures.ANIMATED_ICON, 'ANIMATED_ICON', 'Guild can have an animated icon'],
|
||||
[GuildFeatures.ANIMATED_BANNER, 'ANIMATED_BANNER', 'Guild can have an animated banner'],
|
||||
[GuildFeatures.BANNER, 'BANNER', 'Guild can have a banner'],
|
||||
[GuildFeatures.DETACHED_BANNER, 'DETACHED_BANNER', 'Guild banner is detached from splash'],
|
||||
[GuildFeatures.INVITE_SPLASH, 'INVITE_SPLASH', 'Guild can have an invite splash'],
|
||||
[GuildFeatures.INVITES_DISABLED, 'INVITES_DISABLED', 'Guild has invites disabled'],
|
||||
[
|
||||
GuildFeatures.TEXT_CHANNEL_FLEXIBLE_NAMES,
|
||||
'TEXT_CHANNEL_FLEXIBLE_NAMES',
|
||||
'Guild allows flexible text channel names',
|
||||
],
|
||||
[GuildFeatures.MORE_EMOJI, 'MORE_EMOJI', 'Guild has increased emoji slots'],
|
||||
[GuildFeatures.MORE_STICKERS, 'MORE_STICKERS', 'Guild has increased sticker slots'],
|
||||
[GuildFeatures.UNLIMITED_EMOJI, 'UNLIMITED_EMOJI', 'Guild has unlimited emoji slots'],
|
||||
[GuildFeatures.UNLIMITED_STICKERS, 'UNLIMITED_STICKERS', 'Guild has unlimited sticker slots'],
|
||||
[GuildFeatures.EXPRESSION_PURGE_ALLOWED, 'EXPRESSION_PURGE_ALLOWED', 'Guild allows purging expressions'],
|
||||
[GuildFeatures.VANITY_URL, 'VANITY_URL', 'Guild can have a vanity URL'],
|
||||
[GuildFeatures.VERIFIED, 'VERIFIED', 'Guild is verified'],
|
||||
[GuildFeatures.VIP_VOICE, 'VIP_VOICE', 'Guild has VIP voice features'],
|
||||
[GuildFeatures.UNAVAILABLE_FOR_EVERYONE, 'UNAVAILABLE_FOR_EVERYONE', 'Guild is unavailable for everyone'],
|
||||
[
|
||||
GuildFeatures.UNAVAILABLE_FOR_EVERYONE_BUT_STAFF,
|
||||
'UNAVAILABLE_FOR_EVERYONE_BUT_STAFF',
|
||||
'Guild is unavailable except for staff',
|
||||
],
|
||||
[GuildFeatures.VISIONARY, 'VISIONARY', 'Guild is a visionary guild'],
|
||||
[GuildFeatures.OPERATOR, 'OPERATOR', 'Guild is an operator guild'],
|
||||
[GuildFeatures.LARGE_GUILD_OVERRIDE, 'LARGE_GUILD_OVERRIDE', 'Guild has large guild overrides enabled'],
|
||||
[GuildFeatures.VERY_LARGE_GUILD, 'VERY_LARGE_GUILD', 'Guild has increased member capacity enabled'],
|
||||
[GuildFeatures.MANAGED_MESSAGE_SCHEDULING, 'MT_MESSAGE_SCHEDULING', 'Guild has managed message scheduling'],
|
||||
[GuildFeatures.MANAGED_EXPRESSION_PACKS, 'MT_EXPRESSION_PACKS', 'Guild has managed expression packs'],
|
||||
],
|
||||
'A guild feature flag',
|
||||
),
|
||||
'GuildFeature',
|
||||
);
|
||||
|
||||
const GuildFeatureListSchema = z
|
||||
.array(GuildFeatureSchema)
|
||||
.max(100)
|
||||
.transform(normalizeGuildFeatures)
|
||||
.describe('Array of guild feature flags');
|
||||
|
||||
export const GuildResponse = z.object({
|
||||
id: SnowflakeStringType.describe('The unique identifier for this guild'),
|
||||
name: z.string().describe('The name of the guild'),
|
||||
icon: z.string().nullish().describe('The hash of the guild icon'),
|
||||
banner: z.string().nullish().describe('The hash of the guild banner'),
|
||||
banner_width: Int32Type.nullish().describe('The width of the guild banner in pixels'),
|
||||
banner_height: Int32Type.nullish().describe('The height of the guild banner in pixels'),
|
||||
splash: z.string().nullish().describe('The hash of the guild splash screen'),
|
||||
splash_width: Int32Type.nullish().describe('The width of the guild splash in pixels'),
|
||||
splash_height: Int32Type.nullish().describe('The height of the guild splash in pixels'),
|
||||
splash_card_alignment: SplashCardAlignmentSchema.describe('The alignment of the splash card'),
|
||||
embed_splash: z.string().nullish().describe('The hash of the embedded invite splash'),
|
||||
embed_splash_width: Int32Type.nullish().describe('The width of the embedded invite splash in pixels'),
|
||||
embed_splash_height: Int32Type.nullish().describe('The height of the embedded invite splash in pixels'),
|
||||
vanity_url_code: z.string().nullish().describe('The vanity URL code for the guild'),
|
||||
owner_id: SnowflakeStringType.describe('The ID of the guild owner'),
|
||||
system_channel_id: SnowflakeStringType.nullish().describe('The ID of the channel where system messages are sent'),
|
||||
system_channel_flags: createBitflagInt32Type(
|
||||
SystemChannelFlags,
|
||||
SystemChannelFlagsDescriptions,
|
||||
'System channel message flags',
|
||||
'SystemChannelFlags',
|
||||
),
|
||||
rules_channel_id: SnowflakeStringType.nullish().describe('The ID of the rules channel'),
|
||||
afk_channel_id: SnowflakeStringType.nullish().describe('The ID of the AFK voice channel'),
|
||||
afk_timeout: Int32Type.describe('AFK timeout in seconds before moving users to the AFK channel'),
|
||||
features: GuildFeatureListSchema,
|
||||
verification_level: withFieldDescription(
|
||||
GuildVerificationLevelSchema,
|
||||
'Required verification level for members to participate',
|
||||
),
|
||||
mfa_level: withFieldDescription(GuildMFALevelSchema, 'Required MFA level for moderation actions'),
|
||||
nsfw_level: withFieldDescription(NSFWLevelSchema, 'The NSFW level of the guild'),
|
||||
explicit_content_filter: withFieldDescription(
|
||||
GuildExplicitContentFilterSchema,
|
||||
'Level of content filtering for explicit media',
|
||||
),
|
||||
default_message_notifications: withFieldDescription(
|
||||
DefaultMessageNotificationsSchema,
|
||||
'Default notification level for new members',
|
||||
),
|
||||
disabled_operations: createBitflagInt32Type(
|
||||
GuildOperations,
|
||||
GuildOperationsDescriptions,
|
||||
'Bitfield of disabled operations in the guild',
|
||||
'GuildOperations',
|
||||
),
|
||||
message_history_cutoff: z.iso
|
||||
.datetime()
|
||||
.nullish()
|
||||
.describe(
|
||||
'ISO8601 timestamp controlling how far back members without Read Message History can access messages. When null, no historical access is allowed.',
|
||||
),
|
||||
permissions: PermissionStringType.describe(
|
||||
'fluxer:PermissionStringType The current user permissions in this guild',
|
||||
).nullish(),
|
||||
});
|
||||
|
||||
export type GuildResponse = z.infer<typeof GuildResponse>;
|
||||
|
||||
export const GuildPartialResponse = z.object({
|
||||
id: SnowflakeStringType.describe('The unique identifier for this guild'),
|
||||
name: z.string().describe('The name of the guild'),
|
||||
icon: z.string().nullish().describe('The hash of the guild icon'),
|
||||
banner: z.string().nullish().describe('The hash of the guild banner'),
|
||||
banner_width: Int32Type.nullish().describe('The width of the guild banner in pixels'),
|
||||
banner_height: Int32Type.nullish().describe('The height of the guild banner in pixels'),
|
||||
splash: z.string().nullish().describe('The hash of the guild splash screen'),
|
||||
splash_width: Int32Type.nullish().describe('The width of the guild splash in pixels'),
|
||||
splash_height: Int32Type.nullish().describe('The height of the guild splash in pixels'),
|
||||
splash_card_alignment: SplashCardAlignmentSchema.describe('The alignment of the splash card'),
|
||||
embed_splash: z.string().nullish().describe('The hash of the embedded invite splash'),
|
||||
embed_splash_width: Int32Type.nullish().describe('The width of the embedded invite splash in pixels'),
|
||||
embed_splash_height: Int32Type.nullish().describe('The height of the embedded invite splash in pixels'),
|
||||
features: GuildFeatureListSchema,
|
||||
});
|
||||
|
||||
export type GuildPartialResponse = z.infer<typeof GuildPartialResponse>;
|
||||
|
||||
export const GuildVanityURLResponse = z.object({
|
||||
code: z.string().nullish().describe('The vanity URL code for the guild'),
|
||||
uses: Int32Type.describe('The number of times this vanity URL has been used'),
|
||||
});
|
||||
|
||||
export type GuildVanityURLResponse = z.infer<typeof GuildVanityURLResponse>;
|
||||
|
||||
export const GuildListResponse = z.array(GuildResponse).max(200).describe('A list of guilds');
|
||||
export type GuildListResponse = z.infer<typeof GuildListResponse>;
|
||||
|
||||
export interface Guild {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly icon: string | null;
|
||||
readonly banner?: string | null;
|
||||
readonly banner_width?: number | null;
|
||||
readonly banner_height?: number | null;
|
||||
readonly splash?: string | null;
|
||||
readonly splash_width?: number | null;
|
||||
readonly splash_height?: number | null;
|
||||
readonly splash_card_alignment?: GuildSplashCardAlignmentValue;
|
||||
readonly embed_splash?: string | null;
|
||||
readonly embed_splash_width?: number | null;
|
||||
readonly embed_splash_height?: number | null;
|
||||
readonly vanity_url_code: string | null;
|
||||
readonly owner_id: string;
|
||||
readonly system_channel_id: string | null;
|
||||
readonly system_channel_flags?: number;
|
||||
readonly rules_channel_id?: string | null;
|
||||
readonly afk_channel_id?: string | null;
|
||||
readonly afk_timeout?: number;
|
||||
readonly features: ReadonlyArray<string>;
|
||||
readonly verification_level?: number;
|
||||
readonly mfa_level?: number;
|
||||
readonly nsfw_level?: number;
|
||||
readonly explicit_content_filter?: number;
|
||||
readonly default_message_notifications?: number;
|
||||
readonly disabled_operations?: number;
|
||||
readonly message_history_cutoff?: string | null;
|
||||
readonly joined_at?: string;
|
||||
readonly unavailable?: boolean;
|
||||
readonly member_count?: number;
|
||||
}
|
||||
51
packages/schema/src/domains/guild/GuildRoleSchemas.tsx
Normal file
51
packages/schema/src/domains/guild/GuildRoleSchemas.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {PermissionStringType} from '@fluxer/schema/src/primitives/PermissionValidators';
|
||||
import {Int32Type, SnowflakeStringType} from '@fluxer/schema/src/primitives/SchemaPrimitives';
|
||||
import {z} from 'zod';
|
||||
|
||||
export const GuildRoleResponse = z.object({
|
||||
id: SnowflakeStringType.describe('The unique identifier for this role'),
|
||||
name: z.string().describe('The name of the role'),
|
||||
color: Int32Type.describe('The colour of the role as an integer'),
|
||||
position: Int32Type.describe('The position of the role in the role hierarchy'),
|
||||
hoist_position: Int32Type.nullish().describe('The position of the role in the hoisted member list'),
|
||||
permissions: PermissionStringType.describe('fluxer:PermissionStringType The permissions bitfield for the role'),
|
||||
hoist: z.boolean().describe('Whether this role is displayed separately in the member list'),
|
||||
mentionable: z.boolean().describe('Whether this role can be mentioned by anyone'),
|
||||
unicode_emoji: z.string().nullish().describe('The unicode emoji for this role'),
|
||||
});
|
||||
|
||||
export type GuildRoleResponse = z.infer<typeof GuildRoleResponse>;
|
||||
|
||||
export const GuildRoleListResponse = z.array(GuildRoleResponse).max(250).describe('A list of guild roles');
|
||||
export type GuildRoleListResponse = z.infer<typeof GuildRoleListResponse>;
|
||||
|
||||
export interface GuildRole {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly color: number;
|
||||
readonly position: number;
|
||||
readonly hoist_position?: number | null;
|
||||
readonly permissions: string;
|
||||
readonly hoist: boolean;
|
||||
readonly mentionable: boolean;
|
||||
readonly unicode_emoji?: string | null;
|
||||
}
|
||||
Reference in New Issue
Block a user