fix: Fixed tests

feat: Added RClone integration
feat: Implemented plugin settings
feat: Updated minimal store version
test: Fixed tests
feat: Moved store and igdb and es-de to their own plugins
This commit is contained in:
Simeon Radivoev 2026-04-17 21:21:14 +03:00
parent 444d8c4c27
commit c09fbd3dc8
Signed by: simeonradivoev
GPG key ID: 7611A451D2A5D37A
115 changed files with 4139 additions and 1502 deletions

View file

@ -2,10 +2,9 @@
import * as appSchema from '@schema/app';
import * as emulatorSchema from "@schema/emulators";
import { eq, inArray } from 'drizzle-orm';
import { db, emulatorsDb } from '../app';
import { db, emulatorsDb, plugins } from '../app';
import { cores } from '../emulatorjs/emulatorjs';
import { SERVER_URL } from '@/shared/constants';
import { findExecsByName } from '../games/services/launchGameService';
import { host } from '@/bun/utils/host';
import { findEmulatorPluginIntegration } from '../store/services/emulatorsService';
@ -54,7 +53,18 @@ export async function getRelevantEmulators ()
const groupedEmulators = Map.groupBy(emulators, ({ emulator }) => emulator);
const finalEmulators = await Promise.all(Array.from(groupedEmulators.entries()).map(async ([emulator, system_slug]) =>
{
const execPaths = await findExecsByName(emulator);
const execPaths: EmulatorSourceEntryType[] = [];
await plugins.hooks.emulators.findEmulatorSource.promise({ emulator, sources: execPaths });
const integrations = findEmulatorPluginIntegration(emulator, execPaths);
const storeEmulator = await plugins.hooks.store.fetchEmulator.promise({ id: emulator });
if (storeEmulator)
{
storeEmulator.validSources = execPaths;
storeEmulator.integrations = integrations;
return storeEmulator;
}
let platform: number | null | undefined = null;
const validSystemSlug = system_slug.find(s => s.system);
@ -75,7 +85,7 @@ export async function getRelevantEmulators ()
gameCount: 0,
isCritical: false,
validSources: execPaths,
integrations: findEmulatorPluginIntegration(emulator, execPaths)
integrations
};
return em;

View file

@ -1,12 +1,15 @@
import z from "zod";
import { SettingsSchema } from "@shared/constants";
import Elysia, { status } from "elysia";
import { config, customEmulators, taskQueue } from "../app";
import { config, customEmulators, plugins, taskQueue } from "../app";
import fs from 'node:fs/promises';
import { existsSync } from "node:fs";
import { InstallJob } from "../jobs/install-job";
import { move } from "fs-extra";
import { getRelevantEmulators } from "./services";
import type { JSONSchema7 } from "json-schema";
import ReloadPluginsJob from "../jobs/reload-plugins-job";
import { pluginZodRegistry } from "../plugins/plugin-manager";
export const settings = new Elysia({ prefix: '/api/settings' })
.get('/emulators/automatic', async () =>
@ -77,18 +80,59 @@ export const settings = new Elysia({ prefix: '/api/settings' })
drive: z.string().optional()
})
})
.get("/:id", async ({ params: { id } }) =>
.get("local/:id", async ({ params: { id } }) =>
{
const value = config.get(id);
return { value: value };
}, {
params: z.object({ id: z.keyof(SettingsSchema) }),
}).post('/:id',
}).post('local/:id',
async ({ params: { id }, body: { value }, }) =>
{
config.set(id, value);
}, {
params: z.object({ id: z.keyof(SettingsSchema) }),
body: z.object({ value: z.any() }),
});
})
.get('/definitions/:source', async ({ params: { source } }) =>
{
return plugins.plugins[source].plugin.settingsSchema?.toJSONSchema() as JSONSchema7;
})
.get('/actions/:source', async ({ params: { source } }) =>
{
const plugin = plugins.plugins[source]?.plugin;
if (!plugin.eventsNames) return [];
return plugin.eventsNames;
})
.post('/actions/:source/:id', async ({ params: { source, id } }) =>
{
return await plugins.plugins[source]?.plugin.onEvent?.(id);
})
.get('/:source/:id', async ({ params: { source, id } }) =>
{
return { value: plugins.plugins[source].config?.get(id) };
})
.put('/:source/:id', async ({ params: { source, id }, body: { value } }) =>
{
const plugin = plugins.plugins[source];
if (!plugin.config) return status("Not Found", "Plugin has no config");
const settingSchema = plugin.plugin.settingsSchema?.shape[id] as z.ZodObject;
if (!settingSchema) return status("Not Found", "Could not find setting");
const meta = pluginZodRegistry.get(settingSchema);
if (meta?.readOnly)
{
return;
}
plugin.config?.set(id, value);
if (meta?.requiresRestart)
{
await taskQueue.enqueue(ReloadPluginsJob.id, new ReloadPluginsJob());
}
},
{
body: z.object({ value: z.any() })
});