// Domain DTOs shared by the plugin server and the UI — Schemas are the source of truth, // the derived types keep the original domain names so the pure core reads unchanged. import { Schema } from "effect"; /** Host OS as the launch/quoting domain sees it (macOS hosts use the linux lane). */ export const Os = Schema.Literals(["linux", "windows"]); export type Os = typeof Os.Type; /** Default emulator + core for a platform (operator-overridable per platform / per game). */ export const DefaultLaunch = Schema.Struct({ emulator: Schema.String, core: Schema.optionalKey(Schema.String), extraArgs: Schema.optionalKey(Schema.String), }); export type DefaultLaunch = typeof DefaultLaunch.Type; /** A console platform: extension set, art key, default launch (design §5). */ export const Platform = Schema.Struct({ id: Schema.String, name: Schema.String, extensions: Schema.Array(Schema.String), libretroSystem: Schema.optionalKey(Schema.String), defaultLaunch: DefaultLaunch, disc: Schema.optionalKey(Schema.Boolean), }); export type Platform = typeof Platform.Type; /** An emulator definition: per-OS detection, launch template, archive support. */ export const EmulatorDef = Schema.Struct({ id: Schema.String, name: Schema.String, detect: Schema.Struct({ linux: Schema.Array(Schema.String), windows: Schema.Array(Schema.String), }), coresDir: Schema.optionalKey( Schema.Struct({ linux: Schema.Array(Schema.String), windows: Schema.Array(Schema.String), }), ), template: Schema.String, supportsArchives: Schema.Boolean, contested: Schema.optionalKey(Schema.Boolean), }); export type EmulatorDef = typeof EmulatorDef.Type; /** A detected emulator install (UI's Emulators page + launch resolution). */ export const DetectedEmulator = Schema.Struct({ id: Schema.String, name: Schema.String, template: Schema.String, supportsArchives: Schema.Boolean, contested: Schema.optional(Schema.Boolean), exeToken: Schema.String, exePath: Schema.optional(Schema.String), appId: Schema.optional(Schema.String), via: Schema.Literals(["path", "file", "flatpak"]), coresDir: Schema.optional(Schema.String), cores: Schema.optional(Schema.Array(Schema.String)), }); export type DetectedEmulator = typeof DetectedEmulator.Type; /** A candidate the compute rejected, with a human reason (Library page, CLI). */ export const Skipped = Schema.Struct({ external_id: Schema.String, title: Schema.String, reason: Schema.String, }); export type Skipped = typeof Skipped.Type; /** A summary of one desired-state compute (Overview + Library pages). */ export const SyncReport = Schema.Struct({ considered: Schema.Number, included: Schema.Number, skipped: Schema.Array(Skipped), excluded: Schema.Array( Schema.Struct({ external_id: Schema.String, title: Schema.String }), ), warnings: Schema.Array(Schema.String), truncated: Schema.Number, perPlatform: Schema.Record(Schema.String, Schema.Number), overWarn: Schema.Boolean, }); export type SyncReport = typeof SyncReport.Type; export const LastSync = Schema.Struct({ fingerprint: Schema.String, count: Schema.Number, at: Schema.Number, }); export type LastSync = typeof LastSync.Type; /** The engine status the Overview page renders and the SSE feed streams. */ export const EngineStatus = Schema.Struct({ rootsConfigured: Schema.Number, os: Os, artProvider: Schema.NullOr(Schema.String), syncing: Schema.Boolean, lastSync: Schema.optional(LastSync), lastReport: Schema.optional(SyncReport), detectedAt: Schema.optional(Schema.Number), paths: Schema.Struct({ dir: Schema.String, config: Schema.String, cache: Schema.String, }), }); export type EngineStatus = typeof EngineStatus.Type;