feat: initial Signage 0.1.0

This commit is contained in:
ekklesia
2026-08-28 16:41:54 -05:00
parent 20756f11af
commit 92bef4c7aa
107 changed files with 24397 additions and 0 deletions
+198
View File
@@ -0,0 +1,198 @@
/**
* The wire shapes Signage's dashboard reads.
*
* Signage owns both ends of every one of these, which is exactly why they are written down: the
* server's route and this file are one contract, and a drift between them is a bug an operator sees
* rather than a compiler does.
*/
export interface SettingsResponse {
readonly crossfadeMs: number;
readonly moduleVersion: string;
readonly nativeImageDurationMs: number;
readonly nativePresentation: {
readonly backgroundMode: string;
readonly backgroundColor: string;
readonly backgroundDarkened: boolean;
readonly blurPixels: number;
};
readonly rendererInputVersion: string;
readonly timezone: string;
readonly uploads: {
readonly batchMaxFiles: number;
readonly concurrency: number;
readonly maxBytes: number;
readonly maxPixels: number;
};
}
export interface ImageRendition {
readonly kind: string;
readonly url: string;
readonly expiresAt: string;
readonly width: number;
readonly height: number;
}
export interface ImageRecord {
readonly id: string;
readonly displayName: string;
readonly originalFilename: string;
readonly contentType: string;
readonly byteSize: number;
readonly width: number;
readonly height: number;
readonly status: string;
readonly expiresAt: string | null;
readonly createdAt: string;
readonly renditions: readonly ImageRendition[];
}
export interface TimelineSummary {
readonly id: string;
readonly name: string;
readonly description: string | null;
readonly eligibleFrom: string | null;
readonly eligibleUntil: string | null;
readonly revision: number;
readonly updatedAt: string;
}
export interface TimelineSource {
readonly id: string;
readonly label: string;
readonly providerId: string;
readonly sourceId: string;
}
export interface TimelineSlot {
readonly id: string;
readonly position: number;
readonly kind: "provider-source" | "pinned-item";
readonly sourceId: string | null;
readonly providerId: string | null;
readonly itemId: string | null;
readonly enabled: boolean;
readonly durationOverrideMs: number | null;
readonly eligibleFrom: string | null;
readonly eligibleUntil: string | null;
readonly presentation: {
readonly backgroundMode: string | null;
readonly backgroundColor: string | null;
readonly backgroundDarkened: boolean | null;
readonly blurPixels: number | null;
readonly foregroundShadow: boolean | null;
};
}
export interface TimelineDetail {
readonly timeline: TimelineSummary;
readonly sources: readonly TimelineSource[];
readonly slots: readonly TimelineSlot[];
}
export interface ProviderHealth {
readonly providerId: string;
readonly providerVersion: string;
readonly contractVersion: string;
readonly renderer: { readonly contributionId: string; readonly contributionVersion: string };
readonly defaultDurationMs: number;
readonly registeredAt: string;
readonly consecutiveFailures: number;
readonly lastFailureCode: string | null;
readonly lastFailureAt: string | null;
readonly lastSuccessAt: string | null;
}
export interface ProviderSourceDescriptor {
readonly id: string;
readonly label: string;
readonly description?: string;
}
export interface ProviderItemDescriptor {
readonly id: string;
readonly label: string;
readonly description?: string;
readonly availableUntil?: string | null;
}
export type TransportState = "idle" | "playing" | "paused" | "static";
export interface PlaybackSnapshotView {
readonly groupId: string;
readonly revision: number;
readonly serverNowMs: number;
readonly transport: TransportState;
readonly blackout: boolean;
readonly activeTimelineId: string | null;
readonly pendingTimelineId: string | null;
readonly scheduledTimelineId: string | null;
readonly scheduledActivationAtMs: number | null;
readonly currentSelectionId: string | null;
readonly currentSlotId: string | null;
readonly startedAtMs: number | null;
readonly deadlineAtMs: number | null;
readonly remainingMs: number | null;
readonly selectionRevision: number | null;
readonly staticAssetId: string | null;
}
export interface ChannelView {
readonly id: string;
readonly key: string;
readonly name: string;
readonly isDefault: boolean;
}
export interface ChannelGroupView {
readonly id: string;
readonly name: string;
readonly revision: number;
readonly channels: readonly ChannelView[];
readonly playback: PlaybackSnapshotView;
}
export interface PlaybackDetailView {
readonly snapshot: PlaybackSnapshotView;
readonly current: {
readonly id: string;
readonly itemId: string;
readonly itemRevision: string;
readonly providerId: string;
readonly rendererContributionId: string | null;
readonly revision: number;
readonly stale: boolean;
readonly withdrawn: boolean;
readonly durationMs: number;
readonly startedAtMs: number | null;
readonly deadlineAtMs: number | null;
} | null;
readonly history: readonly {
readonly id: string;
readonly itemId: string;
readonly providerId: string;
readonly sequence: number;
readonly startedAtMs: number | null;
}[];
}
export interface ViewerHealthView {
readonly id: string;
readonly name: string;
readonly online: boolean;
readonly channelId: string | null;
readonly deviceId: string | null;
readonly lastSeenAtMs: number | null;
readonly reportedTimelineId: string | null;
readonly reportedSelectionId: string | null;
readonly reportedProviderId: string | null;
readonly reportedContributionId: string | null;
readonly offlineReady: boolean;
readonly cachedAssetCount: number;
readonly lastError: {
readonly code: string;
readonly detail: string | null;
readonly atMs: number;
} | null;
}