/** Shared helpers for Shopify/Woo one-shot product sync scope. */ export const MAX_SYNC_PRODUCT_IDS = 500; export type ProductSyncScopeInput = { syncLimit: number; status?: string; category?: string; productIds?: readonly string[]; }; /** Deduplicate trimmed IDs; drop empties. Does not cap. */ export function normalizeProductIds(ids: readonly string[]): string[] { const out: string[] = []; const seen = new Set(); for (const raw of ids) { const id = String(raw ?? "").trim(); if (!id || seen.has(id)) continue; seen.add(id); out.push(id); } return out; } /** Toggle id in list; enforces max when adding. */ export function toggleProductId( list: readonly string[], id: string, max = MAX_SYNC_PRODUCT_IDS ): string[] { const key = String(id ?? "").trim(); if (!key) return normalizeProductIds(list); const current = normalizeProductIds(list); if (current.includes(key)) return current.filter((x) => x !== key); if (current.length >= max) return current; return [...current, key]; } /** * Build POST /sync JSON body. * When product_ids is non-empty: exact-ID sync only (omit sync_limit, status, category). */ export function buildProductSyncBody(input: ProductSyncScopeInput): Record { const productIds = normalizeProductIds(input.productIds ?? []).slice(0, MAX_SYNC_PRODUCT_IDS); if (productIds.length > 0) { return { product_ids: productIds }; } const body: Record = { sync_limit: Number.isFinite(input.syncLimit) && input.syncLimit > 0 ? Math.floor(input.syncLimit) : 200 }; const status = String(input.status ?? "").trim(); if (status) body.status = status; const category = String(input.category ?? "").trim(); if (category) body.category = category; return body; }