Initial commit of Descrybe v2 without local scratch artifacts.

Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
2026-08-09 22:47:43 +02:00
commit 8580c996c3
1285 changed files with 325780 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
/** 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<string>();
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<string, unknown> {
const productIds = normalizeProductIds(input.productIds ?? []).slice(0, MAX_SYNC_PRODUCT_IDS);
if (productIds.length > 0) {
return { product_ids: productIds };
}
const body: Record<string, unknown> = {
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;
}