diff --git a/frontend/src/api.js b/frontend/src/api.js index f0535ce..2ea0f05 100644 --- a/frontend/src/api.js +++ b/frontend/src/api.js @@ -203,11 +203,27 @@ export async function createProject({ projectId, name, type, visibility, content // §22.4 (Plan B) / §22 S2: per-collection serving. With a projectId + a // collectionId, read the collection-scoped routes; with only a projectId, the // project default-collection compat path; with neither, the unscoped path. -export async function listRFCs(projectId, collectionId) { - if (projectId && collectionId) { - return jsonOrThrow(await fetch(`/api/projects/${projectId}/collections/${collectionId}/rfcs`)) +// §22.4a SLICE-3: faceted catalog. `opts.selections` is { field: string[] } +// (each non-empty array becomes repeated query params, OR within the field); +// `opts.malformed` toggles the malformed-only filter. Returns the full payload +// { items, facets } — callers read both. With no selections it behaves as the +// pre-SLICE-3 list (and a no-fields collection returns facets: {}). Facets are +// served only on the project/collection-scoped paths, not the unscoped one. +export async function listRFCs(projectId, collectionId, opts = {}) { + const { selections = {}, malformed = false } = opts + const qs = new URLSearchParams() + for (const [field, values] of Object.entries(selections)) { + for (const v of values) qs.append(field, v) } - const url = projectId ? `/api/projects/${projectId}/rfcs` : '/api/rfcs' + if (malformed) qs.set('malformed', 'true') + const query = qs.toString() + let base + if (projectId && collectionId) { + base = `/api/projects/${projectId}/collections/${collectionId}/rfcs` + } else { + base = projectId ? `/api/projects/${projectId}/rfcs` : '/api/rfcs' + } + const url = query ? `${base}?${query}` : base return jsonOrThrow(await fetch(url)) }