Skip to content

[Feature][Medium] Fix type divergence, JSON.parse crash risk, token expiration, popup singleton, and monolithic component #69

Description

@numbers-official

Overview

Deep audit (2026-03-27) identified 6 new medium-priority improvement opportunities not covered by existing issues.


Finding 1: UserSettings Type Diverged from Actual StoredSettings

File: src/types/index.ts, lines 46-53 vs src/services/StorageService.ts, lines 18-34

UserSettings has 6 fields while the actual StoredSettings has 13. The types file gives developers a false picture of the settings schema.

Fix: Remove UserSettings from types/index.ts and consolidate on StoredSettings, or keep one canonical type imported everywhere.


Finding 2: JSON.parse() Without try/catch in StorageService

File: src/services/StorageService.ts, lines 135 and 169

const saved = JSON.parse(result.user_settings); // No try/catch
return JSON.parse(result.upload_queue);          // No try/catch

Corrupted storage (partial write during SW restart, user tampering) causes unhandled SyntaxError making the extension unusable with no recovery.

Fix: Wrap in try/catch, fall back to defaults, and auto-repair corrupted entries.


Finding 3: No Token Expiration or Renewal Handling

Files: src/services/ApiClient.ts, src/services/NumbersApiManager.ts

Auth token is validated once during initialize() and used indefinitely. No interceptor detects 401 responses after initialization. Expired tokens cause silent upload failures treated as generic errors.

Fix: Add 401 response interceptor in ApiClient.request() that clears token and emits AUTH_STATUS_CHANGED to the popup.


Finding 4: Popup Creates Separate NumbersApiManager Singleton from Service Worker

Files: src/popup/popup.tsx, line 50; src/popup/AuthForm.tsx, line 27

Popup's getNumbersApi() creates a separate instance from the service worker, causing duplicate API validation calls and divergent auth state.

Fix: Popup should request auth status via chrome.runtime.sendMessage({ type: 'GET_AUTH_STATUS' }) instead of instantiating its own manager.


Finding 5: 1032-Line Monolithic popup.tsx with 27 Inline Style Objects

File: src/popup/popup.tsx (1032 lines)

8 component functions and 27 inline style objects in a single file. Uses JS onMouseOver/onMouseOut handlers for hover effects instead of CSS :hover.

Fix: Extract components (SharePromptModal.tsx, AssetThumbnail.tsx, CaptureSection.tsx). Move styles to popup.css with CSS classes.


Finding 6: ApiClient.buildAuthHeaders Fragile Content-Type for FormData

File: src/services/ApiClient.ts, lines 71-83 and 128-137

buildAuthHeaders() always sets Content-Type: application/json. For FormData uploads, this is deleted later by coincidence. Fragile pattern prone to regression.

Fix: Have buildAuthHeaders not set Content-Type by default. Set it explicitly only for JSON bodies in request().


Generated by Heart Beat with Omni

Metadata

Metadata

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions