// Shared parsing for the ProductRule-scoping params every scheduling route // (storefront + POS, availability + hold) accepts identically — kept here so // the four call sites don't each re-implement the same defensive JSON parsing. export interface CartLineParam { vendor?: string; productType?: string; } /** `cartLines` is a JSON-encoded array; malformed/missing input degrades to "no cart info" rather than erroring the request. */ export function parseCartLinesParam(raw: string | null | undefined): CartLineParam[] { if (!raw) return []; try { const parsed = JSON.parse(raw); if (!Array.isArray(parsed)) return []; return parsed .filter((entry): entry is Record => typeof entry === "object" && entry !== null) .map((entry) => ({ vendor: typeof entry.vendor === "string" ? entry.vendor : undefined, productType: typeof entry.productType === "string" ? entry.productType : undefined, })); } catch { return []; } } /** `productIds` is a comma-separated list of Shopify Product GIDs. */ export function parseProductIdsParam(raw: string | null | undefined): string[] { return parseGidListParam(raw); } /** Generic comma-separated Shopify GID list (products, variants, …). */ export function parseGidListParam(raw: string | null | undefined): string[] { if (!raw) return []; return raw .split(",") .map((id) => id.trim()) .filter(Boolean); }