/** * Public, browser-only contract for an XLibrary plugin entry module. * Plugin packages should bundle this tiny helper with their own code. */ export type PluginPermission = 'library.games.read' | 'library.games.write' | 'sessions.events.read' | 'tracking.providers' | 'game.custom-fields' | 'game.actions' | 'plugin.storage' | 'plugin.cache' | 'plugin.settings' | 'plugin.auth' | 'network.http' | 'notifications.show' | 'jobs.run' | 'game-sources.providers' | 'browser.page.capture' | 'imports.sources' | 'exports.targets' | 'backup.contribute' | 'filters.facets' | 'ui.game-details.sidebar' | 'ui.game-details.header' | 'ui.dashboard.widget' | 'ui.library.toolbar' | 'ui.settings.section'; export interface PluginRuntimeContext { apiVersion: 1; plugin: { id: string; name: string; version: string; }; permissions: PluginPermission[]; } export interface PluginGame { id: string; name: string; developer?: string; version?: string; engine?: string; tags: string[]; customTags: string[]; status?: string; completionStatus?: string; totalPlaytime?: number; createdAt?: string; updatedAt?: string; providers: string[]; } export interface PluginHost { storage: { get(key: string): Promise; set(key: string, value: unknown): Promise; }; cache: { get(key: string): Promise; set(key: string, value: unknown, options: { ttlSeconds: number; }): Promise<{ stored: true; expiresAt: string; }>; delete(key: string): Promise<{ deleted: boolean; }>; }; settings: { get(): Promise>; set(values: Record): Promise>; }; network: { request(input: { url: string; method?: 'GET' | 'POST'; body?: string; headers?: Record; }): Promise<{ status: number; contentType?: string; body: string; }>; }; notifications: { show(input: { title: string; message: string; level?: 'info' | 'warn' | 'error'; }): Promise<{ shown: true; }>; }; games: { list(): Promise; }; sessions: { list(): Promise; }; gameFields: { get(gameId: string): Promise>; }; importInput: { readChunk(inputId: string, offset: number, maxBytes: number): Promise<{ data: string; eof: boolean; }>; }; exportOutput: { write(dataBase64: string): Promise<{ bytesWritten: number; }>; }; auth: { getStatus(authId: string): Promise<{ connected: boolean; expiresAt?: string; }>; begin(authId: string): Promise<{ started: true; }>; clear(authId: string): Promise<{ cleared: boolean; }>; request(authId: string, input: { url: string; method?: 'GET' | 'POST'; body?: string; headers?: Record; }): Promise<{ status: number; contentType?: string; body: string; }>; }; diagnostics: { log(input: { level: 'debug' | 'info' | 'warn' | 'error'; event: string; message: string; context?: Record; }): Promise<{ recorded: true; }>; }; } export interface PluginSession { id: string; gameId: string; startedAt: number; lastSeen: number; gameName?: string; trackingMode: 'pid' | 'process-name' | 'manual'; } export type PluginCustomFieldValue = string | number | boolean | string[]; export interface PluginTrackingEvent { type: 'started' | 'ended'; session: PluginSession; duration?: number; game: PluginGame; } export interface PluginGameActionPatch { addTags?: string[]; removeTags?: string[]; status?: string; completionStatus?: string; } export interface PluginGameActionResult { message?: string; gamePatch?: PluginGameActionPatch; fieldValues?: Record; } export type PluginUiTone = 'default' | 'info' | 'success' | 'warning' | 'danger'; export type PluginUiPanel = { title?: string; description?: string; nodes: Array<{ type: 'notice'; tone?: PluginUiTone; title?: string; text: string; } | { type: 'stat'; label: string; value: string; description?: string; } | { type: 'key-value'; items: Array<{ label: string; value: string; }>; } | { type: 'action'; id: string; label: string; tone?: PluginUiTone; disabled?: boolean; description?: string; }>; }; export type PluginFilterValue = boolean | string | string[] | { min?: number; max?: number; }; export type PluginGameSourceSearchPayload = { sourceId: string; query: string; cursor?: string; limit: number; locale?: string; }; export type PluginGameSourceResolvePayload = { sourceId: string; externalId?: string; url?: string; locale?: string; }; export type PluginGameSourceRefreshPayload = { sourceId: string; externalId: string; url: string; game: Pick; locale?: string; }; export interface PluginInvocationMap { 'imports.parse': { payload: { sourceId: string; input: Record; }; result: PluginImportResult; }; 'exports.serialize': { payload: { targetId: string; games?: PluginImportGame[]; }; result: PluginExportCompletion; }; 'filters.evaluate': { payload: { facets: Array<{ id: string; selection: PluginFilterValue; }>; games: PluginGame[]; }; result: { matches: Record; }; }; 'backup.capture': { payload: { dataVersion: number; }; result: { dataVersion: number; data: Record; }; }; 'backup.restore': { payload: { dataVersion: number; data: Record; dryRun: boolean; }; result: { restored: boolean; }; }; 'ui.render': { payload: { contributionId: string; slot: PluginPermission; context: { gameId?: string; game?: PluginGame; }; }; result: PluginUiPanel; }; 'ui.action': { payload: { contributionId: string; actionId: string; context: { gameId?: string; game?: PluginGame; }; }; result: { panel?: PluginUiPanel; }; }; 'tracking.session-event': { payload: { providerId: string; event: PluginTrackingEvent; }; result: { fieldValues?: Record; }; }; 'game-actions.execute': { payload: { actionId: string; game: PluginGame; dryRun: boolean; }; result: PluginGameActionResult; }; 'jobs.run': { payload: { jobId: string; trigger: 'startup' | 'session-started' | 'session-ended'; event?: PluginTrackingEvent; }; result: unknown; }; 'settings.migrate': { payload: { fromDataVersion: number; values: Record; }; result: { values: Record; }; }; 'storage.migrate': { payload: { fromDataVersion: number; values: Record; }; result: { values: Record; }; }; 'lifecycle.deactivate': { payload: Record; result: undefined; }; 'game-sources.search': { payload: PluginGameSourceSearchPayload; result: { candidates: PluginGameSourceCandidate[]; nextCursor?: string; }; }; 'game-sources.resolve': { payload: PluginGameSourceResolvePayload; result: PluginGameSourceDraft; }; 'game-sources.refresh': { payload: PluginGameSourceRefreshPayload; result: PluginGameSourcePatch; }; 'game-sources.parse-page': { payload: PluginGameSourceParsePagePayload; result: PluginGameSourceDraft; }; } export type PluginInvocationMethod = keyof PluginInvocationMap; export type PluginInvocation = { [Method in M]: { method: Method; payload: PluginInvocationMap[Method]['payload']; }; }[M]; export type PluginInvocationResult = PluginInvocationMap[M]['result']; export interface PluginGameSourceIdentity { externalId: string; canonicalUrl: string; } export interface PluginGameSourceCandidate { identity: PluginGameSourceIdentity; title: string; developer?: string; version?: string; coverUrl?: string; summary?: string; score?: number; } export interface PluginGameSourceDraft extends PluginGameSourceIdentity { name: string; description?: string; developer?: string; version?: string; coverUrl?: string; screenshotUrls?: string[]; releaseDate?: string; engine?: string; status?: string; tags?: string[]; rating?: number; isPartial?: boolean; missingFields?: string[]; metadata?: Record; } export interface PluginGameSourcePatch extends PluginGameSourceDraft { changedFields: Array<'name' | 'description' | 'developer' | 'version' | 'coverUrl' | 'screenshotUrls' | 'releaseDate' | 'engine' | 'status' | 'tags' | 'rating' | 'metadata'>; } /** * A bounded, inert snapshot returned by the browser extension after the user * approved both the plugin source host and the browser host permission. * It is data only: plugin code never runs in the browser page context. */ export interface PluginGameSourcePageCapture { url: string; title: string; html: string; text: string; capturedAt: string; } export interface PluginGameSourceParsePagePayload { sourceId: string; externalId?: string; url?: string; page: PluginGameSourcePageCapture; locale?: string; } export interface PluginImportGame { id?: string; name: string; description?: string; cover?: string; developer?: string; version?: string; engine?: string; status?: string; completionStatus?: string; primaryProvider?: string; tags?: string[]; customTags?: string[]; screenshots?: string[]; releaseDate?: string | number; totalPlaytime?: number; isPartialData?: boolean; missingFields?: string[]; externalLinks?: Array<{ providerId: string; externalId: string; url?: string; }>; } export interface PluginImportResult { games: PluginImportGame[]; warnings?: Array<{ code: string; message: string; }>; } export interface PluginExportCompletion { completed: true; } export interface XLibraryPlugin { initialize?(context: PluginRuntimeContext, host: PluginHost): Promise | void; deactivate?(context: PluginRuntimeContext, host: PluginHost): Promise | void; invoke(invocation: PluginInvocation, host: PluginHost): Promise | unknown; } export declare function definePlugin(plugin: XLibraryPlugin): XLibraryPlugin; //# sourceMappingURL=index.d.ts.map