feat(shared): reorder AppError constructor to (message, code, status), add singleton logger, retry and TTL cache utilities

This commit is contained in:
MythEclipse
2026-06-02 21:06:42 +07:00
parent 9045e7e347
commit 2d79d8aefd
50 changed files with 401 additions and 449 deletions
+1 -12
View File
@@ -1,12 +1 @@
export interface Guild {
id: string;
name: string;
icon: string | null;
}
export interface Channel {
id: string;
name: string;
type?: string;
parentId?: string | null;
}
export { Guild, Channel } from "../../shared/api/client";
+1 -17
View File
@@ -1,17 +1 @@
export type MediaMode = "music" | "screen";
export interface MediaItem {
id?: string;
source: string;
title: string;
mode?: MediaMode;
durationMs?: number | null;
thumbnailUrl?: string | null;
}
export interface MediaState {
playing: boolean;
musicVolume: number;
current: MediaItem | null;
queue: MediaItem[];
}
export { MediaMode, MediaItem, MediaState } from "../../shared/api/client";
@@ -14,6 +14,15 @@ export interface MessageMetadata {
embeds?: Array<{ title?: string; image?: string; thumbnail?: string }>;
}
export function parseMetadata(value: string | null): MessageMetadata {
if (!value) return {};
try {
return JSON.parse(value) as MessageMetadata;
} catch {
return {};
}
}
export interface MessageRecord {
id: string;
guild_id: string;
+1 -14
View File
@@ -1,14 +1 @@
export type DashboardTab = "live" | "messages" | "analytics";
export interface UIState {
selectedGuild?: string;
selectedVoiceGuild?: string;
selectedVoiceChannel?: string;
selectedTextGuild?: string;
selectedTextChannel?: string;
selectedAnalyticsGuild?: string;
selectedAnalyticsChannel?: string;
activeTab?: DashboardTab;
isListening?: boolean;
isStreaming?: boolean;
}
export { DashboardTab, UIState } from "../../shared/api/client";
+1 -14
View File
@@ -1,14 +1 @@
export interface VoiceStatus {
connected: boolean;
activeGuildId?: string | null;
activeChannelId?: string | null;
activeChannelName?: string | null;
}
export interface ActiveSpeaker {
id?: string;
userId?: string;
username: string;
avatar: string;
speaking: boolean;
}
export { VoiceStatus, ActiveSpeaker } from "../../shared/api/client";
@@ -3,6 +3,7 @@
import { Download, Mic } from "lucide-react";
import { useEffect, useState } from "react";
import { Badge, Button, Skeleton } from "../../../shared/ui";
import { formatBytes, formatDate } from "../../../shared/lib/utils";
interface VoiceRecording {
id: string;
@@ -21,16 +22,6 @@ interface VoiceRecording {
uploaded_at: number | null;
}
function formatDate(value: number): string {
return new Date(value).toLocaleString();
}
function formatBytes(value: number): string {
if (value < 1024) return `${value} B`;
if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KB`;
return `${(value / 1024 / 1024).toFixed(1)} MB`;
}
export function RecordingsSubPanel() {
const [recordings, setRecordings] = useState<VoiceRecording[]>([]);
const [loading, setLoading] = useState(true);
@@ -1,10 +1,5 @@
import type { MessageRecord } from "../../../shared/api/client";
interface MessageMetadata {
stickers?: Array<{ name?: string; url?: string }>;
attachments?: Array<{ name: string; url: string; contentType?: string }>;
embeds?: Array<{ title?: string; image?: string; thumbnail?: string }>;
}
import { parseMetadata } from "../../../entities/message/types";
interface ImageItem {
url: string;
@@ -13,15 +8,6 @@ interface ImageItem {
message: MessageRecord;
}
function parseMetadata(value: string | null): MessageMetadata {
if (!value) return {};
try {
return JSON.parse(value) as MessageMetadata;
} catch {
return {};
}
}
export function ImageGrid({ messages }: { messages: MessageRecord[] }) {
const images: ImageItem[] = [];
@@ -14,6 +14,7 @@ import { Fragment, useMemo, useState } from "react";
import type { MessageRecord } from "../../../shared/api/client";
import { moderateMessage } from "../../../shared/api/client";
import { Badge, Button, Skeleton } from "../../../shared/ui";
import { parseMetadata } from "../../../entities/message/types";
const CUSTOM_EMOJI_REGEX = /<(a)?:([a-zA-Z0-9_]+):(\d+)>/g;
@@ -71,21 +72,6 @@ interface MessageCardProps {
compact?: boolean;
}
interface MessageMetadata {
stickers?: Array<{ name?: string; url?: string }>;
attachments?: Array<{ name: string; url: string; contentType?: string }>;
embeds?: Array<{ title?: string; image?: string; thumbnail?: string }>;
}
function parseMetadata(value: string | null): MessageMetadata {
if (!value) return {};
try {
return JSON.parse(value) as MessageMetadata;
} catch {
return {};
}
}
function parseStringList(value?: string | null): string[] {
if (!value) return [];
try {
@@ -112,6 +112,8 @@ export interface ActiveSpeaker {
speaking: boolean;
}
export type MediaMode = "music" | "screen";
export interface MediaItem {
id?: string;
source: string;
+12
View File
@@ -4,3 +4,15 @@ import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export function formatBytes(bytes: number): string {
if (bytes === 0) return "0 Bytes";
const k = 1024;
const sizes = ["Bytes", "KB", "MB", "GB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return `${Math.round((bytes / Math.pow(k, i)) * 100) / 100} ${sizes[i]}`;
}
export function formatDate(value: number): string {
return new Date(value).toLocaleString();
}