const RESOURCE_NAMESPACE = Object.freeze(["resource", 1]); export const queryKeys = Object.freeze({ resource: Object.freeze({ all: () => RESOURCE_NAMESPACE, list: (filters = {}) => Object.freeze([...RESOURCE_NAMESPACE, "list", canonicalize(filters)]), /** @param {string} resourceId */ detail: (resourceId) => Object.freeze([...RESOURCE_NAMESPACE, "detail", String(resourceId)]), }), }); export const QUERY_REGISTRY = Object.freeze({ RESOURCE: Object.freeze({ namespace: RESOURCE_NAMESPACE, serialization: "canonical-object-order", identity: "no-pii-token-or-raw-url", invalidation: "resource namespace after successful mutation", version: 1, persistence: "disabled", }), }); /** @param {unknown} value @returns {unknown} */ export function canonicalize(value) { if (Array.isArray(value)) return value.map(canonicalize); if (value && typeof value === "object") { return Object.fromEntries( Object.entries(value) .sort(([left], [right]) => left.localeCompare(right)) .map(([key, item]) => [key, canonicalize(item)]), ); } return value; }