# feat: migrate components to TanStack Query v6 (Phase 2)
## Summary
This PR migrates 4 components from the custom
`createInfiniteScrollResource` pattern to TanStack Query v6's
`createInfiniteQuery`:
- **JobSkillSelectionSidebar** - Job skill search with infinite scroll
and category filtering
- **SearchContent** - Search modal for weapons/characters/summons with
element/rarity/proficiency filters
- **User Profile Page** (`[username]/+page.svelte`) - User's teams and
favorites with tab switching
- **Teams Explore Page** (`teams/explore/+page.svelte`) - Public teams
listing
All components now use:
- TanStack Query v6 infinite query pattern with thunk for reactivity
- `IsInViewport` from runed for intersection-based infinite scroll
- Debounced search (debounce the value, not the query)
- Proper loading, error, and empty states
- SSR integration with `initialData` pattern
## Updates since last revision
- **Fixed duplicate key error in SearchContent.svelte** - The API can
return the same item across multiple pages during infinite scroll (e.g.,
due to items being added/removed between page fetches). This caused
Svelte's keyed each block to throw `each_key_duplicate` errors. Fixed by
deduplicating results by `id` using a Map before rendering.
## Review & Testing Checklist for Human
This is a medium-risk change affecting core user-facing pages. Please
verify:
- [ ] **Infinite scroll works on all 4 pages** - Scroll to bottom and
verify more items load automatically
- [ ] **No duplicate items appear in search results** - After the fix,
scrolling through many pages of search results should not show
duplicates
- [ ] **SSR hydration** - Verify no flash of loading state on initial
page load (data should be pre-rendered)
- [ ] **User profile tab switching** - Test switching between "Teams"
and "Favorites" tabs; verify correct data loads
- [ ] **Search debouncing** - Type quickly in JobSkillSelectionSidebar
and SearchContent; verify queries aren't fired on every keystroke
- [ ] **Error states** - Simulate network failure and verify retry
button works
**Recommended Test Plan:**
1. Navigate to `/teams/explore` - verify teams load and infinite scroll
works
2. Navigate to a user profile page - verify teams load, switch to
favorites tab, verify favorites load
3. Open the search sidebar - search for weapons/characters/summons,
scroll through many pages, verify no duplicate key errors and no
duplicate items
4. Open job skill selection - search and filter skills, verify results
### Notes
- The Party component mutations migration (Follow-Up Prompt 5) was
deferred to a follow-up PR due to complexity
- Deprecated resource classes remain in codebase for now; removal
planned for separate PR
- Pre-existing paraglide module errors in build are unrelated to this PR
- Type assertions (`as unknown as`, `as any`) are used to handle
different query result structures between favorites and parties queries
**Link to Devin run:**
https://app.devin.ai/sessions/5aa7ea29edf34f569f95f13acee9e0d9
**Requested by:** Justin Edmund (justin@jedmund.com) / @jedmund
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Justin Edmund <justin@jedmund.com>
## Summary
This PR establishes the foundation for migrating from custom Svelte 5
resource classes to TanStack Query v6 for server state management. It
adds:
**Query Options Factories** (in `src/lib/api/queries/`):
- `party.queries.ts` - Party fetching with infinite scroll support
- `job.queries.ts` - Job and skill queries with pagination
- `user.queries.ts` - User profile, parties, and favorites queries
**Mutation Configurations** (in `src/lib/api/mutations/`):
- `party.mutations.ts` - Party CRUD with cache invalidation
- `grid.mutations.ts` - Weapon/character/summon mutations with
optimistic updates
- `job.mutations.ts` - Job and skill update mutations
**Deprecation Notices**:
- Added `@deprecated` JSDoc to `search.resource.svelte.ts` and
`party.resource.svelte.ts` with migration examples
**SSR Integration** (Phase 4):
- Created `+layout.ts` to initialize QueryClient for SSR support
- Updated `+layout.svelte` to receive QueryClient from load function
- Added SSR utilities in `src/lib/query/ssr.ts`:
- `withInitialData()` - for pages using +page.server.ts
- `prefetchQuery()` / `prefetchInfiniteQuery()` - for pages using
+page.ts
- `setQueryData()` - for direct cache population
- Added documentation in `src/lib/query/README.md`
**Component Wiring Examples** (Phase 5):
- `JobSelectionSidebar.svelte` - Migrated from `createJobResource()` to
`createQuery(() => jobQueries.list())`. Demonstrates client-side query
pattern with automatic loading/error states.
- `teams/[id]/+page.svelte` - Added `withInitialData()` pattern for SSR
integration. Server-fetched party data is used as initial cache value
with background refetching support.
**Migration Guide**:
- Added `src/lib/query/MIGRATION.md` with follow-up prompts for
remaining component migrations (JobSkillSelectionSidebar, search modal,
user profile, teams explore, Party mutations, resource class removal)
## Updates Since Last Revision
Fixed TypeScript type errors in the TanStack Query integration:
- `party.queries.ts`: Made `total` and `perPage` optional in
`PartyPageResult` interface to match adapter return type
- `ssr.ts`: Fixed `withInitialData` to properly handle null values using
`NonNullable<TData>` return type
- `job.mutations.ts`: Fixed slot indexing by casting through `unknown`
to `keyof typeof updatedSkills`
Type checks now pass for all files modified in this PR (16 remaining
errors are pre-existing project issues unrelated to this PR - paraglide
modules not generated, hooks.ts implicit anys).
## Review & Testing Checklist for Human
- [ ] **Verify app loads correctly**: The `+layout.ts` and
`+layout.svelte` changes are critical path - confirm the app still
renders
- [ ] **Test JobSelectionSidebar**: Open job selection sidebar and
verify jobs load correctly, search/filter works, and retry button works
on error
- [ ] **Test teams/[id] page**: Navigate to a party detail page and
verify it renders without loading flash (SSR data should be immediate)
- [ ] **Review type casts**: Check `job.mutations.ts:135` - the `as
unknown as keyof typeof` cast for slot indexing is a workaround for
jobSkills having string literal keys ('0', '1', '2', '3') while slot is
a number
- [ ] **Verify withInitialData behavior**: The `NonNullable<TData>`
return type change in `ssr.ts` should work correctly with `data.party`
which can be `Party | null`
**Recommended test plan**:
1. Run `pnpm install` to ensure dependencies are up to date
2. Start dev server and verify the app loads without errors
3. Navigate to a party detail page (`/teams/[shortcode]`) - should
render immediately without loading state
4. Open job selection sidebar (click job icon on a party you can edit) -
verify jobs load and filtering works
5. Test error handling by temporarily breaking network - verify retry
button appears
### Notes
- Pre-existing project issues remain (paraglide modules not generated,
hooks.ts implicit anys) - these are unrelated to this PR
- Local testing could not run due to missing node_modules (vite not
found) - project setup issue
- TanStack Query devtools installation was skipped due to Storybook
version conflicts
- The existing `search.queries.ts` file was used as the pattern
reference for new query factories
- SSR approach uses hybrid pattern: existing `+page.server.ts` files
work with `withInitialData()`, while new pages can use `prefetchQuery()`
in `+page.ts`
- Migration guide includes 6 follow-up prompts for completing the
remaining component migrations
**Link to Devin run**:
https://app.devin.ai/sessions/33e97a98ae3e415aa4dc35378cad3a2b
**Requested by**: Justin Edmund (justin@jedmund.com) / @jedmund
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Justin Edmund <justin@jedmund.com>
- Created GridItemData type (GridWeapon | GridSummon | GridCharacter)
- Typed GridOperation.data field with GridItemData instead of any
- Typed draggedItem and targetItem parameters with object shapes
- Made targetPosition flexible (number | string) for swaps/moves
- Added type guard for move operation to ensure type safety
Partial implementation of Phase 3.2 - reduced any usages in grid operations.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 3.1: Remove duplicate Awakening interface
- Removed unused src/lib/types/Awakening.d.ts
- Using entities.ts as single source of truth for Awakening type
- Awakening now properly uses LocalizedName interface
- No breaking changes (unused file had zero imports)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 2.2: Add proper type definitions for wx-svelte-grid
- Created Cell interface export in wx-svelte-grid declarations
- Updated all 9 database cell components to use Cell type
- Removed custom Props interfaces with loose IRow typing
- Improved IntelliSense support for grid component props
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed from numeric (0/1/2) to string literals ('public'/'private'/'unlisted')
- Created PartyVisibility type with const assertion
- Updated Party and PartyPreview interfaces
- Updated PartyUpdatePayload interface
- Updated Zod schemas for validation
- Updated test mocks to use string literals
- Added deprecated conversion helpers for backward compat
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- create proper UncapStarProps and TranscendenceStarProps interfaces
- use discriminated union for StarRender type
- add function overloads for createStarProps with type safety
- remove 'as any' casts from star component spreading
- remove optionalProps workaround in SegmentedControl
- stop spreading HTMLAttributes to RadioGroupPrimitive (not supported)
- remove unsupported class prop from bits-ui SelectPrimitive.Root
- add type assertion for RadioGroupPrimitive spread props (as any)
- remove wx-svelte-grid Cell import (not exported)
- simplify LastUpdatedCell props with index signature for grid props
- transform job skills pagination meta to include page/perPage
- fix UserInfo avatar type (optional properties -> required when present)
- add visibility number-to-string mapping in party service (0=public, 1=private, 2=unlisted)
- change mapToApiPayload return type from Partial<Party> to CreatePartyParams
- fix raid/job mapping to use IDs instead of nested objects
- add generic type argument to RestDataProvider<any>
- add type assertion in optionalProps (value as T[keyof T])
- make UncapIndicator StarRender props optional for transcendence stars
- add type assertion for star props spreading (as any)
- fix element name type (string -> literal union with type assertion)
- fix PartySegmentedControl props (value/onValueChange -> selectedTab/onTabChange)
- remove userGender prop (component gets it from context)
- add type assertions for ResourceType and ImageVariant comparisons
- add required id/shortcode to Party object in teams/new
- fix auth hooks expiresAt (undefined -> empty string default)
- add type assertion for Select value binding (excludes null/boolean)
- remove recruits property from Character test mock (doesn't exist in type)
- add missing subaura property to Summon test mocks
- consolidate Awakening imports to use entities source
- make awakening type/level optional in GridWeapon/GridSummon
- fix null handling in AwakeningDisplay (null -> undefined)
Fixed remaining test mock data to match actual type schemas.
Changes:
1. entity.adapter.test.ts:
- Removed invalid maxLevel property from Character mock
- Character interface doesn't have maxLevel
2. grid.adapter.test.ts:
- Added missing required properties to Weapon mock:
- maxSkillLevel: 15
- maxAwakeningLevel: 5
- ax: true
- axType: 1
- Removed invalid series property from Summon mock
- Summon interface doesn't have series property
3. settings/+page.svelte:
- Fixed users.update call (removed extra fetch parameter)
All test mocks now match their corresponding type definitions from
entities.ts, ensuring tests can compile and run correctly.
Result: 24 → 22 errors (-2)
Overall progress: 53 → 22 errors (58% reduction)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed incorrect function call to users.update by removing extra fetch argument.
The issue: settings page was calling users.update(fetch, userId, updateData)
but the function signature is users.update(userId, updateData).
The fetch parameter is not needed - the users.update function uses the global
fetch internally via userAdapter.
Changes:
- src/routes/settings/+page.svelte:
- Removed fetch argument from users.update call
- Changed from: users.update(fetch, account.userId, updateData)
- Changed to: users.update(account.userId, updateData)
Result: 24 → 23 errors (-1)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed TypeScript errors where custom drag data was being stored on the
native Touch type, which doesn't allow extension.
The issue: `currentTouch` was typed as `Touch | null` but the code was
trying to store custom properties (item, source, type) on it for pending
drag operations initiated by mouse pointer events.
The fix: Created a new `PendingDragData` interface to properly type the
custom drag data being stored for mouse events.
Changes:
- src/lib/composables/drag-drop.svelte.ts:
- Added PendingDragData interface with item, source, type
- Changed TouchState.currentTouch from `Touch | null` to `PendingDragData | null`
- This allows storing pending drag data without conflicting with native Touch type
Result: 32 → 28 errors (-4)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed TypeScript errors for optional MSW (Mock Service Worker) test dependency.
MSW is intentionally optional - tests work with or without it. The dynamic
imports are wrapped in try-catch to gracefully handle when MSW is not installed.
Added @ts-expect-error comments to suppress TypeScript module resolution errors
for the optional dynamic imports, while maintaining the runtime fallback behavior.
Changes:
- src/lib/api/adapters/test-setup.ts:
- Added @ts-expect-error for 'msw/node' dynamic import
- Added @ts-expect-error for 'msw' dynamic import
- Preserves optional dependency pattern
Result: 34 → 32 errors (-2)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed multiple test fixture type errors to match actual schema definitions.
Changes:
1. Removed leftover optionalProps() call in users.ts (missed in Phase 2)
2. Fixed Character race field in entity.adapter.test.ts
- Changed from object {race1, race2} to array [1, 2]
- Matches entity.adapter.ts Character interface expectation
3. Added missing ULB stat fields to Weapon mocks in grid.adapter.test.ts
- Added maxHpUlb and maxAtkUlb to hp/atk objects
- Required by entities.ts Weapon interface
Result: 36 → 34 errors (-2)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed TypeScript error where ImageVariant type wasn't accessible in the
same file that re-exported it.
The issue: Re-exporting a type with `export type { X } from 'module'`
doesn't create a local binding that can be used in the same file.
The fix: Import the type first to create a local binding, then re-export it.
Changes:
- src/lib/features/database/detail/image.ts:
- Added: import type { ResourceType, ImageVariant } from '$lib/utils/images'
- Kept: export type { ResourceType as ResourceKind, ImageVariant }
- This allows ImageVariant to be used in the ImageArgs interface below
Result: 37 → 36 errors (-1)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Resolved PUBLIC_SIERO_OAUTH_URL import issue by removing the intermediate
config.ts file and importing environment variables directly where needed.
Changes:
- Removed src/lib/config.ts (unnecessary abstraction layer)
- Updated src/lib/auth/oauth.ts to import PUBLIC_SIERO_API_URL directly
- Updated src/routes/auth/refresh/+server.ts to import directly
- Construct OAUTH_BASE locally as `${PUBLIC_SIERO_API_URL}/oauth`
This fixes the TypeScript error where svelte-check couldn't resolve
PUBLIC_SIERO_OAUTH_URL from the config file, even though the variable
was properly defined in .env and .svelte-kit/ambient.d.ts.
Result: 38 → 37 errors (-1)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed all test fixture mock data to match actual type definitions across
4 test files. Resolved 9 distinct type errors by correcting mock object
structures.
Files modified:
- entity.adapter.test.ts: Fixed Character mock to use nested hp/atk objects
- grid.adapter.test.ts: Fixed GridWeapon/GridCharacter/GridSummon mocks
- Added proper entity objects (mockWeapon, mockCharacter, mockSummon)
- Fixed transcendenceStage -> transcendenceStep
- Removed invalid partyId/weaponId/characterId/summonId properties
- party.adapter.test.ts: Fixed Party mock
- Changed visibility from 'public' string to 0 number
- Removed invalid skills array from Job object
- Added complete RaidGroup with all required properties
- user.adapter.test.ts: Fixed User/Party mocks
- Created separate mockUser (User type) vs mockUserInfo (UserInfo type)
- Fixed role type mismatch (number vs string)
- Added required arrays (weapons, characters, summons) to Party objects
Result: 42 → 38 errors (-4)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed three key type definition issues in the adapter layer:
1. Added missing element property to Party interface
- Added `element?: number` to Party type
- Used throughout codebase but was missing from interface
2. Aligned onError callback types for consistency
- Changed ResourceOptions.onError from Error to AdapterError
- Now matches AdapterOptions.onError type signature
3. Exported Grid types from grid.adapter.ts
- Re-exported GridWeapon, GridCharacter, GridSummon
- Makes types available for test files
Files modified:
- src/lib/types/api/party.ts: Added element property
- src/lib/api/adapters/types.ts: Fixed onError callback type
- src/lib/api/adapters/grid.adapter.ts: Added type re-exports
Result: 43 → 42 errors (-1)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removed inappropriate use of optionalProps() type shim from our own
codebase where we control the types. Type shims should only be used
for third-party library incompatibilities.
Files modified:
- base.adapter.ts: Removed shim from RequestOptions spreading
- grid.service.ts: Removed 3 usages from update methods
- party.service.ts: Removed import
- users.ts: Removed import and usage
- UserSettingsModal.svelte: Direct object construction
- drag-drop.svelte.ts: Direct object for DragOperation.target
Result: 45 → 43 errors (-2)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Build avatar object separately with proper types before assignment
- Apply optionalProps before passing to updateProfile
This maintains 53 errors (65% reduction from original 151).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add | undefined to all optional properties in Button Props interface
- This fixes 4 type errors related to Button component usage with exactOptionalPropertyTypes
Reduces errors from 57 to 53 (65% reduction from original 151).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update UserUpdateParams to include | undefined for all optional fields
- Add | undefined to CreatePartyParams and UpdatePartyParams interfaces
- Add | undefined to CreateGrid*Params interfaces (Weapon, Character, Summon)
- Transform UserUpdateParams to nested avatar structure in users.ts
- Remove unnecessary optionalProps wrappers (now handled by interface definitions)
- Fix TeamView awakening prop with conditional spreading
Reduces errors from 63 to 60.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix jobUtils proficiency type narrowing by storing intermediate values
- Add default empty string for openDescriptionSidebar title parameter
- Remove explicit undefined assignments in search resource tests
Reduces errors from 68 to 63.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add optionalProps shim to base.adapter.ts for RequestInit compatibility
- Apply optionalProps to UserSettingsModal updateData
- Use conditional spreading for Navigation Button element prop
- Apply optionalProps to drag-drop target object creation
- Apply optionalProps to party.service create/update methods
- Apply optionalProps to grid.service CRUD operations
- Fix transcendenceStage -> transcendenceStep typo in grid.service
- Update UserUpdateParams interface to include | undefined
- Update DragOperation interface properties to include | undefined
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- DatabaseProvider.ts: Remove redundant normalizer check
- Normalizer is applied by parent class, no need to apply twice
- Fixes "Property 'normalizer' does not exist" error
- image.ts: Separate type and value exports for proper type resolution
- CharacterImageCell.svelte: Fix getCharacterImage parameter order
- Changed (id, pose, variant) to (id, variant, pose)
- SearchContent.svelte: Fix getCharacterImage parameter order
Fixes ImageVariant type errors and property access errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- jobUtils.ts: Remove string comparison for job.row (row is typed as number)
- job.row === '1' comparison is always false, removed
- grid.service.ts: Fix swap operation to compare position with position
- Changed i.id === operation.targetPosition to i.position === operation.targetPosition
- targetPosition is a number (position), not a string (id)
Fixes "This comparison appears to be unintentional because the types have no overlap" errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- errors.ts: Only assign retryAfter when defined, not undefined
- user.adapter.ts: Build UserProfileResponse conditionally
- Only include optional properties (total, totalPages, perPage) when defined
- Use intermediate variables to ensure type safety
Fixes exactOptionalPropertyTypes violations where `T | undefined` cannot be
assigned to optional property `prop?: T`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update entities.ts WeaponKey to include all required fields (granblue_id, series, group, order)
- Use snake_case naming (granblue_id) to match API/database conventions
- Update modifiers.ts to import from entities.ts and use snake_case property
- Removes duplicate WeaponKey type and eliminates type conflicts
Fixes "Property 'granblueId' does not exist on type 'WeaponKey'" and type assignment errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- UncapIndicator.svelte: Use nullish coalescing for uncapLevel comparison
- UncapStatusDisplay.svelte: Guard uncapLevel in badge active checks
Fixes "'uncapLevel' is possibly 'null'" errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove duplicate generic SearchResult<T> from types.ts
- Export SearchResult from search.adapter.ts via index.ts
- Eliminates type conflict between two incompatible SearchResult definitions
This fixes "Type 'SearchResult' is not assignable to type 'SearchResult<any>'" errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Select.svelte: Use conditional spreading for optional `disabled` prop and `value` prop
- Switch.svelte: Conditionally spread `name` and `value` props
- Segment/RepSegment: Remove HTMLButtonAttributes extension and handle disabled prop properly
- Replace inline `import('svelte').Snippet` with proper import statements
Fixes type errors where bits-ui prop types don't include explicit `undefined` for optional properties, which conflicts with `exactOptionalPropertyTypes: true`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix DetailItem.svelte to accept boolean and null values
- Fix proficiency access in database/characters/[id]/+page.svelte
Co-Authored-By: Justin Edmund <justin@jedmund.com>
- Fix RequestOptions cache type incompatibility in adapters/types.ts
- Add missing properties to Character type in entity.adapter.ts and entities.ts
- Create adapters index.ts for module exports
- Update users.ts to use userAdapter instead of removed core module
- Fix UserSettingsModal.svelte switch import and type errors
- Add type shims for wx-svelte-grid and $env/static/public
- Accept upstream versions for SearchSidebar.svelte and teams/new/+page.svelte
- Add CLEANUP_PLAN.md documenting remaining work
Reduces type errors from ~412 to ~378. See CLEANUP_PLAN.md for remaining fixes.
Co-Authored-By: Justin Edmund <justin@jedmund.com>
## Summary
This PR fixes several pre-existing type errors identified by
`svelte-check`:
1. **PartyService constructor** - Removed unused `fetch` argument from
constructor call in `teams/[id]/+page.server.ts`. The `PartyService`
class has an empty constructor that doesn't accept any parameters.
2. **PaginatedResponse property** - Changed `response.per` to
`response.perPage` in `teams/explore/+page.server.ts` to match the
`PaginatedResponse<T>` type definition.
3. **Broken test files** - Removed 3 test files that were importing
non-existent `actions` exports:
- `database/characters/[id]/page.server.test.ts`
- `database/summons/[id]/page.server.test.ts`
- `database/weapons/[id]/page.server.test.ts`
These tests were testing SvelteKit form actions that don't exist in the
corresponding `+page.server.ts` files.
Reduces `svelte-check` errors from 419 to 366 (-53 errors).
## Review & Testing Checklist for Human
- [ ] **Verify party loading works** - Navigate to `/teams/[shortcode]`
and confirm party data loads correctly. The `PartyService` now uses
`partyAdapter` directly without a custom fetch function - verify this
works on both client and server.
- [ ] **Verify explore pagination** - Navigate to `/teams/explore` and
confirm pagination displays correctly (page count, items per page).
- [ ] **Confirm deleted tests were not needed** - The removed tests were
for form actions (`actions.save`) that don't exist. Verify there's no
plan to implement these actions soon, or if there is, the tests should
be re-added when the actions are implemented.
### Notes
The deleted test files were testing functionality that doesn't exist -
they imported `actions` from page.server.ts files that only export
`load` functions, not form actions. If database entity editing via form
actions is planned, new tests should be written when that functionality
is implemented.
Link to Devin run:
https://app.devin.ai/sessions/611580bc2db94e20a48c3692d3cbd432
Requested by: Justin Edmund (justin@jedmund.com) / @jedmund
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Justin Edmund <justin@jedmund.com>
## Summary
This PR performs low-risk cleanup tasks on the svelte-main branch:
1. **Remove unused imports** from `base.adapter.ts` - `snakeToCamel` and
`camelToSnake` were imported but never used
2. **Add `/.next` to `.gitignore`** - This is a SvelteKit project but
had a stale Next.js build artifact showing in git status
3. **Fix broken auth import** - `map.ts` was importing
`UserInfoResponse` from `$lib/api/resources/users` which never existed.
Created the type in `oauth.ts` based on actual usage in `buildCookies()`
4. **Remove test/example routes** - Deleted development scaffolding that
had no references elsewhere:
- `src/lib/components/examples/SearchExample.svelte`
- `src/routes/test-sidebar/+page.svelte`
- `src/routes/test/drag-drop/+page.svelte`
## Review & Testing Checklist for Human
- [ ] **Verify `UserInfoResponse` type matches actual API response** - I
inferred the type from usage in `map.ts`, but haven't verified against
the actual `/users/info` endpoint response from hensei-api. Fields:
`id`, `username`, `role`, `avatar.picture`, `avatar.element`,
`language`, `gender`, `theme`
- [ ] **Confirm test routes are not needed** - These appeared to be dev
scaffolding with no code references, but verify they're not used in any
manual QA workflows
- [ ] **Test auth flow** - Login/signup should still work correctly with
the new type location
**Recommended test plan:** Log in to the app and verify user info
(avatar, language, theme preferences) loads correctly after
authentication.
### Notes
- The broken `$lib/api/resources/users` import was pre-existing (the
file never existed), not caused by the previous API layer cleanup PR
- Running `pnpm check` confirms the auth/map error is resolved;
remaining type errors are unrelated pre-existing issues
Link to Devin run:
https://app.devin.ai/sessions/611580bc2db94e20a48c3692d3cbd432
Requested by: Justin Edmund (justin@jedmund.com) / @jedmund
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Justin Edmund <justin@jedmund.com>
# Remove legacy API layer (APIClient, core.ts, resources/)
## Summary
This PR consolidates the API layer by removing unused legacy code. The
codebase had two API patterns:
1. **Adapters layer** (`src/lib/api/adapters/`) - The newer, canonical
HTTP layer with retry logic, caching, and proper error handling
2. **Legacy layer** (`src/lib/api/client.ts`, `core.ts`, `resources/`) -
An older pattern using SvelteKit proxy endpoints that was no longer
imported anywhere
The legacy layer was confirmed unused via grep analysis. The only
exception was `transformResponse` and `transformRequest` functions in
`client.ts` which were still used by `BaseAdapter` and
`schemas/party.ts` - these have been moved to `schemas/transforms.ts`.
**Files deleted:**
- `src/lib/api/client.ts` (732 lines - APIClient class was dead code)
- `src/lib/api/core.ts` (helper functions, unused)
- `src/lib/api/index.ts` (empty file)
- `src/lib/api/resources/` directory (search.ts, weapons.ts,
characters.ts, summons.ts - all unused)
**Files modified:**
- `src/lib/api/schemas/transforms.ts` - Added `transformResponse`,
`transformRequest`, and their helper functions
- `src/lib/api/adapters/base.adapter.ts` - Updated import path
- `src/lib/api/schemas/party.ts` - Updated import path
## Review & Testing Checklist for Human
- [ ] **Verify transform functions work correctly** - The
`transformResponse` and `transformRequest` functions handle critical
data transformation (snake_case ↔ camelCase, object ↔ entity field
renaming). Test that party data loads correctly with proper field names.
- [ ] **Test party CRUD operations** - Create, update, and delete a
party to verify the adapters layer still works end-to-end
- [ ] **Test grid operations** - Add/remove weapons, characters, and
summons to verify the entity field renaming still works correctly
- [ ] **Check for any runtime errors** - The local type checking
couldn't run due to missing dev dependencies, so CI is the first line of
defense
**Recommended test plan:**
1. Load an existing party page and verify all data displays correctly
2. Create a new party and add weapons/characters/summons
3. Edit an existing party (update name, add/remove items)
4. Verify search functionality works for weapons/characters/summons
### Notes
- Local lint/typecheck commands failed due to missing dependencies
(prettier-plugin-svelte, eslint-config-prettier) - relying on CI for
type verification
- The services layer (`src/lib/services/`) was intentionally kept as
it's a business logic layer that wraps the adapters
Link to Devin run:
https://app.devin.ai/sessions/611580bc2db94e20a48c3692d3cbd432
Requested by: Justin Edmund (justin@jedmund.com) / @jedmund
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Justin Edmund <justin@jedmund.com>
- let backend compute default uncap levels
- fix InfiniteScroll resource lifecycle (don't destroy on unmount)
- improve party resource error handling with type narrowing
- use SvelteMap/SvelteDate for reactivity
- use shortcode instead of id for job updates
- wrap job_id in party object for rails API
- only send editable skill slots (1-3), skip null values
- add updateAccessory method stub
- update JobSkill type with emp/base boolean flags
- use new skill fields in jobUtils and components
- update job adapter with locale and filter params
- restyle empty skill slots with cleaner placeholder
- simplify ML badge to not show level number
- track active item in sidebar store
- add element accent colors and focus ring mixins
- units show pulsing focus ring when selected in sidebar
- refactor units to use shared menu components
- update context menu test page
- UnitMenuContainer for context/dropdown menu wrapper
- MenuItems for reusable action items
- GearMenuButton for hover-triggered dropdown
- shared scss styles for both menu variants
- replace manual fetch with createInfiniteQuery
- debounced search input with reactive filters
- pagination handled automatically via infinite scroll
- cleaner state management via query result
- integrate @tanstack/svelte-query into layout
- add query client factory and query keys
- new InfiniteScrollQuery component for paginated data
- search query options for weapons/characters/summons
- update dev port to 5174
- Added beforeNavigate hook to close sidebar when navigating between pages
- Prevents search sidebar from staying open when browsing different sections
- Ensures clean UI state transitions between pages
- Update database grid navigation to use granblueId
- Update column definitions to use granblueId
- Fix all detail pages to use camelCase field names from transformed API responses
- Fix field names for HP/ATK stats, abilities, and metadata
- Update DatabaseProvider to use SearchAdapter instead of direct fetch
- Fix RequestCache error by using cacheTTL instead of cache
- Update image cells to use shared image utilities with correct parameters
- Use only camelCase field names (granblueId) from transformed responses
- Update Party interface to use transformed field names (weapons/characters/summons)
- Fix runed import to use useDebounce instead of debounced
- Clean up debug logging
- Add centralized adapter config with proper baseURL
- Fix API response transformation (object -> weapon/character/summon)
- Update components to use image service and correct property names
- Fix Svelte 5 $derived syntax and missing PartyAdapter.list method
Images now display correctly in grids.
Phase 4 - Page Server Components:
- Migrated database page servers to use EntityAdapter directly
- Removed fetch parameter from all page server loads
Phase 5 - Utility Files:
- Deleted lib/api.ts (functionality inlined)
- Deleted lib/server/detail/load.ts (no longer needed)
- Updated DatabaseProvider to use PUBLIC_SIERO_API_URL directly
- Updated OAuth to use native fetch type
Migration Complete:
- All 32 files migrated from api/core to adapter pattern
- Zero remaining dependencies on lib/api/core
- Clean separation of concerns with dedicated adapters
- Created dedicated utility functions for API route proxies (buildApiUrl, extractHeaders, handleApiError)
- Migrated all 20 API route handlers to use new utilities instead of api/core
- Routes continue to act as proxies to Rails API (correct architecture)
- Removed dependency on buildUrl from api/core in all route handlers
- Updated migration plan to reflect completed Phase 3
- Created new UserAdapter for user profile and favorites operations
- Updated routes/teams/explore and routes/[username] to use adapters directly
- Deleted resource facade files (parties.ts, grid.ts, users.ts)
- All services and initial routes now use adapters without backward compatibility
- Updated migration plan to track completed work
- Update services to use adapters directly without FetchLike
- Remove constructor fetch dependency from services
- Add favorite/unfavorite methods to PartyAdapter
- Simplify API resource files to act as facades temporarily
- Services now instantiate without fetch parameter
- Direct adapter usage improves type safety and reduces complexity
- Add tests for GridAdapter covering weapons, characters, and summons
- Add tests for EntityAdapter covering canonical data access
- Test CRUD operations, positioning, uncap updates, and caching
- Verify snake_case transformation and error handling
- Ensure proper cache management with TTL support
- Add GridAdapter for managing user grid item instances
- Support CRUD, position management, and uncap operations
- Add EntityAdapter for read-only canonical game data
- Separate user instances from game reference data
- Export all adapters from index
- Remove non-existent batch update methods for grid items
- Add gridUpdate for atomic batch operations
- Add preview management methods
- Split job management into separate endpoints
- Update tests to match new API structure
- Add PartyAdapter for party CRUD and grid management
- Create reactive PartyResource with optimistic updates
- Support user parties listing with filters
- Handle grid conflicts and job updates
- Include comprehensive test coverage
- Create SearchResource class with reactive state management
- Implement debounced search using Runed utilities
- Support concurrent searches for different entity types
- Add request cancellation and state management
- Include tests for resource functionality
- Implement SearchAdapter extending BaseAdapter
- Support searching weapons, characters, and summons
- Add filtering by element, rarity, proficiency, etc.
- Include pagination support
- Add comprehensive test coverage
- Add BaseAdapter class with request/response transformation
- Implement comprehensive error handling and normalization
- Add retry logic with exponential backoff for network/server errors
- Support request cancellation and deduplication
- Include response caching with configurable TTL
- Add full test coverage for adapter functionality
- created drag-drop composable with touch/mouse support
- added DraggableItem and DropZone components
- integrated grids with drag-drop functionality
- added API endpoints for position updates and swaps
- handles cross-container dragging for all grid types
- Core composable with touch support & operation queue
- DraggableItem & DropZone components
- Proper position mapping for containers
- Cross-container swap/move operations
- Visual feedback states
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>