100 lines
3.8 KiB
TypeScript
100 lines
3.8 KiB
TypeScript
import { artifactFormBody } from '$lib/server/request-body.js';
|
|
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 artifactFormBody(request);
|
|
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: err.kind === 'invalid-release-version' ? 400 : 409 }
|
|
);
|
|
}
|
|
throw err;
|
|
}
|
|
}
|