Conversation
There was a problem hiding this comment.
Pull request overview
This pull request refactors the API module to use a JavaScript Proxy pattern for automatically wrapping API calls with loading spinners. The refactoring separates the raw API request logic from spinner management while maintaining full backward compatibility with existing code.
Changes:
- Renamed
SPINNER_MESSAGEStoAPI_SPINNER_CONFIGfor clarity - Extracted core API logic into
rawApiRequest()function - Implemented Proxy-based API client with automatic spinner wrapping
- Added singleton pattern for API client instance caching
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const baseClient: ApiClient = { | ||
| request: rawApiRequest, | ||
| }; | ||
|
|
||
| return withSpinner(spinnerOpts, async () => { | ||
| const baseUrl = getBaseUrl(); | ||
| const token = getApiToken(); | ||
|
|
||
| const res = await fetch(`${baseUrl}/api/${path}`, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| Authorization: `Bearer ${token}`, | ||
| }, | ||
| body: JSON.stringify(body), | ||
| }); | ||
|
|
||
| if (!res.ok) { | ||
| let message = `API error: ${res.status} ${res.statusText}`; | ||
| try { | ||
| const err = (await res.json()) as ApiError; | ||
| if (err.message) message = `API error: ${err.message}`; | ||
| } catch {} | ||
| throw new Error(message); | ||
| } | ||
|
|
||
| const json = (await res.json()) as ApiResponse<T>; | ||
| return { data: json.data, pagination: json.pagination }; | ||
| return new Proxy(baseClient, { | ||
| get(target, property, receiver) { | ||
| const originalMethod = Reflect.get(target, property, receiver); | ||
|
|
||
| if (property === "request" && typeof originalMethod === "function") { | ||
| return <T>( | ||
| path: string, | ||
| body: object = {}, | ||
| ): Promise<PaginatedResult<T>> => { | ||
| const spinnerConfig = API_SPINNER_CONFIG[path]; | ||
|
|
||
| if (spinnerConfig) { | ||
| return withSpinner(spinnerConfig, () => | ||
| rawApiRequest<T>(path, body), |
There was a problem hiding this comment.
The Proxy implementation doesn't actually use the baseClient's request method. The proxy intercepts calls to request (line 102-119) but then calls rawApiRequest directly (lines 111, 117) instead of calling the originalMethod retrieved on line 100.
This makes the baseClient object on lines 94-96 effectively unused. Consider either:
- Using
originalMethodinstead of callingrawApiRequestdirectly (you may need to cast it for proper typing) - Simplifying by removing the proxy pattern and wrapping
rawApiRequestdirectly if the proxy isn't needed for extensibility
The current implementation works but is confusing because it appears to wrap a method while actually bypassing it.
Refactor api.ts to use a JavaScript Proxy that automatically wraps API calls with spinners based on the API_SPINNER_CONFIG mapping. This pattern: - Separates the raw API request logic from spinner wrapping - Uses a Proxy to intercept the request method and apply spinners - Maintains backward compatibility with existing apiRequest() usage - Caches the proxy-wrapped client as a singleton Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove unnecessary Proxy pattern that wasn't actually using the baseClient's request method. The proxy intercepted calls but then called rawApiRequest directly, making the baseClient effectively unused. Simplified to a straightforward wrapper function that applies spinners based on the API_SPINNER_CONFIG mapping. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
c1cdd86 to
d8887b3
Compare
# 1.0.0 (2026-03-25) ### Bug Fixes * broaden CI detection to handle all truthy values ([7dc2806](7dc2806)) * exclude dist from biome checks ([0dc49a3](0dc49a3)) ### Features * add API Spinner Proxy ([#17](#17)) ([a3bc75a](a3bc75a)) * add fuzzy reference resolution ([#19](#19)) ([6c1c6f9](6c1c6f9)) * add npm publishing, new agent skills, and skill auto-update ([#36](#36)) ([bcb2e75](bcb2e75)), closes [Doist/todoist-cli#176](Doist/todoist-cli#176) [Doist/bob-cli#17](Doist/bob-cli#17) [Doist/twist-cli#101](Doist/twist-cli#101) * add structured error formatting with codes and hints ([#18](#18)) ([17658d2](17658d2)) * implement OAuth PKCE browser login ([#20](#20)) ([b7f6eec](b7f6eec)), closes [#7](#7) [outline/outline#11254](outline/outline#11254) * improve oauth login inputs and callback UX ([#31](#31)) ([3011b28](3011b28))
|
🎉 This PR is included in version 1.0.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Closes #11
Summary
src/lib/api.tsto use a JavaScript Proxy that automatically wraps API calls with spinnersAPI_SPINNER_CONFIGobject mapping API paths to spinner messagesrawApiRequest()requestmethod and applies spinners based on configapiRequest()functionTest plan
npm run type-check- passesnpm test- all 35 tests pass🤖 Generated with Claude Code