28 lines
1.3 KiB
TypeScript
28 lines
1.3 KiB
TypeScript
|
|
"use server";
|
||
|
|
|
||
|
|
import type { FillMode, GeneratePlanInput, GeneratePlanResult } from "@/app/types";
|
||
|
|
import { generatePlan } from "@/app/lib/planner";
|
||
|
|
import { sanitizeState } from "@/app/lib/sanitize";
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Server Actions.
|
||
|
|
//
|
||
|
|
// Note on the split: live cost recalculation runs in the BROWSER (same pure
|
||
|
|
// functions from lib/), so every slider tweak updates instantly with no round
|
||
|
|
// trip. Generation runs HERE so that, once real prices exist, the price API
|
||
|
|
// key and fetch live server-side only.
|
||
|
|
//
|
||
|
|
// Server Actions are public HTTP endpoints, so input goes through the same
|
||
|
|
// sanitizer as saved state (lib/sanitize.ts) rather than being trusted.
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export async function generateMealPlanAction(input: GeneratePlanInput): Promise<GeneratePlanResult> {
|
||
|
|
const state = sanitizeState(input?.state);
|
||
|
|
const fillMode: FillMode = input?.fillMode === "all" ? "all" : "empty";
|
||
|
|
const seed = Number.isFinite(input?.seed) ? Math.floor(input.seed) : Date.now();
|
||
|
|
|
||
|
|
// Real price lookups would go here: fetch → build a SnapshotPriceProvider
|
||
|
|
// → pass it through generatePlan/buildGroceryList.
|
||
|
|
return generatePlan(state, fillMode, seed);
|
||
|
|
}
|