mirror of
https://github.com/YuzuZensai/VRC-Circle.git
synced 2026-09-13 19:08:52 +00:00
♻️ refactor: dedupe utils, lift CardGrid/IconLabel primitives
This commit is contained in:
Vendored
+3
-5
@@ -1,6 +1,7 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { writeFileAtomic, writeFileAtomicSync } from "../lib/atomicFile";
|
||||
import type { CacheEntryInfo, CacheStats } from "../../shared/types/debug";
|
||||
import { httpStatusOf } from "../vrchat/errors";
|
||||
|
||||
interface Entry<T> {
|
||||
value: T;
|
||||
@@ -31,14 +32,11 @@ function byteSize(value: unknown): number {
|
||||
}
|
||||
|
||||
function retryAfterMs(err: unknown): number | null {
|
||||
if (httpStatusOf(err) !== 429) return null;
|
||||
const e = (err ?? {}) as {
|
||||
status?: number;
|
||||
statusCode?: number;
|
||||
response?: { status?: number; headers?: Record<string, string> };
|
||||
response?: { headers?: Record<string, string> };
|
||||
headers?: Record<string, string>;
|
||||
};
|
||||
const status = e.status ?? e.statusCode ?? e.response?.status;
|
||||
if (status !== 429) return null;
|
||||
const raw = e.response?.headers?.["retry-after"] ?? e.headers?.["retry-after"];
|
||||
const secs = raw != null ? Number(raw) : NaN;
|
||||
return Number.isFinite(secs) ? secs * 1000 : 8000;
|
||||
|
||||
@@ -92,10 +92,10 @@ function normalizeStatus(status?: string): UserStatus {
|
||||
}
|
||||
}
|
||||
|
||||
function toIso(v?: string | Date | null): string | undefined {
|
||||
export function toIso(v?: string | Date | null): string | undefined {
|
||||
if (!v) return undefined;
|
||||
const s = v instanceof Date ? v.toISOString() : v;
|
||||
return s === "" ? undefined : s;
|
||||
const date = v instanceof Date ? v : new Date(v);
|
||||
return Number.isNaN(date.getTime()) ? undefined : date.toISOString();
|
||||
}
|
||||
|
||||
export function toUserProfile(raw: RawUser, selfId: string): UserProfile {
|
||||
|
||||
@@ -8,6 +8,7 @@ import type {
|
||||
import type { TwoFactorMethod } from "../../shared/types/auth";
|
||||
import type { UserStatus } from "../../shared/types/user";
|
||||
import { requireActiveClient } from "./client";
|
||||
import { toIso } from "./mappers";
|
||||
import { userCache } from "./userService";
|
||||
import { cacheKeys } from "../cache/policies";
|
||||
import { entityStore } from "../store/entityStore";
|
||||
@@ -20,12 +21,6 @@ const CONTENT_FILTER_KEYS: ContentFilterKey[] = [
|
||||
"content_horror",
|
||||
];
|
||||
|
||||
function toIso(d?: Date | string | null): string | undefined {
|
||||
if (!d) return undefined;
|
||||
const date = typeof d === "string" ? new Date(d) : d;
|
||||
return Number.isNaN(date.getTime()) ? undefined : date.toISOString();
|
||||
}
|
||||
|
||||
function toSettings(u: CurrentUser): AccountSettings {
|
||||
const filters = (u.contentFilters ?? []).filter((t): t is ContentFilterKey =>
|
||||
(CONTENT_FILTER_KEYS as string[]).includes(t),
|
||||
|
||||
@@ -49,10 +49,13 @@ export async function getUser(userId: string): Promise<UserProfile> {
|
||||
export async function getUserByName(username: string): Promise<UserProfile> {
|
||||
const vrc = requireActiveClient();
|
||||
const self = await selfId();
|
||||
return userCache.get(cacheKeys.userByName(username), policies.user, async () => {
|
||||
const key = cacheKeys.userByName(username);
|
||||
const profile = await userCache.get(key, policies.user, async () => {
|
||||
const { data } = await vrc.getUserByName({ path: { username }, throwOnError: true });
|
||||
return toUserProfile(data, self);
|
||||
});
|
||||
refreshStore(profile, key);
|
||||
return profile;
|
||||
}
|
||||
|
||||
export async function searchUsers(query: string): Promise<UserProfile[]> {
|
||||
|
||||
Reference in New Issue
Block a user