mirror of
https://github.com/theodore-song/polymarket-analyst.git
synced 2026-07-28 00:17:46 +00:00
Compact cloud state for mobile
This commit is contained in:
+74
-2
@@ -2,6 +2,11 @@ import { get, put } from "@vercel/blob";
|
||||
|
||||
const STATE_PATH = process.env.PMA_STATE_PATH || "shared/state.json";
|
||||
const AGENTS_KEY = "pma_agents_v2";
|
||||
const SUG_KEY = "pma_suggestions_v5";
|
||||
const PAPER_KEY = "pma_paper_accounts_v1";
|
||||
const LIVE_KEY = "pma_live_readiness_v1";
|
||||
const AGENT_IDS = ["value", "momentum", "favorite", "longshot", "diversifier", "copycat", "whale1", "whale2", "whale3", "whale4"];
|
||||
const LIMITS = { closed: 80, history: 160, snapshots: 240, suggestions: 120, paperHistory: 120, paperSnapshots: 120, audit: 120 };
|
||||
|
||||
async function readJsonBlob() {
|
||||
const blob = await get(STATE_PATH, { access: "private" });
|
||||
@@ -19,6 +24,71 @@ function agentStateFromItems(items) {
|
||||
}
|
||||
}
|
||||
|
||||
function compactPortfolio(p) {
|
||||
if (!p || typeof p !== "object") return p;
|
||||
const out = { ...p };
|
||||
out.positions = Array.isArray(p.positions) ? p.positions : [];
|
||||
out.closed = Array.isArray(p.closed) ? p.closed.slice(-LIMITS.closed) : [];
|
||||
out.history = Array.isArray(p.history) ? p.history.slice(-LIMITS.history) : [];
|
||||
out.snapshots = Array.isArray(p.snapshots) ? p.snapshots.slice(-LIMITS.snapshots) : [];
|
||||
if (p.stopped && typeof p.stopped === "object") out.stopped = Object.fromEntries(Object.entries(p.stopped).slice(-80));
|
||||
return out;
|
||||
}
|
||||
|
||||
function compactAgentState(st) {
|
||||
if (!st || typeof st !== "object") return st;
|
||||
const out = { ...st, agents: {} };
|
||||
for (const id of AGENT_IDS) {
|
||||
out.agents[id] = compactPortfolio(st.agents && st.agents[id]);
|
||||
}
|
||||
out.whales = st.whales || {};
|
||||
return out;
|
||||
}
|
||||
|
||||
function compactSuggestion(s) {
|
||||
if (!s || typeof s !== "object") return s;
|
||||
return {
|
||||
market_id: s.market_id, question: s.question, event: s.event, url: s.url, category: s.category,
|
||||
clob_yes: s.clob_yes, clob_no: s.clob_no, yes_price: s.yes_price, no_price: s.no_price,
|
||||
fair_value: s.fair_value, edge: s.edge, side: s.side, entry_price: s.entry_price,
|
||||
conviction: s.conviction, volume: s.volume, volume_24hr: s.volume_24hr,
|
||||
days_to_resolution: s.days_to_resolution, drivers: s.drivers, rationale: s.rationale,
|
||||
};
|
||||
}
|
||||
|
||||
function compactSuggestions(payload) {
|
||||
if (!payload || typeof payload !== "object") return payload;
|
||||
return { ...payload, suggestions: (payload.suggestions || []).slice(0, LIMITS.suggestions).map(compactSuggestion) };
|
||||
}
|
||||
|
||||
function compactPaperStore(store) {
|
||||
if (!store || typeof store !== "object" || !store.accounts) return store;
|
||||
const accounts = {};
|
||||
for (const [id, acct] of Object.entries(store.accounts)) {
|
||||
accounts[id] = {
|
||||
...acct,
|
||||
history: Array.isArray(acct.history) ? acct.history.slice(-LIMITS.paperHistory) : [],
|
||||
snapshots: Array.isArray(acct.snapshots) ? acct.snapshots.slice(-LIMITS.paperSnapshots) : [],
|
||||
};
|
||||
}
|
||||
return { ...store, accounts };
|
||||
}
|
||||
|
||||
function compactItems(items) {
|
||||
const out = { ...(items || {}) };
|
||||
try { if (out[AGENTS_KEY]) out[AGENTS_KEY] = JSON.stringify(compactAgentState(JSON.parse(out[AGENTS_KEY]))); } catch {}
|
||||
try { if (out[SUG_KEY]) out[SUG_KEY] = JSON.stringify(compactSuggestions(JSON.parse(out[SUG_KEY]))); } catch {}
|
||||
try { if (out[PAPER_KEY]) out[PAPER_KEY] = JSON.stringify(compactPaperStore(JSON.parse(out[PAPER_KEY]))); } catch {}
|
||||
try {
|
||||
if (out[LIVE_KEY]) {
|
||||
const live = JSON.parse(out[LIVE_KEY]);
|
||||
if (Array.isArray(live.audit)) live.audit = live.audit.slice(-LIMITS.audit);
|
||||
out[LIVE_KEY] = JSON.stringify(live);
|
||||
}
|
||||
} catch {}
|
||||
return out;
|
||||
}
|
||||
|
||||
function conflictResponse(res, error, current) {
|
||||
return res.status(409).json({ ok: false, error, state: current });
|
||||
}
|
||||
@@ -31,7 +101,9 @@ export default async function handler(req, res) {
|
||||
}
|
||||
|
||||
if (req.method === "GET") {
|
||||
return res.status(200).json({ ok: true, state: await readJsonBlob() });
|
||||
const state = await readJsonBlob();
|
||||
if (state && state.items) state.items = compactItems(state.items);
|
||||
return res.status(200).json({ ok: true, state });
|
||||
}
|
||||
|
||||
if (req.method === "POST") {
|
||||
@@ -57,7 +129,7 @@ export default async function handler(req, res) {
|
||||
return conflictResponse(res, "This cycle already has a cloud result", current);
|
||||
}
|
||||
}
|
||||
const state = { version: 1, updated_at: new Date().toISOString(), items: body.items };
|
||||
const state = { version: 1, updated_at: new Date().toISOString(), items: compactItems(body.items) };
|
||||
await put(STATE_PATH, JSON.stringify(state), {
|
||||
access: "private",
|
||||
allowOverwrite: true,
|
||||
|
||||
Reference in New Issue
Block a user