rebuild app as turbopack-first single-stack with internal api and openclaw tasks

This commit is contained in:
2026-02-23 23:38:06 -05:00
parent 5df09b714b
commit 6012dd3fcf
40 changed files with 1583 additions and 1578 deletions

View File

@@ -0,0 +1,29 @@
import { jsonError } from '@/lib/server/http';
import { withStore } from '@/lib/server/store';
type Context = {
params: Promise<{ id: string }>;
};
export async function DELETE(_request: Request, context: Context) {
const { id } = await context.params;
const numericId = Number(id);
if (!Number.isInteger(numericId) || numericId <= 0) {
return jsonError('Invalid watchlist id', 400);
}
let removed = false;
await withStore((store) => {
const next = store.watchlist.filter((item) => item.id !== numericId);
removed = next.length !== store.watchlist.length;
store.watchlist = next;
});
if (!removed) {
return jsonError('Watchlist item not found', 404);
}
return Response.json({ success: true });
}

View File

@@ -0,0 +1,71 @@
import type { WatchlistItem } from '@/lib/types';
import { asErrorMessage, jsonError } from '@/lib/server/http';
import { getStoreSnapshot, withStore } from '@/lib/server/store';
function nowIso() {
return new Date().toISOString();
}
export async function GET() {
const snapshot = await getStoreSnapshot();
const items = snapshot.watchlist
.slice()
.sort((a, b) => Date.parse(b.created_at) - Date.parse(a.created_at));
return Response.json({ items });
}
export async function POST(request: Request) {
try {
const payload = await request.json() as {
ticker?: string;
companyName?: string;
sector?: string;
};
if (!payload.ticker || payload.ticker.trim().length < 1) {
return jsonError('ticker is required');
}
if (!payload.companyName || payload.companyName.trim().length < 1) {
return jsonError('companyName is required');
}
let item: WatchlistItem | null = null;
await withStore((store) => {
const ticker = payload.ticker!.trim().toUpperCase();
const existingIndex = store.watchlist.findIndex((entry) => entry.ticker === ticker);
if (existingIndex >= 0) {
const existing = store.watchlist[existingIndex];
const updated: WatchlistItem = {
...existing,
company_name: payload.companyName!.trim(),
sector: payload.sector?.trim() || null
};
store.watchlist[existingIndex] = updated;
item = updated;
return;
}
store.counters.watchlist += 1;
const created: WatchlistItem = {
id: store.counters.watchlist,
user_id: 1,
ticker,
company_name: payload.companyName!.trim(),
sector: payload.sector?.trim() || null,
created_at: nowIso()
};
store.watchlist.unshift(created);
item = created;
});
return Response.json({ item });
} catch (error) {
return jsonError(asErrorMessage(error, 'Failed to create watchlist item'));
}
}