mission-control/app/api/documents/route.ts
OpenClaw Bot 95060930b1 feat: Add machine token auth for Mission Control CLI
- Add mc_api_call_machine() function for MC_MACHINE_TOKEN auth
- Update mc_api_call() to use machine token when available
- Allows cron jobs to authenticate without cookie-based login
- No breaking changes - cookie auth still works for interactive use
- Also updates default API URL to production (was localhost)
2026-02-26 08:31:14 -06:00

149 lines
3.6 KiB
TypeScript

import { createClient } from '@supabase/supabase-js';
import { NextResponse } from 'next/server';
function getSupabaseServerClient() {
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
if (!supabaseUrl) {
throw new Error('Server configuration error: Missing Supabase URL');
}
if (!supabaseServiceKey) {
throw new Error('Server configuration error: Missing Supabase service key');
}
return createClient(supabaseUrl, supabaseServiceKey, {
auth: {
autoRefreshToken: false,
persistSession: false,
},
});
}
export async function POST(request: Request) {
try {
const supabase = getSupabaseServerClient();
const body = await request.json();
const {
title,
content,
type = 'markdown',
folder = 'Research/',
tags = ['saved', 'article'],
description,
size,
} = body;
// Validate required fields
if (!title || !content) {
return NextResponse.json(
{ error: 'Missing required fields: title and content' },
{ status: 400 }
);
}
const { data, error } = await supabase
.from('mission_control_documents')
.insert({
title,
content,
type,
folder,
tags,
description,
size,
})
.select()
.single();
if (error) {
console.error('Supabase error:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
return NextResponse.json({ document: data }, { status: 201 });
} catch (err: any) {
console.error('POST /api/documents error:', err);
return NextResponse.json(
{ error: err.message || 'Unknown error occurred' },
{ status: 500 }
);
}
}
export async function GET() {
try {
const supabase = getSupabaseServerClient();
const { data, error } = await supabase
.from('mission_control_documents')
.select('*')
.order('updated_at', { ascending: false });
if (error) {
console.error('Supabase error:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
return NextResponse.json({ documents: data || [] });
} catch (err: any) {
console.error('API error:', err);
return NextResponse.json(
{ error: err.message || 'Unknown error occurred' },
{ status: 500 }
);
}
}
export async function DELETE(request: Request) {
try {
const supabase = getSupabaseServerClient();
const { searchParams } = new URL(request.url);
let id = searchParams.get('id')?.trim();
if (!id) {
try {
const body = await request.json();
id = body?.id?.trim();
} catch {
// Ignore JSON parse errors; query param is preferred.
}
}
if (!id) {
return NextResponse.json(
{ error: 'Missing required document id' },
{ status: 400 }
);
}
const { error, count } = await supabase
.from('mission_control_documents')
.delete({ count: 'exact' })
.eq('id', id);
if (error) {
console.error('Supabase delete error:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
if (!count) {
return NextResponse.json(
{ error: 'Document not found' },
{ status: 404 }
);
}
return NextResponse.json({ success: true, id });
} catch (err: any) {
console.error('DELETE /api/documents error:', err);
return NextResponse.json(
{ error: err.message || 'Unknown error occurred' },
{ status: 500 }
);
}
}