import { json } from '@sveltejs/kit'; import { createScript, isArtifactKind, ScriptError, type ArtifactKind, type ScopeType } from '$lib/server/fleet/scripts.js'; import { scriptCatalog } from '$lib/server/fleet/library-metadata.js'; function scopeTypeOrNull(v: FormDataEntryValue | null): ScopeType | null { if (v === null) return null; const s = String(v); if (s === '' || s === 'none') return null; if (s === 'game' || s === 'map') return s; throw new ScriptError(`invalid scope_type: ${s}`, 'invalid-scope'); } function kindOrDefault( v: FormDataEntryValue | string | null, fallback: ArtifactKind = 'script' ): ArtifactKind { if (v === null || v === undefined || v === '') return fallback; const s = String(v); if (!isArtifactKind(s)) throw new ScriptError(`invalid kind: ${s}`, 'invalid-kind'); return s; } export async function GET({ url }: { url: URL }) { const kindParam = url.searchParams.get('kind'); const kindFilter = kindParam ? (isArtifactKind(kindParam) ? kindParam : null) : null; const scripts = scriptCatalog(kindFilter ?? undefined); return json({ scripts }); } // Multipart POST — creates an artifact + version 1 from either an uploaded // file (script/plugin/baseline) or a text body (config overlay). Fields: // name, scopeType, scopeValue, notes, releaseVersion, kind (defaults to 'script'), // content (file). Configs may alternatively send `text` as a form field. export async function POST({ request, url }: { request: Request; url: URL }) { const form = await request.formData(); const name = String(form.get('name') ?? '').trim(); const notes = form.get('notes') ? String(form.get('notes')) : undefined; let scopeType: ScopeType | null; let kind: ArtifactKind; try { scopeType = scopeTypeOrNull(form.get('scopeType')); // Kind may come from the form or the query string (thin wrappers use ?kind=). const kindRaw = form.get('kind') ?? url.searchParams.get('kind'); kind = kindOrDefault(kindRaw); } catch (err) { return json({ ok: false, error: (err as Error).message }, { status: 400 }); } const scopeValueRaw = form.get('scopeValue'); const scopeValue = scopeValueRaw ? String(scopeValueRaw).trim() : null; let content: Buffer; let uploadedFilename: string | null = null; const file = form.get('content'); const text = form.get('text'); if (file instanceof File && file.size > 0) { content = Buffer.from(await file.arrayBuffer()); uploadedFilename = file.name; } else if (typeof text === 'string' && text.length > 0) { content = Buffer.from(text, 'utf8'); } else { return json({ ok: false, error: 'content file or text is required' }, { status: 400 }); } // Target rel path: for script/plugin, default to the upload filename. // For config/baseline, createScript() defaults to config.configTargetFile. const targetRelPath = kind === 'script' || kind === 'plugin' ? (uploadedFilename ?? undefined) : undefined; try { const { script, version } = createScript({ name, targetRelPath, scopeType, scopeValue, content, notes, releaseVersion: form.has('releaseVersion') ? String(form.get('releaseVersion')) : undefined, kind }); return json({ ok: true, script, versionId: version.id }); } catch (err) { if (err instanceof ScriptError) { return json({ ok: false, error: err.message, kind: err.kind }, { status: 409 }); } throw err; } }