From bcce40d2cbcc37b5c49337d6783f8573ce959931 Mon Sep 17 00:00:00 2001 From: Ben Stull Date: Sun, 7 Jun 2026 17:38:16 -0700 Subject: [PATCH] =?UTF-8?q?feat(slice3):=20listRFCs=20accepts=20facet=20se?= =?UTF-8?q?lections,=20returns=20{items,facets}=20(=C2=A722.4a)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/api.js | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) 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)) }