import type {PluginGameSourceDraft, XLibraryPlugin} from '@xlibrary/plugin-sdk'; function getExternalId(input: {externalId?: string; url?: string}): string { if (input.externalId?.trim()) { return input.externalId.trim(); } const url = input.url ? new URL(input.url) : undefined; const slug = url?.pathname.split('/').filter(Boolean).at(-1); if (!slug) { throw new Error('A provider external id or URL is required'); } return decodeURIComponent(slug); } function createDraft(input: {externalId?: string; url?: string; name?: string; description?: string}): PluginGameSourceDraft { const externalId = getExternalId(input); return { externalId, canonicalUrl: input.url || `https://catalog.example/games/${encodeURIComponent(externalId)}`, name: input.name || `Example Game (${externalId})`, ...(input.description ? {description: input.description} : {}), tags: [], screenshotUrls: [], isPartial: false, missingFields: [], metadata: {}, }; } const plugin: XLibraryPlugin = { async invoke(invocation) { if (invocation.method === 'game-sources.search') { return { candidates: [{ identity: { externalId: 'example-game', canonicalUrl: 'https://catalog.example/games/example-game', }, title: 'Example Game', }], }; } if (invocation.method === 'game-sources.resolve') { return createDraft(invocation.payload); } if (invocation.method === 'game-sources.refresh') { return { ...createDraft({ externalId: invocation.payload.externalId, url: invocation.payload.url, name: invocation.payload.game.name, description: 'Refreshed from My Game Catalog.', }), version: invocation.payload.game.version || '1.0.0', changedFields: ['description', 'version'], }; } if (invocation.method === 'game-sources.parse-page') { return createDraft({ externalId: invocation.payload.externalId, url: invocation.payload.page.url, name: invocation.payload.page.title, description: invocation.payload.page.text.slice(0, 1_000), }); } throw new Error(`Unsupported plugin method: ${invocation.method}`); }, }; export default plugin;