From 326aea5ad188d2365a58979ea7cca09437908c8a Mon Sep 17 00:00:00 2001 From: Shish Date: Wed, 1 Apr 2026 19:59:14 +0100 Subject: [PATCH 1/2] [openapi] move User to shared components list --- browser3/src/schemas.ts | 15 +++++++++++++++ browser3/src/types.ts | 8 ++++++++ openapi/components.yaml | 10 ++++++++++ openapi/openapi-room.yaml | 9 +-------- player3/src/schemas.ts | 15 +++++++++++++++ player3/src/types.ts | 8 ++++++++ processmedia3/pm3/lib/types.py | 4 ++++ 7 files changed, 61 insertions(+), 8 deletions(-) diff --git a/browser3/src/schemas.ts b/browser3/src/schemas.ts index 5ec18d08..4a5dc612 100644 --- a/browser3/src/schemas.ts +++ b/browser3/src/schemas.ts @@ -290,6 +290,20 @@ export const LintErrorSchema = { } } as const; +export const UserSchema = { + "type": "object", + "required": [ + "is_admin" + ], + "properties": { + "is_admin": { + "type": "boolean", + "description": "Whether the user has admin privileges", + "default": false + } + } +} as const; + export const schemas = { Track: TrackSchema, Attachment: AttachmentSchema, @@ -297,4 +311,5 @@ export const schemas = { QueueItem: QueueItemSchema, Settings: SettingsSchema, LintError: LintErrorSchema, + User: UserSchema, } as const; diff --git a/browser3/src/types.ts b/browser3/src/types.ts index 3580b320..65c7c1e2 100644 --- a/browser3/src/types.ts +++ b/browser3/src/types.ts @@ -144,6 +144,13 @@ export interface components { /** @description Error message */ message: string; }; + User: { + /** + * @description Whether the user has admin privileges + * @default false + */ + is_admin: boolean; + }; }; responses: never; parameters: never; @@ -157,5 +164,6 @@ export type Subtitle = components['schemas']['Subtitle']; export type QueueItem = components['schemas']['QueueItem']; export type Settings = components['schemas']['Settings']; export type LintError = components['schemas']['LintError']; +export type User = components['schemas']['User']; export type $defs = Record; export type operations = Record; diff --git a/openapi/components.yaml b/openapi/components.yaml index 4d27a742..f873ec55 100644 --- a/openapi/components.yaml +++ b/openapi/components.yaml @@ -229,3 +229,13 @@ components: message: type: string description: Error message + + User: + type: object + required: + - is_admin + properties: + is_admin: + type: boolean + description: Whether the user has admin privileges + default: false diff --git a/openapi/openapi-room.yaml b/openapi/openapi-room.yaml index 8d081154..6dd77de8 100644 --- a/openapi/openapi-room.yaml +++ b/openapi/openapi-room.yaml @@ -62,14 +62,7 @@ components: $ref: "./components.yaml#/components/schemas/Settings" User: - type: object - required: - - is_admin - properties: - is_admin: - type: boolean - description: Whether the user has admin privileges - default: false + $ref: "./components.yaml#/components/schemas/User" LoginRequest: type: object diff --git a/player3/src/schemas.ts b/player3/src/schemas.ts index 5ec18d08..4a5dc612 100644 --- a/player3/src/schemas.ts +++ b/player3/src/schemas.ts @@ -290,6 +290,20 @@ export const LintErrorSchema = { } } as const; +export const UserSchema = { + "type": "object", + "required": [ + "is_admin" + ], + "properties": { + "is_admin": { + "type": "boolean", + "description": "Whether the user has admin privileges", + "default": false + } + } +} as const; + export const schemas = { Track: TrackSchema, Attachment: AttachmentSchema, @@ -297,4 +311,5 @@ export const schemas = { QueueItem: QueueItemSchema, Settings: SettingsSchema, LintError: LintErrorSchema, + User: UserSchema, } as const; diff --git a/player3/src/types.ts b/player3/src/types.ts index 3580b320..65c7c1e2 100644 --- a/player3/src/types.ts +++ b/player3/src/types.ts @@ -144,6 +144,13 @@ export interface components { /** @description Error message */ message: string; }; + User: { + /** + * @description Whether the user has admin privileges + * @default false + */ + is_admin: boolean; + }; }; responses: never; parameters: never; @@ -157,5 +164,6 @@ export type Subtitle = components['schemas']['Subtitle']; export type QueueItem = components['schemas']['QueueItem']; export type Settings = components['schemas']['Settings']; export type LintError = components['schemas']['LintError']; +export type User = components['schemas']['User']; export type $defs = Record; export type operations = Record; diff --git a/processmedia3/pm3/lib/types.py b/processmedia3/pm3/lib/types.py index cfc0cb22..a87302a2 100644 --- a/processmedia3/pm3/lib/types.py +++ b/processmedia3/pm3/lib/types.py @@ -46,6 +46,10 @@ class LintError(TypedDict): message: str +class User(TypedDict): + is_admin: bool + + class Attachments(TypedDict): video: list[Attachment] image: list[Attachment] From 1c33442c972a4b0f2e6722bc47d3bcd5a42e8d8e Mon Sep 17 00:00:00 2001 From: Shish Date: Wed, 1 Apr 2026 20:12:55 +0100 Subject: [PATCH 2/2] [br3,pl3] typed API responses --- .../src/components/LyricsViewer/LyricsViewer.tsx | 2 +- browser3/src/hooks/api.ts | 12 ++++++------ browser3/src/providers/room.tsx | 4 ++-- browser3/src/providers/server.tsx | 2 +- player3/src/hooks/api.ts | 12 ++++++------ player3/src/providers/room.tsx | 4 ++-- player3/src/providers/server.tsx | 2 +- player3/src/screens/podium/podium.tsx | 2 +- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/browser3/src/components/LyricsViewer/LyricsViewer.tsx b/browser3/src/components/LyricsViewer/LyricsViewer.tsx index aba5962b..47895e19 100644 --- a/browser3/src/components/LyricsViewer/LyricsViewer.tsx +++ b/browser3/src/components/LyricsViewer/LyricsViewer.tsx @@ -23,7 +23,7 @@ export function LyricsViewer({ (a) => a.mime === "application/json" && a.variant === variant, ); if (subtitleAttachment) { - request({ + request({ url: attachment_path(subtitleAttachment), options: { credentials: "omit" }, onAction: (result) => setLyrics(result), diff --git a/browser3/src/hooks/api.ts b/browser3/src/hooks/api.ts index 05e423dd..2215420d 100644 --- a/browser3/src/hooks/api.ts +++ b/browser3/src/hooks/api.ts @@ -3,23 +3,23 @@ import { useCallback, useContext, useState } from "react"; import { ClientContext } from "@/providers/client"; import { PageContext } from "@/providers/page"; -type CommonRequestProps = { +type CommonRequestProps = { options?: Record; notify?: string; notify_ok?: string; onProgress?: ({ done, size }: { done: number; size: number }) => void; - onAction?: (result: any) => void; + onAction?: (result: T) => void; onException?: () => void; }; -type FunctionRequestProps = CommonRequestProps & { +type FunctionRequestProps = CommonRequestProps & { function: string; url?: never; }; -type UrlRequestProps = CommonRequestProps & { +type UrlRequestProps = CommonRequestProps & { function?: never; url: string; }; -type ApiRequestProps = FunctionRequestProps | UrlRequestProps; +type ApiRequestProps = FunctionRequestProps | UrlRequestProps; export function useApi() { const { roomName } = useContext(PageContext); @@ -32,7 +32,7 @@ export function useApi() { ); const request = useCallback( - (props_: ApiRequestProps) => { + (props_: ApiRequestProps) => { const props = { response: "json", url: diff --git a/browser3/src/providers/room.tsx b/browser3/src/providers/room.tsx index cb989da2..f7067377 100644 --- a/browser3/src/providers/room.tsx +++ b/browser3/src/providers/room.tsx @@ -4,7 +4,7 @@ import { createContext, useContext, useEffect, useMemo, useState } from "react"; import { useApi } from "@/hooks/api"; import { useMemoObj } from "@/hooks/memo"; -import type { QueueItem, Settings, Track } from "@/types"; +import type { QueueItem, Settings, Track, User } from "@/types"; import { current_and_future, get_default_settings, @@ -84,7 +84,7 @@ export function RoomProvider(props: any) { }, [tracks, hiddenTags, forcedTags]); useEffect(() => { - request({ + request({ function: "login", options: { method: "POST", diff --git a/browser3/src/providers/server.tsx b/browser3/src/providers/server.tsx index ab49fbe7..a8343ad5 100644 --- a/browser3/src/providers/server.tsx +++ b/browser3/src/providers/server.tsx @@ -35,7 +35,7 @@ function InternalServerProvider(props: any) { setTracksUpdated(pkt.json()["tracks_json_mtime"]); }); useEffect(() => { - request({ + request>({ url: `/files/tracks.json?ver=${tracksUpdated}`, options: { credentials: "omit" }, onAction: (result) => setTracks(result), diff --git a/player3/src/hooks/api.ts b/player3/src/hooks/api.ts index f4d95f93..e40fae2a 100644 --- a/player3/src/hooks/api.ts +++ b/player3/src/hooks/api.ts @@ -3,23 +3,23 @@ import { useParams } from "react-router-dom"; import { ClientContext } from "@/providers/client"; -type CommonRequestProps = { +type CommonRequestProps = { options?: Record; notify?: string; notify_ok?: string; onProgress?: ({ done, size }: { done: number; size: number }) => void; - onAction?: (result: any) => void; + onAction?: (result: T) => void; onException?: () => void; }; -type FunctionRequestProps = CommonRequestProps & { +type FunctionRequestProps = CommonRequestProps & { function: string; url?: never; }; -type UrlRequestProps = CommonRequestProps & { +type UrlRequestProps = CommonRequestProps & { function?: never; url: string; }; -type ApiRequestProps = FunctionRequestProps | UrlRequestProps; +type ApiRequestProps = FunctionRequestProps | UrlRequestProps; export function useApi() { const { roomName } = useParams(); @@ -32,7 +32,7 @@ export function useApi() { ); const request = useCallback( - (props_: ApiRequestProps) => { + (props_: ApiRequestProps) => { const props = { response: "json", url: diff --git a/player3/src/providers/room.tsx b/player3/src/providers/room.tsx index 1a28adad..0f621657 100644 --- a/player3/src/providers/room.tsx +++ b/player3/src/providers/room.tsx @@ -5,7 +5,7 @@ import { useParams } from "react-router-dom"; import { useApi } from "@/hooks/api"; import { useMemoObj } from "@/hooks/memo"; -import type { QueueItem, Settings } from "@/types"; +import type { QueueItem, Settings, User } from "@/types"; import { current_and_future, get_default_settings } from "@/utils"; import { ClientContext } from "./client"; @@ -53,7 +53,7 @@ export function RoomProvider(props: any) { }); useEffect(() => { - request({ + request({ function: "login", options: { method: "POST", diff --git a/player3/src/providers/server.tsx b/player3/src/providers/server.tsx index c73c4deb..f8a500c8 100644 --- a/player3/src/providers/server.tsx +++ b/player3/src/providers/server.tsx @@ -36,7 +36,7 @@ function InternalServerProvider(props: any) { setTracksUpdated(pkt.json()["tracks_json_mtime"]); }); useEffect(() => { - request({ + request>({ url: `/files/tracks.json?ver=${tracksUpdated}`, options: { credentials: "omit" }, onAction: (result) => setTracks(result), diff --git a/player3/src/screens/podium/podium.tsx b/player3/src/screens/podium/podium.tsx index fdc17c4f..9b94ea96 100644 --- a/player3/src/screens/podium/podium.tsx +++ b/player3/src/screens/podium/podium.tsx @@ -86,7 +86,7 @@ function PodiumLyrics({ a.variant === queue_item.subtitle_variant, ); if (subtitleAttachment) { - request({ + request({ url: attachment_path(subtitleAttachment), options: { credentials: "omit" }, onAction: (result) => setLyrics(add_dot_dot_dots(result)),