import type { Bootstrap, AuditMode } from "./types.js"; export type BatchOp = | { action: "update"; id: string; fields: Partial<{ shopId: string | null; binId: string | null; price: number; thc: number; cbd: number; totalCannabinoids: number; containerWeight: number | null; purchaseDate: string }> } | { action: "checkout"; id: string; date: string } | { action: "checkin"; id: string; date: string; binId: string } | { action: "finish"; id: string; date: string; rating?: number; notes?: string } | { action: "gone"; id: string; date: string; reason: string; notes?: string }; async function request(path: string, init?: RequestInit): Promise { const res = await fetch(`/api${path}`, { ...init, headers: { "Content-Type": "application/json", ...(init?.headers ?? {}) }, }); if (!res.ok) { const text = await res.text(); throw new Error(`${res.status} ${res.statusText}: ${text}`); } return res.json() as Promise; } export const api = { bootstrap: () => request("/bootstrap"), // Catalog: products createProduct: (body: { sku: string; type: string; kind: "bulk" | "discrete"; strainId?: string | null; strainName?: string; brandId?: string | null; defaultThc?: number; defaultCbd?: number; defaultTotalCannabinoids?: number; }) => request<{ id: string }>("/products", { method: "POST", body: JSON.stringify(body) }), updateProduct: ( id: string, body: Partial<{ sku: string; type: string; kind: "bulk" | "discrete"; strainId: string | null; strainName: string; brandId: string | null; }>, ) => request<{ ok: true }>(`/products/${id}`, { method: "PATCH", body: JSON.stringify(body), }), deleteProduct: (id: string) => request<{ ok: true }>(`/products/${id}`, { method: "DELETE" }), updateStrain: ( id: string, body: Partial<{ name: string; defaultThc: number | null; defaultCbd: number | null; defaultTotalCannabinoids: number | null; notes: string | null; }>, ) => request<{ ok: true }>(`/strains/${id}`, { method: "PATCH", body: JSON.stringify(body), }), // Inventory items (instances) createInventoryItem: (body: { assetId: string; productId: string; shopId?: string | null; binId?: string | null; price: number; thc?: number; cbd?: number; totalCannabinoids?: number; weight?: number; containerWeight?: number | null; countOriginal?: number; unitWeight?: number; purchaseDate: string; }) => request<{ id: string; assetId: string }>("/inventory", { method: "POST", body: JSON.stringify(body), }), updateInventoryItem: ( id: string, body: Partial<{ shopId: string | null; binId: string | null; price: number; thc: number; cbd: number; totalCannabinoids: number; weight: number; containerWeight: number | null; countOriginal: number; unitWeight: number; purchaseDate: string; }>, ) => request<{ ok: true }>(`/inventory/${id}`, { method: "PATCH", body: JSON.stringify(body), }), finishInventoryItem: ( id: string, body: { date: string; rating?: number; notes?: string }, ) => request<{ ok: true }>(`/inventory/${id}/finish`, { method: "POST", body: JSON.stringify(body), }), markInventoryItemGone: ( id: string, body: { date: string; reason: string; notes?: string }, ) => request<{ ok: true }>(`/inventory/${id}/gone`, { method: "POST", body: JSON.stringify(body), }), checkoutInventoryItem: ( id: string, body: { date: string }, ) => request<{ ok: true }>(`/inventory/${id}/checkout`, { method: "POST", body: JSON.stringify(body), }), checkinInventoryItem: ( id: string, body: { date: string; binId: string; remainingWeight?: number }, ) => request<{ ok: true }>(`/inventory/${id}/checkin`, { method: "POST", body: JSON.stringify(body), }), reactivateInventoryItem: ( id: string, body: { binId: string }, ) => request<{ ok: true }>(`/inventory/${id}/reactivate`, { method: "POST", body: JSON.stringify(body), }), auditInventoryItem: ( id: string, body: { date: string; mode: AuditMode; value: number; confirmedBy?: string }, ) => request<{ ok: true }>(`/inventory/${id}/audit`, { method: "POST", body: JSON.stringify(body), }), batchInventory: (ops: BatchOp[]) => request<{ ok: true; count: number }>("/inventory/batch", { method: "POST", body: JSON.stringify({ ops }), }), // Catalog tables (brand/shop/bin) — unchanged createBrand: (name: string) => request<{ id: string; name: string }>("/brands", { method: "POST", body: JSON.stringify({ name }), }), updateBrand: (id: string, body: { name: string }) => request<{ id: string; name: string }>(`/brands/${id}`, { method: "PATCH", body: JSON.stringify(body), }), deleteBrand: (id: string) => request<{ ok: true }>(`/brands/${id}`, { method: "DELETE" }), createShop: (body: { name: string; location?: string }) => request<{ id: string; name: string; location: string | null }>("/shops", { method: "POST", body: JSON.stringify(body), }), updateShop: (id: string, body: { name?: string; location?: string | null }) => request<{ id: string; name: string; location: string | null }>(`/shops/${id}`, { method: "PATCH", body: JSON.stringify(body), }), deleteShop: (id: string) => request<{ ok: true }>(`/shops/${id}`, { method: "DELETE" }), createBin: (body: { name: string; capacity?: number; cadenceDays?: number }) => request<{ id: string; name: string; capacity: number; cadenceDays: number; lastChecked: string | null }>("/bins", { method: "POST", body: JSON.stringify(body), }), updateBin: (id: string, body: { name?: string; capacity?: number; cadenceDays?: number }) => request<{ id: string; name: string; capacity: number; cadenceDays: number; lastChecked: string | null }>(`/bins/${id}`, { method: "PATCH", body: JSON.stringify(body), }), deleteBin: (id: string) => request<{ ok: true }>(`/bins/${id}`, { method: "DELETE" }), completeBinCheck: ( binId: string, body: { date: string; verifiedItemIds: string[]; goneItemIds: string[] }, ) => request<{ ok: true; verified: number; gone: number }>(`/bins/${binId}/check`, { method: "POST", body: JSON.stringify(body), }), };