Skip to content

fix: serve public offerings catalog without listPublic - #1229

Merged
thlpkee20-wq merged 1 commit into
RevoraOrg:masterfrom
Deyanju23:fix/offerings-1073-public-catalog-fallback
Sep 29, 2026
Merged

thlpkee20-wq merged 1 commit into
RevoraOrg:masterfrom
Deyanju23:fix/offerings-1073-public-catalog-fallback

Conversation

@Deyanju23

Copy link
Copy Markdown

Closes #1073

What was incomplete

GET /api/offerings called offeringRepo.listPublic behind an optional check and answered a 500 (offeringRepo.listPublic not implemented) whenever a repository did not implement it, so the public catalog could never be served by repositories that only expose raw rows.

Change (src/routes/offerings.ts only)

  • Added an optional list(opts?: { status?: string }) => Promise<Offering[]> to OfferingRepo as a documented raw-row catalog source. listPublic remains preferred and unchanged.
  • Implemented the fallback path: the route applies the status filter, a stable created_at DESC, id ASC ordering, offset/limit windowing, and projects every row through toPublicOffering, so issuer_id, private_note and any other issuer-only field can never leak — even if a repository returns full rows.
  • total is now always page-independent on the fallback path: countPublic when available, otherwise the pre-pagination filtered count.
  • Bound response size: fallback page size defaults to PUBLIC_CATALOG_DEFAULT_LIMIT (100); limit above PUBLIC_CATALOG_MAX_LIMIT (1000) is rejected with 400 rather than silently clamped.
  • Kept the failure contract: no catalog source at all (listPublic and list both absent/non-function) logs at error level and returns a generic INTERNAL_ERROR 500, so repository topology is not disclosed.

Public contract

Response shape { offerings, total? }, 200 on success, 400 BAD_REQUEST for invalid/out-of-range limit/offset, generic 500 when no catalog source is wired are all unchanged. The only addition is the list fallback, which is additive and backwards compatible.

Security notes

  • Public projection is enforced route-side on the fallback path, so private columns cannot be exposed by a repository that returns them.
  • Invalid query input is rejected before any repository call (asserted in tests), avoiding amplified reads from untrusted callers.
  • The misconfiguration error is logged server-side with details and returned to clients as a generic message (not exposed).

Test evidence

npx jest src/routes/offerings.catalog.test.ts src/routes/offerings.test.ts → 2 suites passed, 14 tests passed

Focused file (src/routes/offerings.catalog.test.ts, 11 tests):

  • covers public catalog stable ordering and detail visibility rules
  • validates limit and offset correctly
  • handles unimplemented listPublic gracefully
  • handles database errors gracefully
  • projects raw rows to the public shape with stable ordering and totals (new)
  • applies pagination over the filtered, ordered rows (new)
  • honours a repository countPublic total when present (new)
  • bounds the response with the default page size when limit is omitted (new)
  • rejects out-of-range limit on the fallback path, repository never called (new)
  • returns a deterministic 500 when no catalog source is wired at all (new)
  • surfaces repository failures from the fallback source (new)

npx tsc --noEmit → no diagnostics in src/routes/offerings.ts (repo-wide pre-existing errors in unrelated files are untouched).
npx eslint src/routes/offerings.ts → no new findings (remaining no-explicit-any findings are pre-existing and unchanged).

The catalog route treated a missing `listPublic` as an unimplemented path and
returned a 500, so repositories exposing only raw rows could never serve the
public catalog. Add a documented `list` fallback that filters, stably orders and
paginates rows route-side, then projects each row to the public shape so
issuer-only fields cannot leak. Totals stay page-independent and the missing-
source case remains a deterministic generic 500.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@drips-wave

drips-wave Bot commented Sep 28, 2026

Copy link
Copy Markdown

@Deyanju23 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@thlpkee20-wq
thlpkee20-wq merged commit 9646547 into RevoraOrg:master Sep 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Offering behavior currently marked as incomplete

2 participants