feat(invites): приглашения, каталог публичных серверов и публичность сервера

- POST /guilds/{id}/invites (CREATE_INVITES): код из 10 символов, лимит
  использований и срок жизни; GET /guilds/{id}/invites (MANAGE_GUILD);
  DELETE /invites/{code} — создатель или MANAGE_GUILD;
- GET /invites/{code} — предпросмотр с карточкой сервера, 410 для истёкших и
  исчерпанных; POST /invites/{code} — принятие с проверкой лимита участников,
  повторное принятие не расходует использование;
- PATCH /guilds/{id} принимает `public`: сервер попадает в каталог и открыт для
  входа без приглашения (главный сервер публиковать нельзя);
- GET /guilds/public — каталог (имя, описание, иконка, число участников);
- аудит invite.create/invite.revoke/invite.accept, события INVITE_CREATE и
  INVITE_DELETE владельцу сессии;
- тесты: полный жизненный цикл приглашения, исчерпание, отзыв, права,
  публичный каталог и вход в публичный сервер.
This commit is contained in:
2026-09-19 23:33:34 +03:00
parent e4ffbb05a5
commit 61a84bfeae
16 changed files with 1233 additions and 32 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ export function Button({ variant = 'primary', className = '', ...rest }: ButtonP
return (
<button
type="button"
className={`inline-flex items-center justify-center gap-2 rounded-[var(--radius-md)] px-3 py-1.5 text-sm font-medium transition-colors duration-[var(--duration-fast)] disabled:cursor-not-allowed disabled:opacity-50 ${variants[variant]} ${className}`}
className={`inline-flex items-center justify-center gap-2 rounded-[var(--radius-md)] px-3 py-1.5 text-sm font-medium transition-[background-color,opacity,transform,border-color] duration-[var(--duration-fast)] active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50 ${variants[variant]} ${className}`}
{...rest}
/>
);