refactor(frontend): split types.ts into 18 per-entity files (audit H6)
Convert the 1140-LOC types.ts into a pure re-export barrel backed by
focused per-entity files under types/, joining the existing
bindable.ts. Every import { ... } from '../types.ts' resolves
unchanged; reviewer-confirmed all 102 type exports preserved.
This commit is contained in:
+130
-1084
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* Asset shapes — uploaded/prebuilt media (images, video, sound) keyed by
|
||||||
|
* id and referenced from static-image / video / notification sources.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface Asset {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
filename: string;
|
||||||
|
mime_type: string;
|
||||||
|
asset_type: string;
|
||||||
|
size_bytes: number;
|
||||||
|
description?: string;
|
||||||
|
tags: string[];
|
||||||
|
prebuilt: boolean;
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AssetListResponse {
|
||||||
|
assets: Asset[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Audio source shapes — capture (device) and processed (template-driven)
|
||||||
|
* variants, discriminated on `source_type`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type AudioSourceType = 'capture' | 'processed';
|
||||||
|
|
||||||
|
interface AudioSourceBase {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
source_type: AudioSourceType;
|
||||||
|
description?: string;
|
||||||
|
tags: string[];
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CaptureAudioSource extends AudioSourceBase {
|
||||||
|
source_type: 'capture';
|
||||||
|
device_index: number;
|
||||||
|
is_loopback: boolean;
|
||||||
|
audio_template_id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProcessedAudioSource extends AudioSourceBase {
|
||||||
|
source_type: 'processed';
|
||||||
|
audio_source_id: string;
|
||||||
|
audio_processing_template_id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AudioSource =
|
||||||
|
| CaptureAudioSource
|
||||||
|
| ProcessedAudioSource;
|
||||||
|
|
||||||
|
export interface AudioSourceListResponse {
|
||||||
|
sources: AudioSource[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* Automation shapes — rule sets (`AutomationRule[]`) combined with
|
||||||
|
* AND/OR logic that activate a scene preset. `AutomationRule` is a wide
|
||||||
|
* optional-field shape keyed by `rule_type`; see audit finding H8 for the
|
||||||
|
* frontend rule-type registry that dispatches on it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type RuleType =
|
||||||
|
| 'application' | 'time_of_day' | 'system_idle'
|
||||||
|
| 'display_state' | 'mqtt' | 'webhook' | 'startup'
|
||||||
|
| 'home_assistant' | 'http_poll';
|
||||||
|
|
||||||
|
export type HTTPPollOperator =
|
||||||
|
| 'equals' | 'not_equals' | 'contains' | 'regex'
|
||||||
|
| 'gt' | 'lt' | 'exists';
|
||||||
|
|
||||||
|
export interface AutomationRule {
|
||||||
|
rule_type: RuleType;
|
||||||
|
apps?: string[];
|
||||||
|
match_type?: string;
|
||||||
|
start_time?: string;
|
||||||
|
end_time?: string;
|
||||||
|
idle_minutes?: number;
|
||||||
|
when_idle?: boolean;
|
||||||
|
state?: string;
|
||||||
|
topic?: string;
|
||||||
|
payload?: string;
|
||||||
|
match_mode?: string;
|
||||||
|
token?: string;
|
||||||
|
/** home_assistant rule */
|
||||||
|
ha_source_id?: string;
|
||||||
|
entity_id?: string;
|
||||||
|
/** http_poll rule — references an HTTPValueSource. */
|
||||||
|
value_source_id?: string;
|
||||||
|
operator?: HTTPPollOperator;
|
||||||
|
value?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Automation {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
enabled: boolean;
|
||||||
|
rule_logic: 'or' | 'and';
|
||||||
|
rules: AutomationRule[];
|
||||||
|
scene_preset_id?: string;
|
||||||
|
deactivation_mode: 'none' | 'revert' | 'fallback_scene';
|
||||||
|
deactivation_scene_preset_id?: string;
|
||||||
|
tags: string[];
|
||||||
|
webhook_url?: string;
|
||||||
|
is_active: boolean;
|
||||||
|
last_activated_at?: string;
|
||||||
|
last_deactivated_at?: string;
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutomationListResponse {
|
||||||
|
automations: Automation[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
/**
|
||||||
|
* Color strip source (CSS) shapes — the per-source-type field bag plus
|
||||||
|
* the supporting structures (gradient stops, composite layers, mapped
|
||||||
|
* zones, calibration). `ColorStripSource` is a wide optional-field shape
|
||||||
|
* because the backend stores all source types in one collection keyed by
|
||||||
|
* `source_type`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { BindableColor, BindableFloat } from './bindable.ts';
|
||||||
|
import type { KeyColorRectangle } from './pattern-template.ts';
|
||||||
|
import type { GameEventMapping } from './game-integration.ts';
|
||||||
|
|
||||||
|
export type CSSSourceType =
|
||||||
|
| 'picture' | 'picture_advanced' | 'single_color' | 'gradient'
|
||||||
|
| 'effect' | 'composite' | 'mapped'
|
||||||
|
| 'audio' | 'api_input' | 'notification' | 'daylight'
|
||||||
|
| 'candlelight' | 'processed' | 'weather' | 'key_colors'
|
||||||
|
| 'game_event' | 'math_wave';
|
||||||
|
|
||||||
|
export interface ColorStop {
|
||||||
|
position: number;
|
||||||
|
color: number[];
|
||||||
|
color_right?: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CompositeLayer {
|
||||||
|
source_id: string;
|
||||||
|
blend_mode: string;
|
||||||
|
opacity: number;
|
||||||
|
enabled: boolean;
|
||||||
|
brightness_source_id?: string;
|
||||||
|
processing_template_id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MappedZone {
|
||||||
|
source_id: string;
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
reverse: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AnimationConfig {
|
||||||
|
enabled: boolean;
|
||||||
|
type: string;
|
||||||
|
speed: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CalibrationLine {
|
||||||
|
picture_source_id: string;
|
||||||
|
edge: 'top' | 'right' | 'bottom' | 'left';
|
||||||
|
led_count: number;
|
||||||
|
span_start: number;
|
||||||
|
span_end: number;
|
||||||
|
reverse: boolean;
|
||||||
|
border_width: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Calibration {
|
||||||
|
mode: 'simple' | 'advanced';
|
||||||
|
lines?: CalibrationLine[];
|
||||||
|
layout?: 'clockwise' | 'counterclockwise';
|
||||||
|
start_position?: 'top_left' | 'top_right' | 'bottom_left' | 'bottom_right';
|
||||||
|
offset?: number;
|
||||||
|
leds_top?: number;
|
||||||
|
leds_right?: number;
|
||||||
|
leds_bottom?: number;
|
||||||
|
leds_left?: number;
|
||||||
|
span_top_start?: number;
|
||||||
|
span_top_end?: number;
|
||||||
|
span_right_start?: number;
|
||||||
|
span_right_end?: number;
|
||||||
|
span_bottom_start?: number;
|
||||||
|
span_bottom_end?: number;
|
||||||
|
span_left_start?: number;
|
||||||
|
span_left_end?: number;
|
||||||
|
skip_leds_start?: number;
|
||||||
|
skip_leds_end?: number;
|
||||||
|
border_width?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ColorStripSource {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
source_type: CSSSourceType;
|
||||||
|
led_count: number;
|
||||||
|
description?: string;
|
||||||
|
tags: string[];
|
||||||
|
overlay_active: boolean;
|
||||||
|
clock_id?: string;
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
|
||||||
|
// Picture
|
||||||
|
picture_source_id?: string;
|
||||||
|
smoothing?: BindableFloat;
|
||||||
|
interpolation_mode?: string;
|
||||||
|
calibration?: Calibration;
|
||||||
|
|
||||||
|
// Static / Effect / Candlelight
|
||||||
|
color?: BindableColor;
|
||||||
|
|
||||||
|
// Gradient
|
||||||
|
stops?: ColorStop[];
|
||||||
|
|
||||||
|
// Effect
|
||||||
|
effect_type?: string;
|
||||||
|
palette?: string;
|
||||||
|
intensity?: BindableFloat;
|
||||||
|
scale?: BindableFloat;
|
||||||
|
mirror?: boolean;
|
||||||
|
|
||||||
|
// Composite
|
||||||
|
layers?: CompositeLayer[];
|
||||||
|
|
||||||
|
// Mapped
|
||||||
|
zones?: MappedZone[];
|
||||||
|
|
||||||
|
// Audio
|
||||||
|
visualization_mode?: string;
|
||||||
|
audio_source_id?: string;
|
||||||
|
sensitivity?: BindableFloat;
|
||||||
|
color_peak?: BindableColor;
|
||||||
|
|
||||||
|
// Animation
|
||||||
|
animation?: AnimationConfig;
|
||||||
|
speed?: BindableFloat;
|
||||||
|
|
||||||
|
// API Input
|
||||||
|
fallback_color?: BindableColor;
|
||||||
|
timeout?: BindableFloat;
|
||||||
|
interpolation?: string;
|
||||||
|
|
||||||
|
// Notification
|
||||||
|
notification_effect?: string;
|
||||||
|
duration_ms?: number;
|
||||||
|
default_color?: BindableColor | string;
|
||||||
|
app_colors?: Record<string, string>;
|
||||||
|
app_filter_mode?: string;
|
||||||
|
app_filter_list?: string[];
|
||||||
|
os_listener?: boolean;
|
||||||
|
sound_asset_id?: string | null;
|
||||||
|
sound_volume?: BindableFloat;
|
||||||
|
app_sounds?: Record<string, { sound_asset_id?: string | null; volume?: number }>;
|
||||||
|
|
||||||
|
// Daylight
|
||||||
|
use_real_time?: boolean;
|
||||||
|
latitude?: number;
|
||||||
|
longitude?: number;
|
||||||
|
|
||||||
|
// Candlelight
|
||||||
|
num_candles?: number;
|
||||||
|
wind_strength?: BindableFloat;
|
||||||
|
|
||||||
|
// Processed
|
||||||
|
input_source_id?: string;
|
||||||
|
processing_template_id?: string;
|
||||||
|
|
||||||
|
// Weather
|
||||||
|
weather_source_id?: string;
|
||||||
|
temperature_influence?: BindableFloat;
|
||||||
|
|
||||||
|
// Key Colors
|
||||||
|
rectangles?: KeyColorRectangle[];
|
||||||
|
brightness?: BindableFloat;
|
||||||
|
|
||||||
|
// Game Event
|
||||||
|
game_integration_id?: string;
|
||||||
|
idle_color?: BindableColor;
|
||||||
|
event_mappings?: GameEventMapping[];
|
||||||
|
|
||||||
|
// Math Wave
|
||||||
|
waves?: Array<{ waveform: string; frequency: number; amplitude: number; phase: number; offset: number }>;
|
||||||
|
gradient_id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ColorStripSourceListResponse {
|
||||||
|
sources: ColorStripSource[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* Device entity shapes — physical/logical LED controllers and groups.
|
||||||
|
*
|
||||||
|
* Mirrors the backend `storage/device_store.py` dataclass and the
|
||||||
|
* `api/schemas/devices.py` Pydantic models. Field names use snake_case
|
||||||
|
* to match the JSON payloads.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type DeviceType =
|
||||||
|
| 'wled' | 'adalight' | 'ambiled' | 'mock' | 'mqtt' | 'ws'
|
||||||
|
| 'openrgb' | 'dmx' | 'ddp' | 'opc' | 'espnow' | 'hue' | 'yeelight' | 'wiz' | 'lifx' | 'govee'
|
||||||
|
| 'nanoleaf'
|
||||||
|
| 'ble' | 'usbhid' | 'spi'
|
||||||
|
| 'chroma' | 'gamesense' | 'group';
|
||||||
|
|
||||||
|
export interface Device {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
device_type: DeviceType;
|
||||||
|
led_count: number;
|
||||||
|
enabled: boolean;
|
||||||
|
baud_rate?: number;
|
||||||
|
auto_shutdown: boolean;
|
||||||
|
send_latency_ms: number;
|
||||||
|
rgbw: boolean;
|
||||||
|
zone_mode: string;
|
||||||
|
capabilities: string[];
|
||||||
|
tags: string[];
|
||||||
|
dmx_protocol: string;
|
||||||
|
dmx_start_universe: number;
|
||||||
|
dmx_start_channel: number;
|
||||||
|
ddp_port: number;
|
||||||
|
ddp_destination_id: number;
|
||||||
|
ddp_color_order: number;
|
||||||
|
opc_channel: number;
|
||||||
|
espnow_peer_mac: string;
|
||||||
|
espnow_channel: number;
|
||||||
|
hue_paired: boolean;
|
||||||
|
hue_entertainment_group_id: string;
|
||||||
|
yeelight_min_interval_ms: number;
|
||||||
|
wiz_min_interval_ms: number;
|
||||||
|
lifx_min_interval_ms: number;
|
||||||
|
govee_min_interval_ms: number;
|
||||||
|
nanoleaf_paired: boolean;
|
||||||
|
nanoleaf_min_interval_ms: number;
|
||||||
|
spi_speed_hz: number;
|
||||||
|
spi_led_type: string;
|
||||||
|
chroma_device_type: string;
|
||||||
|
gamesense_device_type: string;
|
||||||
|
default_css_processing_template_id: string;
|
||||||
|
group_device_ids: string[];
|
||||||
|
group_mode: string;
|
||||||
|
/** Optional id from the curated icon library (e.g. 'mouse', 'motherboard').
|
||||||
|
* Empty/missing → no plate is rendered, head reverts to badge-only layout. */
|
||||||
|
icon?: string;
|
||||||
|
/** Optional CSS color override for the icon. Empty/missing inherits --ch. */
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DeviceListResponse {
|
||||||
|
devices: Device[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Display shape — a detected monitor as returned by
|
||||||
|
* `GET /api/v1/config/displays`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface Display {
|
||||||
|
index: number;
|
||||||
|
name: string;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
is_primary: boolean;
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* Game integration shapes — adapters (Chroma, GameSense, …), their
|
||||||
|
* event→effect mappings, runtime status, and curated effect presets.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface GameEventMapping {
|
||||||
|
event_type: string;
|
||||||
|
effect_type: string;
|
||||||
|
color: number[];
|
||||||
|
duration_ms: number;
|
||||||
|
intensity: number;
|
||||||
|
priority: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GameIntegration {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
adapter_type: string;
|
||||||
|
adapter_config: Record<string, any>;
|
||||||
|
event_mappings: GameEventMapping[];
|
||||||
|
enabled: boolean;
|
||||||
|
description?: string;
|
||||||
|
tags: string[];
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GameIntegrationListResponse {
|
||||||
|
integrations: GameIntegration[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GameAdapterConfigField {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
label?: string;
|
||||||
|
default?: any;
|
||||||
|
required?: boolean;
|
||||||
|
hint?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GameAdapterInfo {
|
||||||
|
adapter_type: string;
|
||||||
|
display_name: string;
|
||||||
|
game_name: string;
|
||||||
|
supported_events: string[];
|
||||||
|
config_schema: GameAdapterConfigField[];
|
||||||
|
setup_instructions?: string;
|
||||||
|
supports_auto_setup?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GameAdapterListResponse {
|
||||||
|
adapters: GameAdapterInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GameEventRecord {
|
||||||
|
timestamp: string;
|
||||||
|
event_type: string;
|
||||||
|
value?: number;
|
||||||
|
data?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GameIntegrationStatus {
|
||||||
|
integration_id: string;
|
||||||
|
connected: boolean;
|
||||||
|
last_event_at?: string;
|
||||||
|
event_count: number;
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EffectPreset {
|
||||||
|
key: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
target_game_types: string[];
|
||||||
|
event_mappings: GameEventMapping[];
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Home Assistant source shapes — a HA connection plus its live
|
||||||
|
* connection-status projections used by the dashboard integration card.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface HomeAssistantSource {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
host: string;
|
||||||
|
use_ssl: boolean;
|
||||||
|
entity_filters: string[];
|
||||||
|
connected: boolean;
|
||||||
|
entity_count: number;
|
||||||
|
description?: string;
|
||||||
|
tags: string[];
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HomeAssistantSourceListResponse {
|
||||||
|
sources: HomeAssistantSource[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HomeAssistantConnectionStatus {
|
||||||
|
source_id: string;
|
||||||
|
name: string;
|
||||||
|
connected: boolean;
|
||||||
|
entity_count: number;
|
||||||
|
host?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HomeAssistantStatusResponse {
|
||||||
|
connections: HomeAssistantConnectionStatus[];
|
||||||
|
total_sources: number;
|
||||||
|
connected_count: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* HTTP endpoint shapes.
|
||||||
|
*
|
||||||
|
* A connection definition only (URL + auth + headers + timeout).
|
||||||
|
* No polling cadence is configured on the endpoint itself —
|
||||||
|
* HTTPValueSource owns interval_s and references the endpoint.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type HTTPMethod = 'GET' | 'HEAD';
|
||||||
|
|
||||||
|
export interface HTTPEndpoint {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
method: HTTPMethod;
|
||||||
|
/** Server NEVER returns the token; this flag indicates one is stored. */
|
||||||
|
auth_token_set: boolean;
|
||||||
|
headers: Record<string, string>;
|
||||||
|
timeout_s: number;
|
||||||
|
description?: string;
|
||||||
|
tags: string[];
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HTTPEndpointListResponse {
|
||||||
|
endpoints: HTTPEndpoint[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Wire payload for `POST /http/endpoints` / `PUT /http/endpoints/{id}`.
|
||||||
|
* All fields optional — the route validates required-on-create separately. */
|
||||||
|
export interface HTTPEndpointWritePayload {
|
||||||
|
name?: string;
|
||||||
|
url?: string;
|
||||||
|
method?: HTTPMethod;
|
||||||
|
/** Plaintext token. PUT distinguishes None=keep / ""=clear; omit the field to keep. */
|
||||||
|
auth_token?: string;
|
||||||
|
headers?: Record<string, string>;
|
||||||
|
timeout_s?: number;
|
||||||
|
description?: string;
|
||||||
|
tags?: string[];
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HTTPTestRequest {
|
||||||
|
url: string;
|
||||||
|
method: HTTPMethod;
|
||||||
|
auth_token: string;
|
||||||
|
headers: Record<string, string>;
|
||||||
|
timeout_s: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HTTPTestResponse {
|
||||||
|
success: boolean;
|
||||||
|
status_code?: number;
|
||||||
|
body_preview?: string;
|
||||||
|
body_json?: unknown;
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* MQTT source shapes — a broker connection plus its live connection
|
||||||
|
* status. Backs Zigbee2MQTT light targets and MQTT automation rules.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface MQTTSource {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
broker_host: string;
|
||||||
|
broker_port: number;
|
||||||
|
username: string;
|
||||||
|
password_set: boolean;
|
||||||
|
client_id: string;
|
||||||
|
base_topic: string;
|
||||||
|
connected: boolean;
|
||||||
|
description?: string;
|
||||||
|
tags: string[];
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MQTTSourceListResponse {
|
||||||
|
sources: MQTTSource[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MQTTConnectionStatus {
|
||||||
|
source_id: string;
|
||||||
|
name: string;
|
||||||
|
connected: boolean;
|
||||||
|
broker: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MQTTStatusResponse {
|
||||||
|
connections: MQTTConnectionStatus[];
|
||||||
|
total_sources: number;
|
||||||
|
connected_count: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
/**
|
||||||
|
* Output target shapes — the discriminated union over `target_type`
|
||||||
|
* (`led` | `ha_light` | `z2m_light`). Each target binds a colour source
|
||||||
|
* to a physical/logical output.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { BindableFloat } from './bindable.ts';
|
||||||
|
|
||||||
|
export type TargetType = 'led' | 'ha_light' | 'z2m_light';
|
||||||
|
|
||||||
|
export interface HALightMapping {
|
||||||
|
entity_id: string;
|
||||||
|
led_start: number;
|
||||||
|
led_end: number;
|
||||||
|
brightness_scale: BindableFloat;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Z2MLightMapping {
|
||||||
|
friendly_name: string;
|
||||||
|
led_start: number;
|
||||||
|
led_end: number;
|
||||||
|
brightness_scale: BindableFloat;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OutputTargetBase {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
target_type: TargetType;
|
||||||
|
description?: string;
|
||||||
|
tags: string[];
|
||||||
|
/** Optional id from the curated icon library. Empty/missing →
|
||||||
|
* for LED targets, the card inherits the device's icon; for
|
||||||
|
* HA-light targets, no plate is rendered. */
|
||||||
|
icon?: string;
|
||||||
|
/** Optional CSS color override for the icon. Empty/missing →
|
||||||
|
* inherits the device color (LED targets) or --ch (others). */
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LedOutputTarget extends OutputTargetBase {
|
||||||
|
target_type: 'led';
|
||||||
|
device_id: string;
|
||||||
|
color_strip_source_id: string;
|
||||||
|
brightness?: BindableFloat;
|
||||||
|
fps?: BindableFloat;
|
||||||
|
keepalive_interval: number;
|
||||||
|
state_check_interval: number;
|
||||||
|
min_brightness_threshold?: BindableFloat;
|
||||||
|
adaptive_fps: boolean;
|
||||||
|
protocol: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type HALightSourceKind = 'css' | 'color_vs';
|
||||||
|
|
||||||
|
export interface HALightOutputTarget extends OutputTargetBase {
|
||||||
|
target_type: 'ha_light';
|
||||||
|
ha_source_id: string;
|
||||||
|
/** Which colour source feeds the lights: a CSS (`'css'`) or a colour-returning value source (`'color_vs'`). */
|
||||||
|
source_kind: HALightSourceKind;
|
||||||
|
color_strip_source_id: string;
|
||||||
|
/** Used when `source_kind === 'color_vs'`. References a value source whose `return_type === 'color'`. */
|
||||||
|
color_value_source_id?: string;
|
||||||
|
brightness?: BindableFloat;
|
||||||
|
ha_light_mappings?: HALightMapping[];
|
||||||
|
update_rate?: BindableFloat;
|
||||||
|
transition?: BindableFloat;
|
||||||
|
color_tolerance?: BindableFloat;
|
||||||
|
min_brightness_threshold?: BindableFloat;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Z2MLightOutputTarget extends OutputTargetBase {
|
||||||
|
target_type: 'z2m_light';
|
||||||
|
mqtt_source_id: string;
|
||||||
|
source_kind: HALightSourceKind;
|
||||||
|
color_strip_source_id: string;
|
||||||
|
color_value_source_id?: string;
|
||||||
|
brightness?: BindableFloat;
|
||||||
|
z2m_light_mappings?: Z2MLightMapping[];
|
||||||
|
base_topic: string;
|
||||||
|
update_rate?: BindableFloat;
|
||||||
|
transition?: BindableFloat;
|
||||||
|
color_tolerance?: BindableFloat;
|
||||||
|
min_brightness_threshold?: BindableFloat;
|
||||||
|
stop_action?: 'none' | 'turn_off';
|
||||||
|
}
|
||||||
|
|
||||||
|
export type OutputTarget = LedOutputTarget | HALightOutputTarget | Z2MLightOutputTarget;
|
||||||
|
|
||||||
|
export interface OutputTargetListResponse {
|
||||||
|
targets: OutputTarget[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Pattern template shapes — named collections of key-colour rectangles
|
||||||
|
* reused across key-colour CSS sources.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface KeyColorRectangle {
|
||||||
|
name: string;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PatternTemplate {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
rectangles: KeyColorRectangle[];
|
||||||
|
tags: string[];
|
||||||
|
description?: string;
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PatternTemplateListResponse {
|
||||||
|
templates: PatternTemplate[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* Picture source shapes — the discriminated union over `stream_type`
|
||||||
|
* (`raw` | `processed` | `static_image` | `video`). These feed the
|
||||||
|
* picture-based CSS sources and calibration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type PictureSourceType = 'raw' | 'processed' | 'static_image' | 'video';
|
||||||
|
|
||||||
|
interface PictureSourceBase {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
stream_type: PictureSourceType;
|
||||||
|
description?: string;
|
||||||
|
tags: string[];
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RawPictureSource extends PictureSourceBase {
|
||||||
|
stream_type: 'raw';
|
||||||
|
display_index: number;
|
||||||
|
capture_template_id: string;
|
||||||
|
target_fps: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProcessedPictureSource extends PictureSourceBase {
|
||||||
|
stream_type: 'processed';
|
||||||
|
source_stream_id: string;
|
||||||
|
postprocessing_template_id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StaticImagePictureSource extends PictureSourceBase {
|
||||||
|
stream_type: 'static_image';
|
||||||
|
image_asset_id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VideoPictureSource extends PictureSourceBase {
|
||||||
|
stream_type: 'video';
|
||||||
|
video_asset_id?: string;
|
||||||
|
loop: boolean;
|
||||||
|
playback_speed: number;
|
||||||
|
start_time?: number;
|
||||||
|
end_time?: number;
|
||||||
|
resolution_limit?: number;
|
||||||
|
clock_id?: string;
|
||||||
|
target_fps: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PictureSource =
|
||||||
|
| RawPictureSource
|
||||||
|
| ProcessedPictureSource
|
||||||
|
| StaticImagePictureSource
|
||||||
|
| VideoPictureSource;
|
||||||
|
|
||||||
|
export interface PictureSourceListResponse {
|
||||||
|
streams: PictureSource[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Scene preset shapes — a named snapshot of which targets run with which
|
||||||
|
* colour source / brightness / fps, applied as a group.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { BindableFloat } from './bindable.ts';
|
||||||
|
|
||||||
|
export interface TargetSnapshot {
|
||||||
|
id?: string;
|
||||||
|
target_id: string;
|
||||||
|
running: boolean;
|
||||||
|
color_strip_source_id: string;
|
||||||
|
brightness?: BindableFloat;
|
||||||
|
fps: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScenePreset {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
color?: string;
|
||||||
|
targets: TargetSnapshot[];
|
||||||
|
order: number;
|
||||||
|
tags: string[];
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScenePresetListResponse {
|
||||||
|
presets: ScenePreset[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Sync clock shapes — shared time bases that animated sources subscribe
|
||||||
|
* to so multiple effects stay phase-aligned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface SyncClock {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
speed: number;
|
||||||
|
description?: string;
|
||||||
|
tags: string[];
|
||||||
|
is_running: boolean;
|
||||||
|
elapsed_time: number;
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SyncClockListResponse {
|
||||||
|
clocks: SyncClock[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/**
|
||||||
|
* Processing template shapes — capture engines, post-processing /
|
||||||
|
* colour-strip filter chains, and audio engines — plus the filter and
|
||||||
|
* engine definition shapes returned by the discovery endpoints.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface FilterInstance {
|
||||||
|
filter_id: string;
|
||||||
|
options: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CaptureTemplate {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
engine_type: string;
|
||||||
|
engine_config: Record<string, any>;
|
||||||
|
tags: string[];
|
||||||
|
description?: string;
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PostprocessingTemplate {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
filters: FilterInstance[];
|
||||||
|
tags: string[];
|
||||||
|
description?: string;
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ColorStripProcessingTemplate {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
filters: FilterInstance[];
|
||||||
|
tags: string[];
|
||||||
|
description?: string;
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AudioTemplate {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
engine_type: string;
|
||||||
|
engine_config: Record<string, any>;
|
||||||
|
tags: string[];
|
||||||
|
description?: string;
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Filter Definition (from /filters endpoint) ────────────────
|
||||||
|
|
||||||
|
export interface FilterOptionDef {
|
||||||
|
type: string;
|
||||||
|
default?: any;
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
|
step?: number;
|
||||||
|
choices?: string[];
|
||||||
|
label?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FilterDef {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
category?: string;
|
||||||
|
options: Record<string, FilterOptionDef>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Engine Info (from /capture-engines, /audio-engines) ───────
|
||||||
|
|
||||||
|
export interface EngineInfo {
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
available: boolean;
|
||||||
|
has_own_displays?: boolean;
|
||||||
|
default_config?: Record<string, any>;
|
||||||
|
config_choices?: Record<string, string[]>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
/**
|
||||||
|
* Value source shapes — the discriminated union over `source_type`.
|
||||||
|
* Each variant returns either a `float` or a `color`; the union drives
|
||||||
|
* the value-source editor and the bindable-binding pickers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type ValueSourceType =
|
||||||
|
| 'static' | 'animated' | 'audio'
|
||||||
|
| 'adaptive_time' | 'adaptive_scene' | 'daylight'
|
||||||
|
| 'static_color' | 'animated_color' | 'adaptive_time_color'
|
||||||
|
| 'ha_entity' | 'gradient_map' | 'css_extract'
|
||||||
|
| 'system_metrics' | 'game_event' | 'http';
|
||||||
|
|
||||||
|
export interface SchedulePoint {
|
||||||
|
time: string;
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ColorSchedulePoint {
|
||||||
|
time: string;
|
||||||
|
color: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ValueSourceBase {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
source_type: ValueSourceType;
|
||||||
|
return_type: 'float' | 'color';
|
||||||
|
description?: string;
|
||||||
|
tags: string[];
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StaticValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'static';
|
||||||
|
return_type: 'float';
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AnimatedValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'animated';
|
||||||
|
return_type: 'float';
|
||||||
|
waveform: string;
|
||||||
|
speed: number;
|
||||||
|
min_value: number;
|
||||||
|
max_value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AudioValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'audio';
|
||||||
|
return_type: 'float';
|
||||||
|
audio_source_id: string;
|
||||||
|
mode: string;
|
||||||
|
sensitivity: number;
|
||||||
|
smoothing: number;
|
||||||
|
min_value: number;
|
||||||
|
max_value: number;
|
||||||
|
auto_gain: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AdaptiveTimeValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'adaptive_time';
|
||||||
|
return_type: 'float';
|
||||||
|
schedule: SchedulePoint[];
|
||||||
|
min_value: number;
|
||||||
|
max_value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AdaptiveSceneValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'adaptive_scene';
|
||||||
|
return_type: 'float';
|
||||||
|
picture_source_id: string;
|
||||||
|
scene_behavior: string;
|
||||||
|
sensitivity: number;
|
||||||
|
smoothing: number;
|
||||||
|
min_value: number;
|
||||||
|
max_value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DaylightValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'daylight';
|
||||||
|
return_type: 'float';
|
||||||
|
speed: number;
|
||||||
|
use_real_time: boolean;
|
||||||
|
latitude: number;
|
||||||
|
longitude: number;
|
||||||
|
min_value: number;
|
||||||
|
max_value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StaticColorValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'static_color';
|
||||||
|
return_type: 'color';
|
||||||
|
color: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AnimatedColorValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'animated_color';
|
||||||
|
return_type: 'color';
|
||||||
|
colors: number[][];
|
||||||
|
speed: number;
|
||||||
|
easing: string;
|
||||||
|
clock_id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AdaptiveTimeColorValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'adaptive_time_color';
|
||||||
|
return_type: 'color';
|
||||||
|
schedule: ColorSchedulePoint[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HAEntityValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'ha_entity';
|
||||||
|
return_type: 'float';
|
||||||
|
ha_source_id: string;
|
||||||
|
entity_id: string;
|
||||||
|
attribute: string;
|
||||||
|
min_ha_value: number;
|
||||||
|
max_ha_value: number;
|
||||||
|
smoothing: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GradientMapValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'gradient_map';
|
||||||
|
return_type: 'color';
|
||||||
|
value_source_id: string;
|
||||||
|
gradient_id: string;
|
||||||
|
easing: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CSSExtractValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'css_extract';
|
||||||
|
return_type: 'color';
|
||||||
|
color_strip_source_id: string;
|
||||||
|
led_start: number;
|
||||||
|
led_end: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SystemMetricsValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'system_metrics';
|
||||||
|
return_type: 'float';
|
||||||
|
metric: string;
|
||||||
|
min_value: number;
|
||||||
|
max_value: number;
|
||||||
|
max_rate: number;
|
||||||
|
disk_path: string;
|
||||||
|
sensor_label: string;
|
||||||
|
poll_interval: number;
|
||||||
|
smoothing: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GameEventValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'game_event';
|
||||||
|
return_type: 'float';
|
||||||
|
game_integration_id: string;
|
||||||
|
event_type: string;
|
||||||
|
min_game_value: number;
|
||||||
|
max_game_value: number;
|
||||||
|
smoothing: number;
|
||||||
|
default_value: number;
|
||||||
|
timeout: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HTTPValueSource extends ValueSourceBase {
|
||||||
|
source_type: 'http';
|
||||||
|
return_type: 'float';
|
||||||
|
http_endpoint_id: string;
|
||||||
|
json_path: string;
|
||||||
|
interval_s: number;
|
||||||
|
min_value: number;
|
||||||
|
max_value: number;
|
||||||
|
smoothing: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ValueSource =
|
||||||
|
| StaticValueSource
|
||||||
|
| AnimatedValueSource
|
||||||
|
| AudioValueSource
|
||||||
|
| AdaptiveTimeValueSource
|
||||||
|
| AdaptiveSceneValueSource
|
||||||
|
| DaylightValueSource
|
||||||
|
| StaticColorValueSource
|
||||||
|
| AnimatedColorValueSource
|
||||||
|
| AdaptiveTimeColorValueSource
|
||||||
|
| HAEntityValueSource
|
||||||
|
| GradientMapValueSource
|
||||||
|
| CSSExtractValueSource
|
||||||
|
| SystemMetricsValueSource
|
||||||
|
| GameEventValueSource
|
||||||
|
| HTTPValueSource;
|
||||||
|
|
||||||
|
export interface ValueSourceListResponse {
|
||||||
|
sources: ValueSource[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* Weather source shapes — a provider connection (+ location) that
|
||||||
|
* weather-driven CSS sources read temperature / conditions from.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface WeatherSource {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
provider: string;
|
||||||
|
provider_config: Record<string, any>;
|
||||||
|
latitude: number;
|
||||||
|
longitude: number;
|
||||||
|
update_interval: number;
|
||||||
|
description?: string;
|
||||||
|
tags: string[];
|
||||||
|
icon?: string;
|
||||||
|
icon_color?: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WeatherSourceListResponse {
|
||||||
|
sources: WeatherSource[];
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user