Skip to content

refactor(frontend): derive PaginatedResponse from the generated schema - #573

Open
hamza-56 wants to merge 2 commits into
mainfrom
hamza/refactor/drive-paginated-schema
Open

refactor(frontend): derive PaginatedResponse from the generated schema#573
hamza-56 wants to merge 2 commits into
mainfrom
hamza/refactor/drive-paginated-schema

Conversation

@hamza-56

@hamza-56 hamza-56 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

What

PaginatedResponse<T> in frontend/lib/drive.ts hand-duplicated the envelope of the generated PaginatedResponse_* schemas field for field, the same latent-drift pattern UserPluginState had before #567; the page shapes are now direct aliases of the generated schemas.

Changes

  • refactor(frontend): replace the hand-written PaginatedResponse<T> with PaginatedFolders / PaginatedFiles, direct Schema<...> aliases like every other type in the module (openapi-typescript emits one monomorphic paginated schema per item type, so there is no generic to preserve)
  • refactor(frontend): make fetchAllPages's fetcher parameter structural (just the items/total fields the loop reads), keeping it polymorphic without a named envelope type

How to Test

  1. cd frontend && bun run typecheck passes.
  2. make test.frontend passes (25 files, 212 tests).
  3. listFolders / listFiles return types are now exactly the generated schemas, so any backend change to the pagination envelope fails tsc after make frontend.build.api with no extra gate needed.

Notes

Type-level only, no runtime change. No migration, no env vars, no dependencies.

This description was written with the assistance of an LLM (Claude).

The hand-written generic duplicated the envelope of the generated
PaginatedResponse_* schemas field for field, the same latent-drift
pattern UserPluginState had. Map it off the generated schema (only the
item type is swapped back in, since openapi-typescript emits one
monomorphic schema per item type) and add a compile-time gate in
drive.test.ts checking the generic against both generated schemas, so a
backend change to the envelope fails tsc after regeneration.
The mapped generic still reconstructed the envelope; PaginatedFolders
and PaginatedFiles now alias the generated schemas exactly like every
other type in the module, so nothing is left to drift and the type-level
gate test is unnecessary. fetchAllPages keeps its generic via a
structural parameter (just the items/total fields the loop reads).
@hamza-56 hamza-56 self-assigned this Aug 5, 2026
@hamza-56
hamza-56 requested a review from abdulrafey1 August 5, 2026 22:59
@hamza-56

hamza-56 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

@claude-review

@claude

claude Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @hamza-56's task in 1m 3s —— View job


Review: refactor(frontend): derive PaginatedResponse from the generated schema

  • Read the changed file (frontend/lib/drive.ts)
  • Diff against origin/main & inspect callers
  • Verify generated schema names exist
  • Post review

Verdict: LGTM — approve. This is a clean, correct, low-risk type-level refactor that removes a real drift hazard.

What I checked

  • Generated schemas exist and match. PaginatedResponse_DriveFolderResponse_ and PaginatedResponse_DriveFileResponse_ are both emitted in frontend/lib/api/generated.ts (lines 1773 / 1796), each carrying { items, total, skip, limit } — so aliasing them via Schema<...> is exact, and the "one monomorphic schema per item type" comment is accurate.
  • No orphaned references. The removed PaginatedResponse<T> generic wasn't imported anywhere else — a repo-wide grep for PaginatedResponse outside generated.ts and drive.ts returns nothing, so no external consumer breaks.
  • fetchAllPages structural param is sound. The three callers (useFolderPicker.ts:36, DriveFilePicker.tsx:129/143, GoogleDrive.tsx:562) pass listFolders/listFiles directly. Their return types have items/total (plus extras), so they satisfy the narrowed { items: T[]; total: number } fetcher via structural typing, and T still infers correctly. Keeping this one polymorphic rather than tying it to a named envelope is the right call.
  • Consistency. The two new aliases now match the direct-alias style of every other type at the top of the module.

Minor / non-blocking

  • The data as PaginatedFolders / as PaginatedFiles casts paper over openapi-fetch's data: T | undefined. This is unchanged by the PR (the whole module already does this), so not a concern here — just noting the pattern persists.
  • Out of scope, but for a future pass: frontend/lib/tests/drive.test.ts sits under lib/tests/, which doesn't match vitest's include: ["tests/**/*.test.{ts,tsx}"] per CLAUDE.md — worth confirming it's actually being collected. Not this PR's doing.

Type-only, no runtime change, and the stated verification (typecheck + make test.frontend) is the right gate. Nice cleanup. 👍
· hamza/refactor/drive-paginated-schema

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.

2 participants