feat(lists): read and show the list cap on every capped list

Twelve routes answer a capped list with meta.truncated / meta.limit on
the envelope, and the web client read only data, so no surface said a
list had stopped short. apiGetList / apiPostList are now the one client
reader of the cap and ListCapNotice the one line that shows it; every
capped list on the web reads its cap and shows the notice under the list,
the paged readers (side effects, illness episodes) stop on the route's
answer instead of a full-page guess, and the ECG list moves its five
readers onto one hook. The record activity feed sent its cap twice, in
data and on the envelope; it rides the envelope alone now. A guard
derives the capped routes from the tree and binds each to a client that
reads its cap.
This commit is contained in:
Marc-André Bombeck committed 2026-10-20 10:04:11 +02:00
1 parent be79603d53
commit dc5120b59a
49 files changed
+574 -204

No files matched your search

+3 -9
View File
@@ -142,13 +142,9 @@ export const GET = apiHandler(async () => {
createdAt: row.createdAt.toISOString(),
}));
// Exact: one row past the cap was asked for, so a list that is exactly
// full no longer reads as cut.
const truncated = cap.truncated;
annotate({
action: { name: "sharing.activity.list" },
meta: { entry_count: entries.length, truncated },
meta: { entry_count: entries.length, truncated: cap.truncated },
});
return apiListSuccess(
@@ -157,11 +153,9 @@ export const GET = apiHandler(async () => {
// The bound the view states out loud. Resolved here so the UI never has to
// hardcode a number the operator can change.
retentionDays,
// Whether the list is everything inside that window, or its most recent
// hundred rows. The view says which; silence would let the oldest line
// read as the beginning.
truncated,
},
// Whether the list is everything inside that window, or its most recent
// hundred rows, rides the envelope like every capped list's (`meta`).
cap,
);
});