feat(events): generate main api client with orval#727
Conversation
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughMigrates event API to Zod-based DTOs and updates OpenAPI with operationIds and response schemas; replaces many web-local query hooks with generated API hooks and consolidates event types into a centralized types module; adjusts controllers, services, and components to use new DTOs/hooks and serializes timeline timestamps as ISO strings. Changes
Sequence Diagram(s)sequenceDiagram
participant Web as Web App
participant GenClient as Generated API Hooks
participant API as Server API (NestJS + Zod)
participant DB as Database
Web->>GenClient: call hook (e.g., useShowEventOverview({guildId,eventId}))
GenClient->>API: HTTP request /guilds/{guildId}/events/{eventId}/overview
API->>API: validate request & run controller -> service
API->>DB: query event/kill/ranking data
DB-->>API: return rows
API->>API: serialize to DTO (Zod schema) and stringify dates (ISO)
API-->>GenClient: 200 JSON response (matches OpenAPI/Zod schema)
GenClient-->>Web: return typed data via hook
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2bf493c8d9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| import { EventActionDialog } from "./components/dialogs/event-action-dialog"; | ||
| import { getEventStatusAtTimestamp } from "./utils"; | ||
| import { Skeleton } from "@lootlog/ui/components/skeleton"; | ||
| import { useListEvents } from "@/lib/api/generated/main/events/events"; |
There was a problem hiding this comment.
Generate Orval client before compiling web sources
This import depends on @/lib/api/generated/main/..., but the generated client is not present in the repository snapshot and this commit does not wire api:client:generate into the existing build/typecheck flow (the apps/web build script and turbo.json tasks still run without it). On a clean checkout, module resolution fails before runtime, so web builds/checks break until someone manually generates artifacts; please make generation part of the automated pipeline (or commit the generated files).
Useful? React with 👍 / 👎.
| const activeEventsGuildId = canViewEvents ? (guildId ?? "") : ""; | ||
|
|
||
| const { data: activeEvents } = useEvents({ | ||
| guildId: guildId ?? "", | ||
| activeOnly: true, | ||
| enabled: Boolean(canViewEvents), | ||
| }); | ||
| const { data: activeEvents } = useListEvents( | ||
| { | ||
| guildId: activeEventsGuildId, |
There was a problem hiding this comment.
Skip events query when viewer lacks event access
When canViewEvents is false, this code sets activeEventsGuildId to an empty string but still executes useListEvents, which triggers requests against an invalid guild path (effectively /guilds//events). The previous implementation guarded this with enabled: Boolean(canViewEvents), so this is a regression that causes avoidable failing API calls for users without events permissions; disable the query instead of passing an empty ID.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
apps/web/src/features/guild/events/utils/normalize-bonus-breakdown.ts (1)
24-33:⚠️ Potential issue | 🟠 MajorGuard entry field access after widening input to
unknown.Line 26 and Line 30 can throw when
bonusBreakdowncontainsnull/non-object entries, becauseentry.ruleId/entry.ruleNameare accessed directly. This introduces a runtime crash path in a defensive normalizer.Proposed fix
return { ruleId: - typeof entry.ruleId === "string" && entry.ruleId.length > 0 - ? entry.ruleId + typeof entry?.ruleId === "string" && entry.ruleId.trim().length > 0 + ? entry.ruleId.trim() : "rule", ruleName: - typeof entry.ruleName === "string" && entry.ruleName.trim().length > 0 + typeof entry?.ruleName === "string" && + entry.ruleName.trim().length > 0 ? entry.ruleName.trim() : null, points, };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/features/guild/events/utils/normalize-bonus-breakdown.ts` around lines 24 - 33, The normalizer currently accesses entry.ruleId and entry.ruleName directly (in the normalization logic inside normalize-bonus-breakdown.ts), which can throw if bonusBreakdown contains null or non-object entries; update the mapping logic to first verify each entry is an object (e.g., typeof entry === "object" && entry !== null) before reading properties, and only read/trim ruleId/ruleName when typeof entry.ruleId === "string" / typeof entry.ruleName === "string"; fallback to the existing defaults ("rule" and null) if the checks fail so the function (and any function that calls it) no longer crashes on null/non-object entries.apps/api/src/events/events-ranking.controller.ts (1)
168-171:⚠️ Potential issue | 🟠 MajorTwo 200 responses are still untyped (
@ApiResponse) after the Zod migration.
updateRankingPointsandupdateKillPointnow stand out as untyped success payloads, which degrades Orval output quality (unknown/weak types) in this PR’s generated-client flow.Use
@ZodResponse({ status: 200, type: ... })with DTOs matching the actual payloads, like the other updated endpoints.Also applies to: 552-555
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/api/src/events/events-ranking.controller.ts` around lines 168 - 171, The two endpoints updateRankingPoints and updateKillPoint still use generic `@ApiResponse`({status: 200}) and should be converted to use `@ZodResponse`({ status: 200, type: ... }) like the other migrated endpoints; replace the untyped `@ApiResponse` decorators on the methods updateRankingPoints and updateKillPoint with `@ZodResponse` decorators that reference the proper Zod DTO schemas (create or reuse the matching response DTO/zod schema for the actual payload shape) so Orval generates strong types for those success responses.apps/api/openapi.yaml (1)
3292-3315:⚠️ Potential issue | 🟠 Major
updateRankingPointsis still undocumented as a mutation contract.The spec says this PATCH applies a signed delta, but it has neither a
requestBodynor a typed200payload. Orval will generate an untyped/void mutation for one of the newly promoted event operations, which undercuts the client-generation work in this PR.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/api/openapi.yaml` around lines 3292 - 3315, The OpenAPI operation updateRankingPoints is missing a requestBody and a typed 200 response; add a requestBody (application/json) with a schema describing the signed delta payload (e.g., fields like signer, signature, delta, reason) and update the "200" response to include a JSON schema for the updated Ranking (or a defined component schema reference such as '#/components/schemas/Ranking' or '#/components/schemas/RankingUpdateResponse') so Orval generates a typed mutation; ensure the operationId updateRankingPoints remains and reference any existing component schemas or create new ones under components/schemas for reuse.
🧹 Nitpick comments (8)
apps/web/src/features/guild/events/types/api.ts (1)
12-18: KeepMemberfield presence aligned with API DTO shape.
avatarandrolesare nullable/array fields in the backend response schema, but still present keys. Marking them optional here weakens type guarantees unnecessarily.Suggested type alignment
export type Member = { id: number; name: string; - avatar?: string | null; + avatar: string | null; userId: string; - roles?: MemberRole[]; + roles: MemberRole[]; };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/features/guild/events/types/api.ts` around lines 12 - 18, The Member type currently marks avatar and roles as optional which loosens type guarantees; update the Member type (symbol: Member) so those keys are required but allow null to match the API DTO shape (e.g., use avatar: string | null and roles: MemberRole[] | null) so the fields are always present in responses but may be null, and adjust any consuming code that assumed they could be undefined.apps/web/src/features/guild/events/hooks/queries/use-event-settings.ts (1)
13-15: Remove unnecessary type assertion and rely on generated function typing.The cast
as Promise<EventSettingsResponseDto>on line 13–15 is likely redundant. The Orval configuration usesincludeHttpResponseReturnType: falseand the OpenAPI schema defines the endpoint to returnEventSettingsResponseDtodirectly, so the generatedeventsSettingsControllerGetSettingsfunction should already be properly typed to returnPromise<EventSettingsResponseDto>. Using the generated type directly eliminates unnecessary assertions and improves type safety.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/features/guild/events/hooks/queries/use-event-settings.ts` around lines 13 - 15, The call to eventsSettingsControllerGetSettings is using an unnecessary type assertion "as Promise<EventSettingsResponseDto>"; remove that cast and let TypeScript use the generated function's return type directly (i.e., pass the guildId to eventsSettingsControllerGetSettings(...) without the "as Promise<EventSettingsResponseDto>" assertion) so the code relies on the Orval-generated typing for EventSettingsResponseDto and avoids an unsafe redundant cast.apps/web/src/features/guild/events/hooks/mutations/use-create-event.ts (1)
30-37: NormalizeguildIdonce and reuse it for URL + query key.Line 30 uses raw
guildId, while Line 37 falls back to"". This can desync request target vs invalidation key in edge cases. Prefer a single normalized variable reused in both places.Proposed patch
export const useCreateEvent = () => { - const guildId = useGuildId(); + const guildId = useGuildId(); + const normalizedGuildId = guildId ?? ""; const queryClient = useQueryClient(); const { client } = useApiClient(); return useMutation<Event, Error, CreateEventData>({ mutationFn: async (data) => { const response = await client.post<Event>( - `/guilds/${guildId}/events`, + `/guilds/${normalizedGuildId}/events`, data, ); return response; }, onSuccess: () => { queryClient.invalidateQueries({ - queryKey: getListEventsQueryKey({ guildId: guildId ?? "" }), + queryKey: getListEventsQueryKey({ guildId: normalizedGuildId }), }); }, }); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/features/guild/events/hooks/mutations/use-create-event.ts` around lines 30 - 37, Normalize guildId once into a local constant (e.g., normalizedGuildId = guildId ?? "") at the top of the mutation and use that single variable for both the POST URL `/guilds/${normalizedGuildId}/events` and the invalidate call `getListEventsQueryKey({ guildId: normalizedGuildId })` so the request target and query key cannot diverge; update references inside the mutation (the URL string and queryClient.invalidateQueries call) to use the normalizedGuildId and remove the inline fallback.apps/web/src/components/layout/guilds-sidebar-nav.tsx (1)
35-44: Gate theuseListEventsquery with theenabledoption to prevent empty-guildId requests.Lines 37–44 execute
useListEventsunconditionally even whencanViewEventsis false. Use theenabledoption to skip the query:const { data: activeEvents } = useListEvents( { guildId: activeEventsGuildId, }, { activeOnly: "true", enabled: canViewEvents, // Add this }, );This aligns with the pattern used elsewhere in the file and prevents unnecessary requests with an empty guildId.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/components/layout/guilds-sidebar-nav.tsx` around lines 35 - 44, The useListEvents query is called unconditionally which triggers requests with an empty guildId; update the useListEvents call that uses activeEventsGuildId so it includes the query option enabled: canViewEvents (i.e., add enabled: canViewEvents to the second options object) so the hook is skipped when canViewEvents is false; this touches the useListEvents invocation and the activeEventsGuildId logic in guilds-sidebar-nav.tsx.apps/web/src/features/guild/events/hooks/queries/use-kill-timeline.ts (1)
30-36: Remove the forced promise cast to keep strict API typing.Line 36 masks mismatches between generated API output and
MapTimelineData[]. Let inference carry the return type directly fromeventsMonitoringControllerGetKillTimelineData.Proposed refactor
queryFn: () => eventsMonitoringControllerGetKillTimelineData({ guildId: guildId ?? "", eventId, heroId, killId, - }) as Promise<MapTimelineData[]>, + }),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/features/guild/events/hooks/queries/use-kill-timeline.ts` around lines 30 - 36, The queryFn in use-kill-timeline.ts is force-casting the API call to MapTimelineData[] which hides type mismatches; remove the "as Promise<MapTimelineData[]>" cast and let TypeScript infer the return type from eventsMonitoringControllerGetKillTimelineData (keeping the same args: guildId, eventId, heroId, killId) so any generated API/type mismatch surfaces correctly and strict typing is preserved.apps/web/src/features/guild/events/hooks/queries/use-event-member-kill-history.ts (1)
50-58: Avoid force-casting the generated API promise type.Line 58 hides schema drift from the generated client. Prefer deriving
EventMemberKillHistoryResponsefromeventsRankingControllerGetMemberKillHistoryand removing the cast.Proposed refactor
-export interface EventMemberKillHistoryResponse { - member: KillParticipantMember; - data: EventMemberKill[]; - nextCursor: string | null; -} +export type EventMemberKillHistoryResponse = Awaited< + ReturnType<typeof eventsRankingControllerGetMemberKillHistory> +>; ... queryFn: ({ pageParam }) => eventsRankingControllerGetMemberKillHistory( { guildId, eventId, memberId }, { limit: String(limit), heroId, cursor: typeof pageParam === "string" ? pageParam : undefined, }, - ) as Promise<EventMemberKillHistoryResponse>, + ),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/features/guild/events/hooks/queries/use-event-member-kill-history.ts` around lines 50 - 58, The code is force-casting the promise returned by eventsRankingControllerGetMemberKillHistory to EventMemberKillHistoryResponse which hides schema drift; remove the "as Promise<EventMemberKillHistoryResponse>" cast and instead derive the response type from the generated client (e.g. use ReturnType<typeof eventsRankingControllerGetMemberKillHistory> combined with Awaited<> to get the resolved type) and update any query typing (the queryFn return type or the hook's generics) to use that derived type so the compile-time type matches the actual API client signature.apps/api/src/events/events-ranking.controller.ts (1)
263-266: Add explicitoperationIdto the remaining endpoints in this controller.A few routes still rely on inferred operation IDs, which makes generated hook/function names less stable across schema regeneration.
Also applies to: 299-302, 369-372, 448-451, 501-504, 544-547
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/api/src/events/events-ranking.controller.ts` around lines 263 - 266, Several controller endpoints still use inferred OpenAPI operationIds; update each ApiOperation decorator to include an explicit operationId to stabilize generated client names. For each ApiOperation instance in events-ranking.controller.ts (the blocks at the shown ranges and the ones at 299-302, 369-372, 448-451, 501-504, 544-547), add a unique, descriptive operationId string (e.g., "getEventHeroStats", "listEventHeroes", etc.) that matches the handler method intent; ensure the operationId values are consistent and reflect the corresponding handler function names so regenerated schemas produce stable hook/function names.apps/web/src/features/guild/events/hooks/queries/use-hero-respawn-config.ts (1)
24-31: Avoid force-casting the generated API promise type.The
as Promise<RespawnConfig>assertion can hide contract drift between generated client types and this hook. Prefer relying on the generated return type (or validating/transforming explicitly) so mismatches fail at compile time.Suggested change
- queryFn: () => - eventsMonitoringControllerGetHeroRespawnConfig({ - guildId: guildId ?? "", - eventId, - heroId, - }) as Promise<RespawnConfig>, + queryFn: () => + eventsMonitoringControllerGetHeroRespawnConfig({ + guildId: guildId ?? "", + eventId, + heroId, + }),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/features/guild/events/hooks/queries/use-hero-respawn-config.ts` around lines 24 - 31, The hook currently force-casts the API call with "as Promise<RespawnConfig>" which can hide type drift; remove that assertion and let TypeScript infer the real generated return type from eventsMonitoringControllerGetHeroRespawnConfig, or explicitly transform/validate the response inside the queryFn. Concretely: in use-hero-respawn-config.ts update the queryFn for useQuery (the query constant and the eventsMonitoringControllerGetHeroRespawnConfig call) to either return the API promise directly (no "as Promise<RespawnConfig>") and adjust the useQuery generic to the generated type, or make the queryFn async, await the API call and map/validate the result to RespawnConfig before returning so mismatches surface at compile time.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/api/openapi.yaml`:
- Around line 2454-2457: The showEvent operation currently returns the
lightweight EventOverviewResponseDto (same as showEventOverview), which strips
map/location/assignment data; update the showEvent response schema to reference
the full event DTO instead of EventOverviewResponseDto—e.g., replace the $ref
"#/components/schemas/EventOverviewResponseDto" under the showEvent response
with the detailed schema (such as "#/components/schemas/EventResponseDto" or the
existing full event/details schema) so showEvent and showEventOverview have
distinct contracts.
In `@apps/api/src/events/dto/event-monitoring-response.dto.ts`:
- Around line 26-33: The schema KillTimelineAssignmentResponseSchema currently
requires memberUserId to be a non-null string but the timeline service emits
assignment members where userId can be string | null; update the schema to
accept null by making memberUserId nullable (e.g., z.string().nullable() or
z.union([z.string(), z.null()])), and verify any downstream code that depends on
KillTimelineAssignmentResponseSchema handles a null memberUserId accordingly.
In `@apps/web/src/features/guild/events/components/heroes/hero-card.tsx`:
- Around line 26-28: The HeroStats interface allows npcId to be null, but the
hero-card rendering currently displays "ID: null" for those heroes; update the
component that renders the metadata (in the hero-card.tsx render/JSX where
HeroStats.npcId is shown) to conditionally include the "ID: ..." segment only
when npcId !== null (or truthy if you prefer), leaving it out when npcId is
null; keep the HeroStats type as-is and ensure any formatting or separators
around the metadata are adjusted so no extra punctuation appears when the ID
segment is omitted.
In `@apps/web/src/features/guild/events/hooks/queries/use-event-kill-history.ts`:
- Line 4: The file currently casts the API call to Promise<KillHistoryResponse>
and imports HeroKill which isn’t used; remove the explicit cast on the call to
eventsRankingControllerGetEventKillHistory and rely on the generated return type
(which already contains .data and .nextCursor), and delete the unused HeroKill
import from use-event-kill-history.ts so TypeScript type-checking at the API
boundary is preserved.
In `@apps/web/src/features/guild/events/hooks/queries/use-event-loots.ts`:
- Around line 20-39: Remove the unsafe double-cast and the unnecessary Promise
cast: replace the "as unknown as LootsControllerFetchLootsByGuildIdParams"
pattern by either directly typing the params object (e.g. const params:
LootsControllerFetchLootsByGuildIdParams = { ... } or let TypeScript infer the
shape and omit undefined fields) so you don’t bypass the generated contract, and
remove the "as Promise<Loot[]>" cast on the queryFn; apply the same change in
use-matching-loots.ts; update the params variable and the queryFn return typing
where present to rely on the generated DTO types instead of double-casting.
In `@apps/web/src/features/guild/events/hooks/queries/use-kill-detail.ts`:
- Around line 55-57: The current conditional uses a truthy check on
response.eventConfig.scoringRules which will skip normalization for
falsy-but-valid values (e.g., false, 0, ""); change the check in the mapping
that sets scoringRules to explicitly test for null/undefined (e.g.,
response.eventConfig.scoringRules != null) and only pass through null when the
value is null or undefined, otherwise call
normalizeScoringRules(response.eventConfig.scoringRules) so
normalizeScoringRules and scoringRules handling remain correct.
In `@apps/web/src/features/guild/events/hooks/queries/use-map-coverage-timer.ts`:
- Around line 39-45: The code is using unchecked "as Promise<...>" casts on
generated Orval client calls; remove the redundant casts from
eventsMonitoringControllerGetActiveGapForMap (and the similar cast on
eventsMonitoringControllerGetHeroCoverageGaps) so the queryFn returns the
client's inferred promise type directly, e.g. change queryFn to just call
eventsMonitoringControllerGetActiveGapForMap({...}) without "as Promise<...>"
and let TypeScript use the generated return type.
In `@apps/web/src/features/guild/events/hooks/queries/use-matching-loots.ts`:
- Around line 42-61: The params object is being forced into
LootsControllerFetchLootsByGuildIdParams and responses are forced into Loot via
unsafe assertions; remove the "as unknown as
LootsControllerFetchLootsByGuildIdParams" and any "as Promise<Loot[]>" casts in
use-matching-loots (and the same spots in use-event-loots) and instead rely on
the generated types (LootsControllerFetchLootsByGuildIdParams and
LootResponseDto) — either change your local Loot type to match LootResponseDto
(dropping non-API fields like source, diedPlayers, updatedAt, member) or add an
explicit mapping function (e.g., mapLootResponseDtoToLoot) that converts
LootResponseDto -> Loot after fetching; also ensure the params object only
includes properties defined by LootsControllerFetchLootsByGuildIdParams so the
API call type-checks without assertions.
In `@apps/web/src/lib/api/orval-fetch.ts`:
- Line 15: The current baseURL assignment (const baseURL = API_URL ??
window.location.origin) can throw when window is undefined in SSR/tests; change
it to guard window access by using a typeof window !== 'undefined' (or
globalThis) check and fallback to a safe value (e.g., empty string or an env
fallback) when window is not available; update the expression in orval-fetch.ts
where baseURL is declared so it uses API_URL ?? (typeof window !== 'undefined' ?
window.location.origin : process.env.DEFAULT_BASE_URL ?? '') to avoid
ReferenceError in non-browser environments.
In `@scripts/sanitize-openapi.mjs`:
- Around line 91-124: The dedup logic in ensurePathParameters only inspects
operation.parameters and can duplicate parameters that live at
pathItem.parameters; change the logic to consider both operation.parameters and
pathItem.parameters when looking for existingParameter (search the union of
operation.parameters and pathItem.parameters by parameter.in and name), and only
push a new parameter into operation.parameters when it does not exist anywhere;
if the match is found on a path-level parameter, update that path-level
parameter.schema when empty instead of adding a duplicate to
operation.parameters. Ensure you still set operation.parameters = parameters
(where parameters starts from the original operation.parameters array) and
preserve the names/structure used in the snippet (operation.parameters,
pathItem.parameters, existingParameter).
- Line 6: The require call in scripts/sanitize-openapi.mjs hard-codes
"../apps/api/node_modules/js-yaml" (assigned to the yaml variable) which breaks
in pnpm workspaces; replace it by resolving "js-yaml" from the apps/api package
root and then requiring that resolved path (e.g., use require.resolve('js-yaml',
{ paths: [path.resolve(__dirname, 'apps/api')] }) or Node's createRequire rooted
at apps/api/package.json to locate the module) and assign the resulting
require(...) to the yaml variable so module resolution is based on apps/api
instead of a fixed node_modules path.
---
Outside diff comments:
In `@apps/api/openapi.yaml`:
- Around line 3292-3315: The OpenAPI operation updateRankingPoints is missing a
requestBody and a typed 200 response; add a requestBody (application/json) with
a schema describing the signed delta payload (e.g., fields like signer,
signature, delta, reason) and update the "200" response to include a JSON schema
for the updated Ranking (or a defined component schema reference such as
'#/components/schemas/Ranking' or '#/components/schemas/RankingUpdateResponse')
so Orval generates a typed mutation; ensure the operationId updateRankingPoints
remains and reference any existing component schemas or create new ones under
components/schemas for reuse.
In `@apps/api/src/events/events-ranking.controller.ts`:
- Around line 168-171: The two endpoints updateRankingPoints and updateKillPoint
still use generic `@ApiResponse`({status: 200}) and should be converted to use
`@ZodResponse`({ status: 200, type: ... }) like the other migrated endpoints;
replace the untyped `@ApiResponse` decorators on the methods updateRankingPoints
and updateKillPoint with `@ZodResponse` decorators that reference the proper Zod
DTO schemas (create or reuse the matching response DTO/zod schema for the actual
payload shape) so Orval generates strong types for those success responses.
In `@apps/web/src/features/guild/events/utils/normalize-bonus-breakdown.ts`:
- Around line 24-33: The normalizer currently accesses entry.ruleId and
entry.ruleName directly (in the normalization logic inside
normalize-bonus-breakdown.ts), which can throw if bonusBreakdown contains null
or non-object entries; update the mapping logic to first verify each entry is an
object (e.g., typeof entry === "object" && entry !== null) before reading
properties, and only read/trim ruleId/ruleName when typeof entry.ruleId ===
"string" / typeof entry.ruleName === "string"; fallback to the existing defaults
("rule" and null) if the checks fail so the function (and any function that
calls it) no longer crashes on null/non-object entries.
---
Nitpick comments:
In `@apps/api/src/events/events-ranking.controller.ts`:
- Around line 263-266: Several controller endpoints still use inferred OpenAPI
operationIds; update each ApiOperation decorator to include an explicit
operationId to stabilize generated client names. For each ApiOperation instance
in events-ranking.controller.ts (the blocks at the shown ranges and the ones at
299-302, 369-372, 448-451, 501-504, 544-547), add a unique, descriptive
operationId string (e.g., "getEventHeroStats", "listEventHeroes", etc.) that
matches the handler method intent; ensure the operationId values are consistent
and reflect the corresponding handler function names so regenerated schemas
produce stable hook/function names.
In `@apps/web/src/components/layout/guilds-sidebar-nav.tsx`:
- Around line 35-44: The useListEvents query is called unconditionally which
triggers requests with an empty guildId; update the useListEvents call that uses
activeEventsGuildId so it includes the query option enabled: canViewEvents
(i.e., add enabled: canViewEvents to the second options object) so the hook is
skipped when canViewEvents is false; this touches the useListEvents invocation
and the activeEventsGuildId logic in guilds-sidebar-nav.tsx.
In `@apps/web/src/features/guild/events/hooks/mutations/use-create-event.ts`:
- Around line 30-37: Normalize guildId once into a local constant (e.g.,
normalizedGuildId = guildId ?? "") at the top of the mutation and use that
single variable for both the POST URL `/guilds/${normalizedGuildId}/events` and
the invalidate call `getListEventsQueryKey({ guildId: normalizedGuildId })` so
the request target and query key cannot diverge; update references inside the
mutation (the URL string and queryClient.invalidateQueries call) to use the
normalizedGuildId and remove the inline fallback.
In
`@apps/web/src/features/guild/events/hooks/queries/use-event-member-kill-history.ts`:
- Around line 50-58: The code is force-casting the promise returned by
eventsRankingControllerGetMemberKillHistory to EventMemberKillHistoryResponse
which hides schema drift; remove the "as
Promise<EventMemberKillHistoryResponse>" cast and instead derive the response
type from the generated client (e.g. use ReturnType<typeof
eventsRankingControllerGetMemberKillHistory> combined with Awaited<> to get the
resolved type) and update any query typing (the queryFn return type or the
hook's generics) to use that derived type so the compile-time type matches the
actual API client signature.
In `@apps/web/src/features/guild/events/hooks/queries/use-event-settings.ts`:
- Around line 13-15: The call to eventsSettingsControllerGetSettings is using an
unnecessary type assertion "as Promise<EventSettingsResponseDto>"; remove that
cast and let TypeScript use the generated function's return type directly (i.e.,
pass the guildId to eventsSettingsControllerGetSettings(...) without the "as
Promise<EventSettingsResponseDto>" assertion) so the code relies on the
Orval-generated typing for EventSettingsResponseDto and avoids an unsafe
redundant cast.
In `@apps/web/src/features/guild/events/hooks/queries/use-hero-respawn-config.ts`:
- Around line 24-31: The hook currently force-casts the API call with "as
Promise<RespawnConfig>" which can hide type drift; remove that assertion and let
TypeScript infer the real generated return type from
eventsMonitoringControllerGetHeroRespawnConfig, or explicitly transform/validate
the response inside the queryFn. Concretely: in use-hero-respawn-config.ts
update the queryFn for useQuery (the query constant and the
eventsMonitoringControllerGetHeroRespawnConfig call) to either return the API
promise directly (no "as Promise<RespawnConfig>") and adjust the useQuery
generic to the generated type, or make the queryFn async, await the API call and
map/validate the result to RespawnConfig before returning so mismatches surface
at compile time.
In `@apps/web/src/features/guild/events/hooks/queries/use-kill-timeline.ts`:
- Around line 30-36: The queryFn in use-kill-timeline.ts is force-casting the
API call to MapTimelineData[] which hides type mismatches; remove the "as
Promise<MapTimelineData[]>" cast and let TypeScript infer the return type from
eventsMonitoringControllerGetKillTimelineData (keeping the same args: guildId,
eventId, heroId, killId) so any generated API/type mismatch surfaces correctly
and strict typing is preserved.
In `@apps/web/src/features/guild/events/types/api.ts`:
- Around line 12-18: The Member type currently marks avatar and roles as
optional which loosens type guarantees; update the Member type (symbol: Member)
so those keys are required but allow null to match the API DTO shape (e.g., use
avatar: string | null and roles: MemberRole[] | null) so the fields are always
present in responses but may be null, and adjust any consuming code that assumed
they could be undefined.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 76c8265f-5c1b-440b-a581-b9e178adc4b2
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (72)
apps/api/openapi.yamlapps/api/src/events/dto/event-kill-response.dto.tsapps/api/src/events/dto/event-monitoring-response.dto.tsapps/api/src/events/dto/event-response.dto.tsapps/api/src/events/dto/event-wrapped-response.dto.tsapps/api/src/events/events-catalog.controller.tsapps/api/src/events/events-monitoring.controller.tsapps/api/src/events/events-ranking.controller.tsapps/api/src/events/services/event-kill.service.tsapps/api/src/main.tsapps/web/src/components/layout/event-timers-list.tsxapps/web/src/components/layout/guild-pinned-events-section.tsxapps/web/src/components/layout/guilds-sidebar-nav.tsxapps/web/src/components/layout/pinned-events-banner.tsxapps/web/src/features/guild/events/components/heroes/hero-card.tsxapps/web/src/features/guild/events/components/heroes/hero-window-status-badge.tsxapps/web/src/features/guild/events/components/kills/kill-history-card.tsxapps/web/src/features/guild/events/components/kills/recent-kills-preview.tsxapps/web/src/features/guild/events/components/maps/event-map-grid.tsxapps/web/src/features/guild/events/components/maps/map-card.tsxapps/web/src/features/guild/events/components/ranking/event-ranking-preview.tsxapps/web/src/features/guild/events/components/ranking/event-ranking-table.tsxapps/web/src/features/guild/events/components/shared/member-badge.tsxapps/web/src/features/guild/events/components/stats/event-hero-loots.tsxapps/web/src/features/guild/events/event-detail.tsxapps/web/src/features/guild/events/event-edit-rulebook-page.tsxapps/web/src/features/guild/events/event-edit-scoring-page.tsxapps/web/src/features/guild/events/event-edit-settings-page.tsxapps/web/src/features/guild/events/event-kills-history.tsxapps/web/src/features/guild/events/event-member-kills-page.tsxapps/web/src/features/guild/events/event-ranking-page.tsxapps/web/src/features/guild/events/events.tsxapps/web/src/features/guild/events/hero-detail.tsxapps/web/src/features/guild/events/hooks/mutations/use-create-event.tsapps/web/src/features/guild/events/hooks/mutations/use-delete-event.tsapps/web/src/features/guild/events/hooks/mutations/use-event-mutations.tsapps/web/src/features/guild/events/hooks/queries/index.tsapps/web/src/features/guild/events/hooks/queries/use-event-hero-stats.tsapps/web/src/features/guild/events/hooks/queries/use-event-hero-timers.tsapps/web/src/features/guild/events/hooks/queries/use-event-kill-history.tsapps/web/src/features/guild/events/hooks/queries/use-event-loots.tsapps/web/src/features/guild/events/hooks/queries/use-event-maps.tsapps/web/src/features/guild/events/hooks/queries/use-event-member-kill-history.tsapps/web/src/features/guild/events/hooks/queries/use-event-overview.tsapps/web/src/features/guild/events/hooks/queries/use-event-participation-confirmations.tsapps/web/src/features/guild/events/hooks/queries/use-event-ranking.tsapps/web/src/features/guild/events/hooks/queries/use-event-settings.tsapps/web/src/features/guild/events/hooks/queries/use-event-wrapped.tsapps/web/src/features/guild/events/hooks/queries/use-events.tsapps/web/src/features/guild/events/hooks/queries/use-hero-active-gaps.tsapps/web/src/features/guild/events/hooks/queries/use-hero-kill-history.tsapps/web/src/features/guild/events/hooks/queries/use-hero-presence-stats.tsapps/web/src/features/guild/events/hooks/queries/use-hero-respawn-config.tsapps/web/src/features/guild/events/hooks/queries/use-kill-detail.tsapps/web/src/features/guild/events/hooks/queries/use-kill-timeline.tsapps/web/src/features/guild/events/hooks/queries/use-map-coverage-timer.tsapps/web/src/features/guild/events/hooks/queries/use-matching-loots.tsapps/web/src/features/guild/events/hooks/queries/use-ranking-edit-history.tsapps/web/src/features/guild/events/hooks/queries/use-recent-hero-kills.tsapps/web/src/features/guild/events/kill-detail.tsxapps/web/src/features/guild/events/types/api.tsapps/web/src/features/guild/events/utils/normalize-bonus-breakdown.tsapps/web/src/features/guild/events/utils/scoring-rules.tsapps/web/src/lib/api-client/api-client.tsapps/web/src/lib/api/orval-fetch.tsapps/web/src/lib/router/route-errors.tsapps/web/src/routes/_authenticated/$guildId.tsxapps/web/src/routes/_authenticated/$guildId/events.tsxapps/web/src/routes/_authenticated/$guildId/events_.$eventId_.tsxorval.config.tspackage.jsonscripts/sanitize-openapi.mjs
💤 Files with no reviewable changes (4)
- apps/web/src/features/guild/events/hooks/queries/index.ts
- apps/web/src/features/guild/events/hooks/queries/use-event-ranking.ts
- apps/web/src/features/guild/events/hooks/queries/use-events.ts
- apps/web/src/features/guild/events/hooks/queries/use-event-overview.ts
| content: | ||
| application/json: | ||
| schema: | ||
| $ref: "#/components/schemas/EventOverviewResponseDto" |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
showEvent now exposes the same lightweight contract as /overview.
This points the detailed endpoint at EventOverviewResponseDto, which omits map/location/assignment data. That makes showEvent effectively indistinguishable from showEventOverview and narrows the generated client contract for the main event-details call.
Proposed fix
- $ref: "#/components/schemas/EventOverviewResponseDto"
+ $ref: "#/components/schemas/EventMutationResponseDto"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/EventOverviewResponseDto" | |
| content: | |
| application/json: | |
| schema: | |
| $ref: "#/components/schemas/EventMutationResponseDto" |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/api/openapi.yaml` around lines 2454 - 2457, The showEvent operation
currently returns the lightweight EventOverviewResponseDto (same as
showEventOverview), which strips map/location/assignment data; update the
showEvent response schema to reference the full event DTO instead of
EventOverviewResponseDto—e.g., replace the $ref
"#/components/schemas/EventOverviewResponseDto" under the showEvent response
with the detailed schema (such as "#/components/schemas/EventResponseDto" or the
existing full event/details schema) so showEvent and showEventOverview have
distinct contracts.
| const KillTimelineAssignmentResponseSchema = z.object({ | ||
| memberId: z.number(), | ||
| memberName: z.string(), | ||
| memberAvatar: z.string().nullable(), | ||
| memberUserId: z.string(), | ||
| assignedAt: z.iso.datetime(), | ||
| unassignedAt: z.iso.datetime().nullable(), | ||
| }); |
There was a problem hiding this comment.
memberUserId nullability is inconsistent with emitted data.
The timeline service builds assignment members with userId: string | null, but this schema requires z.string(). A null userId will fail response validation.
✅ Proposed fix
const KillTimelineAssignmentResponseSchema = z.object({
memberId: z.number(),
memberName: z.string(),
memberAvatar: z.string().nullable(),
- memberUserId: z.string(),
+ memberUserId: z.string().nullable(),
assignedAt: z.iso.datetime(),
unassignedAt: z.iso.datetime().nullable(),
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const KillTimelineAssignmentResponseSchema = z.object({ | |
| memberId: z.number(), | |
| memberName: z.string(), | |
| memberAvatar: z.string().nullable(), | |
| memberUserId: z.string(), | |
| assignedAt: z.iso.datetime(), | |
| unassignedAt: z.iso.datetime().nullable(), | |
| }); | |
| const KillTimelineAssignmentResponseSchema = z.object({ | |
| memberId: z.number(), | |
| memberName: z.string(), | |
| memberAvatar: z.string().nullable(), | |
| memberUserId: z.string().nullable(), | |
| assignedAt: z.iso.datetime(), | |
| unassignedAt: z.iso.datetime().nullable(), | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/api/src/events/dto/event-monitoring-response.dto.ts` around lines 26 -
33, The schema KillTimelineAssignmentResponseSchema currently requires
memberUserId to be a non-null string but the timeline service emits assignment
members where userId can be string | null; update the schema to accept null by
making memberUserId nullable (e.g., z.string().nullable() or
z.union([z.string(), z.null()])), and verify any downstream code that depends on
KillTimelineAssignmentResponseSchema handles a null memberUserId accordingly.
| interface HeroStats { | ||
| npcId: number; | ||
| npcId: number | null; | ||
| killCount: number; |
There was a problem hiding this comment.
Avoid rendering ID: null for heroes without an NPC id.
Making npcId nullable here means the metadata line below can now show ID: null to users. Please hide that segment when the id is absent.
Suggested fix
- ID: {hero.npcId} •{" "}
+ {hero.npcId !== null ? `ID: ${hero.npcId} • ` : ""}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/features/guild/events/components/heroes/hero-card.tsx` around
lines 26 - 28, The HeroStats interface allows npcId to be null, but the
hero-card rendering currently displays "ID: null" for those heroes; update the
component that renders the metadata (in the hero-card.tsx render/JSX where
HeroStats.npcId is shown) to conditionally include the "ID: ..." segment only
when npcId !== null (or truthy if you prefer), leaving it out when npcId is
null; keep the HeroStats type as-is and ensure any formatting or separators
around the metadata are adjusted so no extra punctuation appears when the ID
segment is omitted.
| const params = { | ||
| limit, | ||
| npcs: npcNames.length > 0 ? npcNames : undefined, | ||
| cursor: undefined, | ||
| npcs: npcNames, | ||
| players: undefined, | ||
| rarities: undefined, | ||
| npcTypes: undefined, | ||
| world, | ||
| }; | ||
|
|
||
| const queryString = stringify(queryParams, { | ||
| arrayFormat: "comma", | ||
| allowEmptyArrays: false, | ||
| filter: (_, value) => { | ||
| if (value === "" || value === undefined || value === null) { | ||
| return; | ||
| } | ||
| return value; | ||
| }, | ||
| }); | ||
| npcLevelMin: undefined, | ||
| npcLevelMax: undefined, | ||
| itemLevelMin: undefined, | ||
| itemLevelMax: undefined, | ||
| playerLevelMin: undefined, | ||
| playerLevelMax: undefined, | ||
| search: undefined, | ||
| hid: undefined, | ||
| itemNames: undefined, | ||
| createdAtMin: undefined, | ||
| createdAtMax: undefined, | ||
| } as unknown as LootsControllerFetchLootsByGuildIdParams; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify generated signature and expected params type for loots endpoint
LOOTS_FILE="$(fd -p 'loots.ts' | rg 'lib/api/generated/main/loots/loots.ts$' | head -n1)"
echo "Inspecting: ${LOOTS_FILE}"
rg -n "lootsControllerFetchLootsByGuildId|LootsControllerFetchLootsByGuildIdParams" "$LOOTS_FILE" -A8 -B4
# Verify local call sites and current assertions
rg -n "lootsControllerFetchLootsByGuildId\\(|as unknown as LootsControllerFetchLootsByGuildIdParams" apps/web/src/features/guild/events/hooks/queries/use-event-loots.ts -A4 -B4Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
find apps/web -name "*use-event-loots*" -type fRepository: lootlog/monorepo
Length of output: 127
🏁 Script executed:
find . -path "*/api/generated*" -name "*loot*" -type f 2>/dev/null | head -20Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
git ls-files | grep -E "(use-event-loots|loots)" | head -20Repository: lootlog/monorepo
Length of output: 948
🏁 Script executed:
cat -n apps/web/src/features/guild/events/hooks/queries/use-event-loots.ts | head -60Repository: lootlog/monorepo
Length of output: 1840
🏁 Script executed:
rg "LootsControllerFetchLootsByGuildIdParams" apps/web --type ts -B2 -A2Repository: lootlog/monorepo
Length of output: 2402
🏁 Script executed:
find apps/web -path "*/generated*" -type d 2>/dev/nullRepository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
find apps/web -name "model*" -path "*/generated*" 2>/dev/null | head -20Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
rg "@/lib" apps/web/tsconfig.json -A5 -B5Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
find . -path "*/lib/api/generated*" -type f 2>/dev/null | head -20Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
cat apps/web/tsconfig.json | grep -A10 "paths"Repository: lootlog/monorepo
Length of output: 216
🏁 Script executed:
find apps/web -name "tsconfig*.json" -type f | xargs catRepository: lootlog/monorepo
Length of output: 1707
🏁 Script executed:
find . -name "*.openapi*" -o -name "openapi.json" -o -name "*codegen*" 2>/dev/null | head -20Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
git ls-files | grep -E "tsconfig|codegen|openapi" | head -20Repository: lootlog/monorepo
Length of output: 650
🏁 Script executed:
find apps/web/src/lib/api/generated -type f 2>/dev/null | head -20Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
cat apps/api/openapi.yaml | grep -A50 "LootsControllerFetchLootsByGuildIdParams\|FetchLootsByGuildId" | head -100Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
ls -la apps/web/src/lib/api/generated/main/ 2>/dev/null || echo "Directory does not exist"Repository: lootlog/monorepo
Length of output: 84
🏁 Script executed:
cat apps/api/src/loots/dto/fetch-loots-params.dto.tsRepository: lootlog/monorepo
Length of output: 1483
🏁 Script executed:
cat apps/api/src/loots/loots.controller.ts | grep -A20 "fetchLootsByGuildId"Repository: lootlog/monorepo
Length of output: 876
🏁 Script executed:
rg "generateApiClients|openapi|codegen" package.json apps/web/package.json --type jsonRepository: lootlog/monorepo
Length of output: 192
🏁 Script executed:
cat apps/api/src/loots/dto/fetch-loots-params.dto.ts | grep -v ".optional()"Repository: lootlog/monorepo
Length of output: 980
🏁 Script executed:
rg "readonly|required" apps/api/src/loots/dto/fetch-loots-params.dto.tsRepository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
cat apps/web/src/features/guild/events/hooks/queries/use-matching-loots.ts | head -60Repository: lootlog/monorepo
Length of output: 1691
Remove the double-cast on request params; it hides contract drift.
as unknown as LootsControllerFetchLootsByGuildIdParams bypasses type safety at the exact boundary where generated API contracts should protect you. Since all fields in FetchLootsParamsDto are optional, you can safely omit undefined values and use a direct type annotation instead. If the generated param shape changes, this still compiles and can send wrong filters at runtime.
💡 Suggested typed fix
- const params = {
+ const params: LootsControllerFetchLootsByGuildIdParams = {
limit,
- cursor: undefined,
npcs: npcNames,
- players: undefined,
- rarities: undefined,
- npcTypes: undefined,
world,
- npcLevelMin: undefined,
- npcLevelMax: undefined,
- itemLevelMin: undefined,
- itemLevelMax: undefined,
- playerLevelMin: undefined,
- playerLevelMax: undefined,
- search: undefined,
- hid: undefined,
- itemNames: undefined,
- createdAtMin: undefined,
- createdAtMax: undefined,
- } as unknown as LootsControllerFetchLootsByGuildIdParams;
+ };Also applies to: use-matching-loots.ts (same pattern) and line 44-46 (remove the as Promise<Loot[]> cast on the queryFn).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/features/guild/events/hooks/queries/use-event-loots.ts` around
lines 20 - 39, Remove the unsafe double-cast and the unnecessary Promise cast:
replace the "as unknown as LootsControllerFetchLootsByGuildIdParams" pattern by
either directly typing the params object (e.g. const params:
LootsControllerFetchLootsByGuildIdParams = { ... } or let TypeScript infer the
shape and omit undefined fields) so you don’t bypass the generated contract, and
remove the "as Promise<Loot[]>" cast on the queryFn; apply the same change in
use-matching-loots.ts; update the params variable and the queryFn return typing
where present to rely on the generated DTO types instead of double-casting.
| queryFn: () => | ||
| eventsMonitoringControllerGetActiveGapForMap({ | ||
| guildId: guildId ?? "", | ||
| eventId, | ||
| mapId, | ||
| }) as Promise<CoverageGap | null>, | ||
| enabled: enabled && !!guildId && !!eventId && !!mapId, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
generated_file="$(fd -i 'events.ts' | rg 'generated/main/events/events.ts$' | head -n1 || true)"
if [[ -z "${generated_file}" ]]; then
echo "Could not find generated events client file."
exit 1
fi
echo "Inspecting: ${generated_file}"
rg -nP -C3 'export const (eventsMonitoringControllerGetActiveGapForMap|eventsMonitoringControllerGetMapCoverageGaps|listEventMaps)\b' "${generated_file}"Repository: lootlog/monorepo
Length of output: 104
🏁 Script executed:
cd /tmp/repo && pwdRepository: lootlog/monorepo
Length of output: 119
🏁 Script executed:
# Find the actual file mentioned in the review
fd 'use-map-coverage-timer.ts' --type fRepository: lootlog/monorepo
Length of output: 134
🏁 Script executed:
# Explore the structure of the generated files
fd 'events' --type f | grep -E '(generated|client)' | head -20Repository: lootlog/monorepo
Length of output: 223
🏁 Script executed:
# Look for generated API client files more broadly
find . -type d -name 'generated' 2>/dev/null | head -10Repository: lootlog/monorepo
Length of output: 114
🏁 Script executed:
# Check the structure of generated folders
ls -la apps/web/src/generated 2>/dev/null || echo "No generated folder in apps/web"Repository: lootlog/monorepo
Length of output: 91
🏁 Script executed:
# Look for events-related generated files in API
find apps/api/src/generated -name '*event*' -type f 2>/dev/null | head -20Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
# Check what's in the generated directory for web app
find apps/web/src/generated -name '*event*' -type f 2>/dev/null | head -20Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
# Read the actual review file to see the current code
cat -n apps/web/src/features/guild/events/hooks/queries/use-map-coverage-timer.tsRepository: lootlog/monorepo
Length of output: 4212
🏁 Script executed:
# Now find the actual generated API client
find apps/web/src/lib -name 'events.ts' -o -name 'events.js' 2>/dev/nullRepository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
# Check the lib/api structure
find apps/web/src/lib/api -type f 2>/dev/null | head -30Repository: lootlog/monorepo
Length of output: 95
🏁 Script executed:
# More aggressive search for the generated folder
find . -path '*/lib/api/generated*' -type f 2>/dev/null | head -20Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
# Check tsconfig to understand @ alias
cat apps/web/tsconfig.json | grep -A5 -B5 '"@"'Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
# Search for the generated folder more broadly
find . -type d -name 'generated' 2>/dev/null | grep -v node_modulesRepository: lootlog/monorepo
Length of output: 114
🏁 Script executed:
# Look for events.ts in node_modules (might be generated there)
find node_modules -path '*/generated/main/events/events.ts' 2>/dev/null | head -5Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
# Check if there's a build or dist directory
ls -la apps/web/ | grep -E '(dist|build|\.next)' || echo "No dist/build found"Repository: lootlog/monorepo
Length of output: 79
🏁 Script executed:
# Look for orval config which might generate these files
find . -name 'orval.config*' -o -name '.orval*' 2>/dev/null | head -10Repository: lootlog/monorepo
Length of output: 77
🏁 Script executed:
# Check the orval config
cat orval.config.tsRepository: lootlog/monorepo
Length of output: 960
🏁 Script executed:
# Search for where the imports are actually coming from in the source
rg -n "@/lib/api/generated/main/events/events" apps/web/src --type ts --type tsxRepository: lootlog/monorepo
Length of output: 87
🏁 Script executed:
# Check if generated files might be in a different location
find . -path '*lib/api*' -type d 2>/dev/null | head -20Repository: lootlog/monorepo
Length of output: 112
🏁 Script executed:
# Check if generated files exist at the expected location
ls -la apps/web/src/lib/api/generated/ 2>/dev/null || echo "Directory does not exist"Repository: lootlog/monorepo
Length of output: 84
🏁 Script executed:
# Check gitignore
cat .gitignore | grep -i generatedRepository: lootlog/monorepo
Length of output: 136
🏁 Script executed:
# Search for any reference to the generated API files
rg 'eventsMonitoringControllerGetActiveGapForMap' --type ts -lRepository: lootlog/monorepo
Length of output: 134
🏁 Script executed:
# Check package.json for scripts that might generate these
cat package.json | grep -A5 '"generate"' || cat package.json | grep -A5 'orval'Repository: lootlog/monorepo
Length of output: 611
🏁 Script executed:
# Look at the orval-fetch.ts to understand how the generated code would work
cat apps/web/src/lib/api/orval-fetch.tsRepository: lootlog/monorepo
Length of output: 645
🏁 Script executed:
# Check the OpenAPI spec to understand what the API returns
cat apps/api/openapi.yaml | head -100Repository: lootlog/monorepo
Length of output: 2913
🏁 Script executed:
# Search for the eventsMonitoring controller in the OpenAPI spec
rg -A20 'eventsMonitoringControllerGetActiveGapForMap|eventsMonitoringControllerGetMapCoverageGaps' apps/api/openapi.yaml | head -60Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
# Let's understand what Orval generates by checking their docs on includeHttpResponseReturnType
# For now, let's check if there's existing generated code in git history or in API
find apps/api/src -name '*events*' -type f | head -20Repository: lootlog/monorepo
Length of output: 669
🏁 Script executed:
# Check the events-monitoring controller to see what it returns
cat apps/api/src/events/events-monitoring.controller.tsRepository: lootlog/monorepo
Length of output: 11831
🏁 Script executed:
# Also search for CoverageGapResponseDto definition
rg -n 'CoverageGapResponseDto' apps/api/src --type ts -A5 -B5 | head -80Repository: lootlog/monorepo
Length of output: 7070
🏁 Script executed:
# Check the OpenAPI spec for the specific endpoints
rg -n '/events.*getActiveGapForMap|/events.*getMapCoverageGaps' apps/api/openapi.yaml -A20 | head -100Repository: lootlog/monorepo
Length of output: 42
Remove unchecked as Promise<...> casts on generated client calls.
The generated Orval client with includeHttpResponseReturnType: false already infers correct promise types directly from the OpenAPI spec. These casts bypass compile-time validation and are redundant—particularly evident since eventsMonitoringControllerGetHeroCoverageGaps (line 102) works without a cast using the same pattern.
Cleanup required
- queryFn: () =>
- eventsMonitoringControllerGetActiveGapForMap({
- guildId: guildId ?? "",
- eventId,
- mapId,
- }) as Promise<CoverageGap | null>,
+ queryFn: () =>
+ eventsMonitoringControllerGetActiveGapForMap({
+ guildId: guildId ?? "",
+ eventId,
+ mapId,
+ }),
- queryFn: () =>
- eventsMonitoringControllerGetMapCoverageGaps({
- guildId: guildId ?? "",
- eventId,
- mapId,
- }) as Promise<CoverageGap[]>,
+ queryFn: () =>
+ eventsMonitoringControllerGetMapCoverageGaps({
+ guildId: guildId ?? "",
+ eventId,
+ mapId,
+ }),Applies to lines 39–45 and 112–117.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| queryFn: () => | |
| eventsMonitoringControllerGetActiveGapForMap({ | |
| guildId: guildId ?? "", | |
| eventId, | |
| mapId, | |
| }) as Promise<CoverageGap | null>, | |
| enabled: enabled && !!guildId && !!eventId && !!mapId, | |
| queryFn: () => | |
| eventsMonitoringControllerGetActiveGapForMap({ | |
| guildId: guildId ?? "", | |
| eventId, | |
| mapId, | |
| }), | |
| enabled: enabled && !!guildId && !!eventId && !!mapId, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/features/guild/events/hooks/queries/use-map-coverage-timer.ts`
around lines 39 - 45, The code is using unchecked "as Promise<...>" casts on
generated Orval client calls; remove the redundant casts from
eventsMonitoringControllerGetActiveGapForMap (and the similar cast on
eventsMonitoringControllerGetHeroCoverageGaps) so the queryFn returns the
client's inferred promise type directly, e.g. change queryFn to just call
eventsMonitoringControllerGetActiveGapForMap({...}) without "as Promise<...>"
and let TypeScript use the generated return type.
| const params = { | ||
| limit: 50, | ||
| cursor: undefined, | ||
| npcs: [npcName], | ||
| players: undefined, | ||
| rarities: undefined, | ||
| npcTypes: undefined, | ||
| world, | ||
| npcLevelMin: undefined, | ||
| npcLevelMax: undefined, | ||
| itemLevelMin: undefined, | ||
| itemLevelMax: undefined, | ||
| playerLevelMin: undefined, | ||
| playerLevelMax: undefined, | ||
| search: undefined, | ||
| hid: undefined, | ||
| itemNames: undefined, | ||
| createdAtMin, | ||
| createdAtMax, | ||
| } as unknown as LootsControllerFetchLootsByGuildIdParams; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n --type=ts -C3 '\b(lootsControllerFetchLootsByGuildId|LootsControllerFetchLootsByGuildIdParams)\b' apps/web/src/lib/api/generated/mainRepository: lootlog/monorepo
Length of output: 135
🏁 Script executed:
#!/bin/bash
# Find the generated API files
fd -t f "generated" apps/web/src/lib/ | head -20Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
#!/bin/bash
# Search for lootsControllerFetchLootsByGuildId definition
rg -n "lootsControllerFetchLootsByGuildId" apps/web/src/ --type=ts | head -20Repository: lootlog/monorepo
Length of output: 677
🏁 Script executed:
#!/bin/bash
# Search for LootsControllerFetchLootsByGuildIdParams definition
rg -n "LootsControllerFetchLootsByGuildIdParams" apps/web/src/ --type=ts | head -20Repository: lootlog/monorepo
Length of output: 659
🏁 Script executed:
#!/bin/bash
# Read the generated loots API file
cat apps/web/src/lib/api/generated/main/loots/loots.tsRepository: lootlog/monorepo
Length of output: 142
🏁 Script executed:
#!/bin/bash
# Search for LootsControllerFetchLootsByGuildIdParams in model file
rg -n "LootsControllerFetchLootsByGuildIdParams" apps/web/src/lib/api/generated/main/model.ts -A 30Repository: lootlog/monorepo
Length of output: 144
🏁 Script executed:
#!/bin/bash
# List the generated api directory structure
find apps/web/src/lib/api/generated -type f -name "*.ts" | head -20Repository: lootlog/monorepo
Length of output: 125
🏁 Script executed:
#!/bin/bash
# Try to find files related to loots
find apps/web/src/lib/api/generated -type f -name "*loot*" 2>/dev/nullRepository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
#!/bin/bash
# Check what's in the generated main directory
ls -la apps/web/src/lib/api/generated/main/ 2>/dev/null | head -30Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
#!/bin/bash
# Read the reviewed file
cat apps/web/src/features/guild/events/hooks/queries/use-matching-loots.tsRepository: lootlog/monorepo
Length of output: 2060
🏁 Script executed:
#!/bin/bash
# Check if there's a tsconfig with path resolution
cat tsconfig.json | grep -A 20 "paths"Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
#!/bin/bash
# Search for API specification files (OpenAPI, swagger, etc.)
find . -maxdepth 3 -type f \( -name "*.yml" -o -name "*.yaml" -o -name "*.openapi" -o -name "*swagger*" -o -name "*openapi*" \) 2>/dev/null | grep -E "(api|spec|openapi|swagger)" | head -20Repository: lootlog/monorepo
Length of output: 193
🏁 Script executed:
#!/bin/bash
# Look for generation scripts or build configuration
find . -maxdepth 3 -type f \( -name "*codegen*" -o -name "*generate*" -o -name "package.json" \) 2>/dev/null | head -10Repository: lootlog/monorepo
Length of output: 350
🏁 Script executed:
#!/bin/bash
# Check the other file mentioned to see if there's a similar pattern
cat apps/web/src/features/guild/events/hooks/queries/use-event-loots.tsRepository: lootlog/monorepo
Length of output: 1483
🏁 Script executed:
#!/bin/bash
# Search for the loots endpoint in openapi.yaml
grep -n "FetchLootsByGuildId\|/loots" apps/api/openapi.yaml | head -30Repository: lootlog/monorepo
Length of output: 293
🏁 Script executed:
#!/bin/bash
# Extract the loots endpoint definition
sed -n '/paths:/,/components:/p' apps/api/openapi.yaml | grep -A 50 "guild.*loot\|loot.*guild" | head -80Repository: lootlog/monorepo
Length of output: 1993
🏁 Script executed:
#!/bin/bash
# Check what the web package.json says about code generation
cat apps/web/package.json | grep -A 10 -B 5 "codegen\|generate"Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
#!/bin/bash
# Read web package.json to find codegen setup
cat apps/web/package.json | head -100Repository: lootlog/monorepo
Length of output: 2070
🏁 Script executed:
#!/bin/bash
# Look for openapi-generator or similar codegen config in the repo
find . -maxdepth 2 -name "openapi*" -o -name "*codegen*" -o -name ".openapirc*" 2>/dev/nullRepository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
#!/bin/bash
# Check if there's an openapi-generator config in the web app
ls -la apps/web/ | grep -E "openapi|codegen|generate"Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
#!/bin/bash
# Search for references to generated code generation or scripts
grep -r "generated" apps/web/ --include="*.json" --include="*.ts" --include="*.js" 2>/dev/null | grep -E "script|generate|codegen" | head -10Repository: lootlog/monorepo
Length of output: 1630
🏁 Script executed:
#!/bin/bash
# Check monorepo root for turbo/build config
cat turbo.json 2>/dev/null | head -50Repository: lootlog/monorepo
Length of output: 1105
🏁 Script executed:
#!/bin/bash
# Search for where LootsControllerFetchLootsByGuildIdParams is actually defined or could be generated from
rg "LootsControllerFetchLootsByGuildIdParams|lootsControllerFetchLootsByGuildId" --type=ts --type=js 2>/dev/null | grep -v "use-matching\|use-event"Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
#!/bin/bash
# Search for the actual package.json scripts that might generate the API client
grep -r "openapi-generator\|@openapi-generator\|swagger-typescript-api\|orval" . --include="package.json" 2>/dev/nullRepository: lootlog/monorepo
Length of output: 232
🏁 Script executed:
#!/bin/bash
# Check root package.json for generation scripts
cat package.json 2>/dev/null | grep -A 30 "scripts"Repository: lootlog/monorepo
Length of output: 2470
🏁 Script executed:
#!/bin/bash
# Look for any config files related to API generation
find . -maxdepth 2 -type f \( -name ".openapirc*" -o -name "openapi-generator*" -o -name "orval.config*" \) 2>/dev/nullRepository: lootlog/monorepo
Length of output: 77
🏁 Script executed:
#!/bin/bash
# Read the orval configuration
cat orval.config.tsRepository: lootlog/monorepo
Length of output: 960
🏁 Script executed:
#!/bin/bash
# Also check if there's any documentation about the response types in the generated code or in comments
grep -r "Loot\[" apps/web/src/ --include="*.ts" --include="*.tsx" -B 2 -A 2 | head -30Repository: lootlog/monorepo
Length of output: 2853
🏁 Script executed:
#!/bin/bash
# Check the generated output directory structure to see if the generated code is committed or build-time only
git ls-files apps/web/src/lib/api/generated/ 2>/dev/null | head -5Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
#!/bin/bash
# Check the gitignore to see if generated is excluded
cat .gitignore | grep -E "generated|api"Repository: lootlog/monorepo
Length of output: 200
🏁 Script executed:
#!/bin/bash
# Let's look more at the openapi spec to understand the response type for this endpoint
sed -n '1004,1150p' apps/api/openapi.yamlRepository: lootlog/monorepo
Length of output: 4231
🏁 Script executed:
#!/bin/bash
# Look at what the openapi spec says about the response schema
sed -n '/components:/,/^$/p' apps/api/openapi.yaml | grep -A 100 "LootResponseDto:" | head -120Repository: lootlog/monorepo
Length of output: 3029
🏁 Script executed:
#!/bin/bash
# Check what the Loot type is imported from
cat apps/web/src/hooks/api/loots/use-loots.ts 2>/dev/null | head -50Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
#!/bin/bash
# Search for where the Loot type is defined
rg "type Loot|interface Loot|export.*Loot" apps/web/src/ --type=ts | grep -v "Loots\|LootResponse\|LootShare" | head -20Repository: lootlog/monorepo
Length of output: 2342
🏁 Script executed:
#!/bin/bash
# Check the hooks/api directory structure
find apps/web/src/hooks -type f -name "*.ts" 2>/dev/null | head -20Repository: lootlog/monorepo
Length of output: 1275
🏁 Script executed:
#!/bin/bash
# Look for the import in the files we already have
grep -n "type { Loot }" apps/web/src/features/guild/events/hooks/queries/use-matching-loots.ts -A 5 -B 5Repository: lootlog/monorepo
Length of output: 514
🏁 Script executed:
#!/bin/bash
# Read the use-loots file to find the Loot type definition
cat apps/web/src/hooks/api/loots/use-loots.tsRepository: lootlog/monorepo
Length of output: 133
🏁 Script executed:
#!/bin/bash
# Find the use-loots file
find apps/web/src -name "*use-loots*" -type fRepository: lootlog/monorepo
Length of output: 142
🏁 Script executed:
#!/bin/bash
# Search for where Loot type is exported from
rg "export.*type Loot\b" apps/web/src/ --type=ts | head -10Repository: lootlog/monorepo
Length of output: 123
🏁 Script executed:
#!/bin/bash
# Read the use-loots.tsx file
cat apps/web/src/hooks/api/loots/use-loots.tsxRepository: lootlog/monorepo
Length of output: 2492
Remove unsafe type assertions that hide API/type mismatches.
The as unknown as LootsControllerFetchLootsByGuildIdParams and as Promise<Loot[]> assertions bypass generated type contracts. The OpenAPI spec shows the endpoint returns LootResponseDto (with id, world, location, items, players, npcs, lootShare, createdAt, commentsCount), but the custom Loot type includes additional fields (source, diedPlayers, updatedAt, member) not in the API response. Removing the assertions will expose this mismatch.
Refactor to either:
- Remove the assertions and update
Loottype to matchLootResponseDto(excluding fields not returned by the API), or - Add a transform/mapping layer to bridge the shape difference.
Also applies to: use-event-loots.ts (lines 39, 44-46)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/features/guild/events/hooks/queries/use-matching-loots.ts`
around lines 42 - 61, The params object is being forced into
LootsControllerFetchLootsByGuildIdParams and responses are forced into Loot via
unsafe assertions; remove the "as unknown as
LootsControllerFetchLootsByGuildIdParams" and any "as Promise<Loot[]>" casts in
use-matching-loots (and the same spots in use-event-loots) and instead rely on
the generated types (LootsControllerFetchLootsByGuildIdParams and
LootResponseDto) — either change your local Loot type to match LootResponseDto
(dropping non-API fields like source, diedPlayers, updatedAt, member) or add an
explicit mapping function (e.g., mapLootResponseDtoToLoot) that converts
LootResponseDto -> Loot after fetching; also ensure the params object only
includes properties defined by LootsControllerFetchLootsByGuildIdParams so the
API call type-checks without assertions.
| path: string, | ||
| requestInit: RequestInit = {}, | ||
| ): Promise<TData> => { | ||
| const baseURL = API_URL ?? window.location.origin; |
There was a problem hiding this comment.
Guard window access in base URL resolution.
Line 15 can throw ReferenceError: window is not defined outside the browser when API_URL is unset. This makes the shared mutator fragile in SSR/test contexts.
Proposed fix
- const baseURL = API_URL ?? window.location.origin;
+ const baseURL =
+ API_URL ??
+ (typeof window !== "undefined" ? window.location.origin : undefined);
+ if (!baseURL) {
+ throw new Error("API_URL must be configured when window is unavailable.");
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const baseURL = API_URL ?? window.location.origin; | |
| const baseURL = | |
| API_URL ?? | |
| (typeof window !== "undefined" ? window.location.origin : undefined); | |
| if (!baseURL) { | |
| throw new Error("API_URL must be configured when window is unavailable."); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/lib/api/orval-fetch.ts` at line 15, The current baseURL
assignment (const baseURL = API_URL ?? window.location.origin) can throw when
window is undefined in SSR/tests; change it to guard window access by using a
typeof window !== 'undefined' (or globalThis) check and fallback to a safe value
(e.g., empty string or an env fallback) when window is not available; update the
expression in orval-fetch.ts where baseURL is declared so it uses API_URL ??
(typeof window !== 'undefined' ? window.location.origin :
process.env.DEFAULT_BASE_URL ?? '') to avoid ReferenceError in non-browser
environments.
| import { createRequire } from "node:module"; | ||
|
|
||
| const require = createRequire(import.meta.url); | ||
| const yaml = require("../apps/api/node_modules/js-yaml"); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check whether js-yaml is declared and whether the hardcoded directory actually exists.
rg -n --type=json '"js-yaml"\s*:' --glob '**/package.json'
[ -d apps/api/node_modules/js-yaml ] && ls -d apps/api/node_modules/js-yaml || trueRepository: lootlog/monorepo
Length of output: 109
🏁 Script executed:
cat -n scripts/sanitize-openapi.mjs | head -20Repository: lootlog/monorepo
Length of output: 660
🏁 Script executed:
# Check if node_modules exists at all in apps/api
ls -la apps/api/ | grep -E "^d" | head -20Repository: lootlog/monorepo
Length of output: 400
🏁 Script executed:
# Check package-lock.json or yarn.lock to understand dependencies
ls -la apps/api/ | grep -E "(package-lock|yarn.lock|pnpm-lock)"Repository: lootlog/monorepo
Length of output: 42
🏁 Script executed:
# Check root-level dependency management
ls -la package*.json yarn.lock pnpm-lock.yaml 2>/dev/null || echo "No root lock files found"Repository: lootlog/monorepo
Length of output: 214
🏁 Script executed:
# Check if there's a CI/build config showing how monorepo is set up
find . -maxdepth 2 -name "*.yml" -o -name "*.yaml" | grep -E "(github|gitlab|ci)" | head -5Repository: lootlog/monorepo
Length of output: 84
🏁 Script executed:
# Check if node_modules exists at root
[ -d node_modules ] && echo "Root node_modules exists" || echo "Root node_modules does not exist"Repository: lootlog/monorepo
Length of output: 92
🏁 Script executed:
# Check root package.json for workspace and pnpm config
cat -n package.json | head -30Repository: lootlog/monorepo
Length of output: 1022
🏁 Script executed:
# Check if sanitize-openapi is referenced anywhere
rg "sanitize-openapi" --type=json --type=yaml --type=mdRepository: lootlog/monorepo
Length of output: 192
Avoid hard-coding apps/api/node_modules/js-yaml resolution.
This script is part of the build pipeline (api:client:generate) and will break in pnpm workspace configurations that don't place js-yaml at that exact filesystem path. Resolve js-yaml through module resolution rooted at apps/api/package.json instead.
💡 Suggested fix
import fs from "node:fs";
import path from "node:path";
import { createRequire } from "node:module";
-const require = createRequire(import.meta.url);
-const yaml = require("../apps/api/node_modules/js-yaml");
+const requireFromApi = createRequire(path.resolve("apps/api/package.json"));
+const yaml = requireFromApi("js-yaml");🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/sanitize-openapi.mjs` at line 6, The require call in
scripts/sanitize-openapi.mjs hard-codes "../apps/api/node_modules/js-yaml"
(assigned to the yaml variable) which breaks in pnpm workspaces; replace it by
resolving "js-yaml" from the apps/api package root and then requiring that
resolved path (e.g., use require.resolve('js-yaml', { paths:
[path.resolve(__dirname, 'apps/api')] }) or Node's createRequire rooted at
apps/api/package.json to locate the module) and assign the resulting
require(...) to the yaml variable so module resolution is based on apps/api
instead of a fixed node_modules path.
| const parameters = Array.isArray(operation.parameters) | ||
| ? operation.parameters | ||
| : []; | ||
|
|
||
| for (const parameterName of pathParameterNames) { | ||
| const existingParameter = parameters.find( | ||
| (parameter) => | ||
| parameter && | ||
| typeof parameter === "object" && | ||
| parameter.in === "path" && | ||
| parameter.name === parameterName, | ||
| ); | ||
|
|
||
| if (!existingParameter) { | ||
| parameters.push({ | ||
| name: parameterName, | ||
| in: "path", | ||
| required: true, | ||
| schema: { type: "string" }, | ||
| }); | ||
| continue; | ||
| } | ||
|
|
||
| if ( | ||
| !existingParameter.schema || | ||
| typeof existingParameter.schema !== "object" || | ||
| Object.keys(existingParameter.schema).length === 0 | ||
| ) { | ||
| existingParameter.schema = { type: "string" }; | ||
| } | ||
| } | ||
|
|
||
| operation.parameters = parameters; | ||
| } |
There was a problem hiding this comment.
Path-level parameters are not considered during deduplication.
ensurePathParameters only checks operation.parameters; if a {param} is already declared in pathItem.parameters, this can inject duplicates at operation level and produce invalid OpenAPI merges.
💡 Suggested fix
- const parameters = Array.isArray(operation.parameters)
- ? operation.parameters
- : [];
+ const pathLevelParameters = Array.isArray(pathItem.parameters)
+ ? pathItem.parameters
+ : [];
+ const parameters = Array.isArray(operation.parameters)
+ ? operation.parameters
+ : [];
for (const parameterName of pathParameterNames) {
- const existingParameter = parameters.find(
+ const existingParameter = [...pathLevelParameters, ...parameters].find(
(parameter) =>
parameter &&
typeof parameter === "object" &&
parameter.in === "path" &&
parameter.name === parameterName,
);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/sanitize-openapi.mjs` around lines 91 - 124, The dedup logic in
ensurePathParameters only inspects operation.parameters and can duplicate
parameters that live at pathItem.parameters; change the logic to consider both
operation.parameters and pathItem.parameters when looking for existingParameter
(search the union of operation.parameters and pathItem.parameters by
parameter.in and name), and only push a new parameter into operation.parameters
when it does not exist anywhere; if the match is found on a path-level
parameter, update that path-level parameter.schema when empty instead of adding
a duplicate to operation.parameters. Ensure you still set operation.parameters =
parameters (where parameters starts from the original operation.parameters
array) and preserve the names/structure used in the snippet
(operation.parameters, pathItem.parameters, existingParameter).
2bf493c to
c4e3076
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/api/openapi.yaml (1)
3291-3315:⚠️ Potential issue | 🟡 MinorAdd a type specification to the
updateRankingPointsresponse decorator to include the ranking payload.The controller method returns an
EventRankingobject (via the service's update call), but the@ApiResponsedecorator lacks a type field. Unlike neighboring ranking endpoints (listEventRankingandlistRankingEditHistory), which use@ZodResponsewith explicit types, this one omits the type specification. Orval will type the 200 response as void, losing the payload schema and generated types.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/api/openapi.yaml` around lines 3291 - 3315, The updateRankingPoints endpoint is missing a response type in its OpenAPI/ decorator, causing the 200 response to be typed as void; update the controller's decorator for the updateRankingPoints operation (the `@ApiResponse/`@ZodResponse on the updateRankingPoints method) to include the correct response schema/type (EventRanking or the same Zod schema used by listEventRanking/listRankingEditHistory) so the 200 response returns the ranking payload and Orval can generate proper types.
♻️ Duplicate comments (1)
apps/api/openapi.yaml (1)
2454-2457:⚠️ Potential issue | 🟠 Major
showEventstill exposes the overview contract instead of detailed event data.Line 2457 still references
EventOverviewResponseDto, so/guilds/{guildId}/events/{eventId}remains effectively the same lightweight contract as/overviewand omits detailed map/assignment payloads.Proposed fix
- $ref: "#/components/schemas/EventOverviewResponseDto" + $ref: "#/components/schemas/EventMutationResponseDto"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/api/openapi.yaml` around lines 2454 - 2457, The OpenAPI operation showEvent is currently referencing the lightweight EventOverviewResponseDto; update the response schema for the operation (the content/application/json schema under showEvent) to reference the detailed event contract (e.g., replace $ref: "#/components/schemas/EventOverviewResponseDto" with the detailed schema such as "#/components/schemas/EventResponseDto" or the actual detailed event DTO used elsewhere) so /guilds/{guildId}/events/{eventId} returns the full map/assignment payloads; ensure the referenced detailed schema name matches the existing component definition.
🧹 Nitpick comments (3)
apps/api/src/events/dto/event-response.dto.ts (2)
241-252: Consider reusing a shared success payload schema.Both DTOs inline similar
successobject schemas. Extracting one schema reduces duplication.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/api/src/events/dto/event-response.dto.ts` around lines 241 - 252, Both ConfirmParticipationForKillResponseDto and SuccessResponseDto duplicate the same success boolean schema; extract a shared Zod schema (e.g., SuccessPayloadSchema = z.object({ success: z.boolean() })) and then reuse it in createZodDto for both ConfirmParticipationForKillResponseDto (compose with confirmedNow) and SuccessResponseDto to remove duplication, updating the imports/exports so the new SuccessPayloadSchema or a SharedSuccessResponseDto is available to other modules.
47-78: Extract shared event base schema to prevent field drift.
EventListItemResponseSchemaandEventOverviewResponseSchemaduplicate the same core event fields. A shared base schema would keep these payloads synchronized.♻️ Proposed refactor
+const EventBaseResponseSchema = z.object({ + id: z.string(), + guildId: z.string(), + name: z.string(), + world: z.string(), + active: z.boolean(), + startsAt: nullableIsoDatetimeCodec, + endsAt: nullableIsoDatetimeCodec, + createdAt: isoDatetimeCodec, + updatedAt: isoDatetimeCodec, +}); + -const EventListItemResponseSchema = z.object({ - id: z.string(), - guildId: z.string(), - name: z.string(), - world: z.string(), - active: z.boolean(), - startsAt: nullableIsoDatetimeCodec, - endsAt: nullableIsoDatetimeCodec, - createdAt: isoDatetimeCodec, - updatedAt: isoDatetimeCodec, +const EventListItemResponseSchema = EventBaseResponseSchema.extend({ heroNpcs: z.array(EventHeroNpcResponseSchema), }); -const EventOverviewResponseSchema = z.object({ - id: z.string(), - guildId: z.string(), - name: z.string(), - world: z.string(), - active: z.boolean(), - startsAt: nullableIsoDatetimeCodec, - endsAt: nullableIsoDatetimeCodec, - createdAt: isoDatetimeCodec, - updatedAt: isoDatetimeCodec, +const EventOverviewResponseSchema = EventBaseResponseSchema.extend({ basePointsPerKill: z.number().nullable().optional(), assignmentTimeoutMinutes: z.number().nullable().optional(), participationConfirmationMinutes: z.number().nullable().optional(),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/api/src/events/dto/event-response.dto.ts` around lines 47 - 78, Create a shared EventBaseResponseSchema containing the duplicated core fields (id, guildId, name, world, active, startsAt, endsAt, createdAt, updatedAt, heroNpcs) and then refactor EventListItemResponseSchema and EventOverviewResponseSchema to derive from it (via .extend or .merge) so the list schema reuses the base and the overview schema extends the base with the extra fields (basePointsPerKill, assignmentTimeoutMinutes, participationConfirmationMinutes, mapAssignmentCap, rulebookMarkdown, scoringMode, scoringRules); update any imports/usages accordingly to avoid duplicated field definitions and prevent drift between EventListItemResponseSchema and EventOverviewResponseSchema.apps/api/src/events/dto/event-kill-response.dto.ts (1)
106-111: Avoid duplicate member schema definitions.
KillDetailMemberResponseSchemaduplicatesEventKillParticipantMemberResponseSchema. Reuse the existing schema to prevent drift.♻️ Proposed refactor
-const KillDetailMemberResponseSchema = z.object({ - id: z.number(), - name: z.string(), - avatar: z.string().nullable(), - userId: z.string(), -}); +const KillDetailMemberResponseSchema = + EventKillParticipantMemberResponseSchema;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/api/src/events/dto/event-kill-response.dto.ts` around lines 106 - 111, KillDetailMemberResponseSchema duplicates EventKillParticipantMemberResponseSchema; remove the duplicate schema and reuse the existing EventKillParticipantMemberResponseSchema by replacing references to KillDetailMemberResponseSchema with EventKillParticipantMemberResponseSchema (or alias it) so the DTOs like KillDetailResponseSchema and any TypeOf uses continue to validate against the single source of truth; ensure imports/exports are updated accordingly and types remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/api/src/events/dto/event-kill-response.dto.ts`:
- Around line 29-31: The EventKillParticipantMapDataResponseSchema defines mapId
as z.string() but other event DTOs (see EventResponse DTO's mapId) use a number;
update EventKillParticipantMapDataResponseSchema to use the same type as the
canonical event DTO (change mapId to z.number() if the canonical is numeric) so
generated client types remain consistent — adjust any related parsing or
serialization in code that constructs or consumes
EventKillParticipantMapDataResponseSchema to handle the numeric mapId.
In `@apps/web/src/components/layout/guild-pinned-events-section.tsx`:
- Around line 14-21: The component currently fetches only events active at
request time via useListEvents (populating activeEvents/isEventsPending), so
events that start later won't appear; update the fetch logic to periodically
refetch so newly-active events are picked up—either enable the hook's polling
option (e.g., pollingInterval or refetchInterval if supported) or add a
useEffect that calls the provided refetch method on useListEvents at an interval
and clears the timer on unmount; ensure you reference useListEvents,
activeEvents and isEventsPending in the change so the periodic refetch targets
the same query/context.
In
`@apps/web/src/features/guild/events/components/dialogs/event-summary-dialog.tsx`:
- Around line 46-49: The hook useShowEventWrapped is invoked unconditionally
causing the expensive summary fetch even when the dialog is closed; update the
call in EventSummaryDialog to gate the query by the dialog open state (e.g. pass
a query option like enabled: open or useShowEventWrapped({ guildId, eventId }, {
enabled: open })) so the hook only runs when open is true, and keep the existing
useEffect side effects unchanged.
In `@apps/web/src/features/guild/events/hero-detail.tsx`:
- Around line 147-155: The useListEventHeroTimers query is firing with world: ""
before event data resolves; update the call to useListEventHeroTimers (the
invocation that currently passes { guildId: guildId ?? "", eventId: eventId ??
"" } and { world: event?.world ?? "" }) to include an enabled flag so the query
only runs when event?.world is truthy (e.g., add enabled: Boolean(event?.world)
in the options object), ensuring the request is guarded until event.world is
available.
---
Outside diff comments:
In `@apps/api/openapi.yaml`:
- Around line 3291-3315: The updateRankingPoints endpoint is missing a response
type in its OpenAPI/ decorator, causing the 200 response to be typed as void;
update the controller's decorator for the updateRankingPoints operation (the
`@ApiResponse/`@ZodResponse on the updateRankingPoints method) to include the
correct response schema/type (EventRanking or the same Zod schema used by
listEventRanking/listRankingEditHistory) so the 200 response returns the ranking
payload and Orval can generate proper types.
---
Duplicate comments:
In `@apps/api/openapi.yaml`:
- Around line 2454-2457: The OpenAPI operation showEvent is currently
referencing the lightweight EventOverviewResponseDto; update the response schema
for the operation (the content/application/json schema under showEvent) to
reference the detailed event contract (e.g., replace $ref:
"#/components/schemas/EventOverviewResponseDto" with the detailed schema such as
"#/components/schemas/EventResponseDto" or the actual detailed event DTO used
elsewhere) so /guilds/{guildId}/events/{eventId} returns the full map/assignment
payloads; ensure the referenced detailed schema name matches the existing
component definition.
---
Nitpick comments:
In `@apps/api/src/events/dto/event-kill-response.dto.ts`:
- Around line 106-111: KillDetailMemberResponseSchema duplicates
EventKillParticipantMemberResponseSchema; remove the duplicate schema and reuse
the existing EventKillParticipantMemberResponseSchema by replacing references to
KillDetailMemberResponseSchema with EventKillParticipantMemberResponseSchema (or
alias it) so the DTOs like KillDetailResponseSchema and any TypeOf uses continue
to validate against the single source of truth; ensure imports/exports are
updated accordingly and types remain unchanged.
In `@apps/api/src/events/dto/event-response.dto.ts`:
- Around line 241-252: Both ConfirmParticipationForKillResponseDto and
SuccessResponseDto duplicate the same success boolean schema; extract a shared
Zod schema (e.g., SuccessPayloadSchema = z.object({ success: z.boolean() })) and
then reuse it in createZodDto for both ConfirmParticipationForKillResponseDto
(compose with confirmedNow) and SuccessResponseDto to remove duplication,
updating the imports/exports so the new SuccessPayloadSchema or a
SharedSuccessResponseDto is available to other modules.
- Around line 47-78: Create a shared EventBaseResponseSchema containing the
duplicated core fields (id, guildId, name, world, active, startsAt, endsAt,
createdAt, updatedAt, heroNpcs) and then refactor EventListItemResponseSchema
and EventOverviewResponseSchema to derive from it (via .extend or .merge) so the
list schema reuses the base and the overview schema extends the base with the
extra fields (basePointsPerKill, assignmentTimeoutMinutes,
participationConfirmationMinutes, mapAssignmentCap, rulebookMarkdown,
scoringMode, scoringRules); update any imports/usages accordingly to avoid
duplicated field definitions and prevent drift between
EventListItemResponseSchema and EventOverviewResponseSchema.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e052af12-68a3-42f7-86f5-ce9c64b6fdfa
⛔ Files ignored due to path filters (218)
apps/web/src/lib/api/generated/main/chat/chat.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/event-settings/event-settings.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/events/events.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/guilds/guilds.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/health/health.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/internal/internal.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/kills/kills.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/lootlog-config/lootlog-config.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/loots/loots.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/map-templates/map-templates.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/maps/maps.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/members/members.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/messaging/messaging.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/assignMapLocationDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/assignMemberDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/chatControllerDeleteChatMessagePathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/chatControllerGetChatMessagesPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/chatControllerSendChatMessagePathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/chatControllerUpdateChatMessagePathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/closeRespawnWindowDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/confirmParticipationForKillPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/confirmParticipationForKillResponseDtoOutput.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/countResponseDtoOutput.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/coverageGapResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/coverageGapResponseDtoGapType.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createCommentDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createEventDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createEventDtoHeroNpcsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createEventDtoHeroNpcsItemMapsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createEventDtoScoringMode.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createEventDtoScoringRules.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createEventDtoScoringRulesRulesItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createEventDtoScoringRulesRulesItemAction.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createEventDtoScoringRulesRulesItemActionType.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createEventDtoScoringRulesRulesItemConditionsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createEventPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createHeroDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createHeroDtoMapsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createKillDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createKillDtoNpc.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createKillResponseDtoOutput.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createLocationDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createLootDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createLootDtoLootsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createLootDtoNpcsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createLootDtoPlayersItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createLootDtoSource.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createLootResponseDtoOutput.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createManualTimerDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createMapDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createMapTemplateDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createMapTemplateDtoMapsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createNotificationDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createNotificationDtoNpc.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createNotificationRuleDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createNotificationRuleDtoScheduleAnchor.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createNotificationRuleDtoScheduleIntervalType.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createNotificationRuleDtoScheduleStrategy.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createNotificationRuleDtoTriggerType.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createNotificationTargetDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createNotificationTargetDtoTargetType.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createOrUpdateLootlogCharacterConfigDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createPartyGatheringDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createPartyGatheringDtoCharacter.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createPartyGatheringDtoCharacterClan.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createReservationDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createTimerFromGameClientDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createTimerFromGameClientDtoNpc.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createVolunteerDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createVolunteerDtoCharacter.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createVolunteerDtoCharacterClan.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createWatchedItemDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/createWatchedItemQuickAddDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/deleteEventPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventHeroStatsResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventKillHistoryResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventKillHistoryResponseDtoDataItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventKillHistoryResponseDtoDataItemHeroNpc.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventKillHistoryResponseDtoDataItemPointsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventKillHistoryResponseDtoDataItemPointsItemMapDataItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventKillHistoryResponseDtoDataItemPointsItemMember.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventKillHistoryResponseDtoSchema0.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventListItemResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventListItemResponseDtoHeroNpcsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMapsResponseDtoOutput.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMapsResponseDtoOutputHeroNpcsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMapsResponseDtoOutputHeroNpcsItemLocationsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMapsResponseDtoOutputHeroNpcsItemLocationsItemMapsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMapsResponseDtoOutputHeroNpcsItemLocationsItemMapsItemAssignedMembersItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMapsResponseDtoOutputHeroNpcsItemLocationsItemMapsItemAssignedMembersItemRolesItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMapsResponseDtoOutputHeroNpcsItemMapsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMapsResponseDtoOutputHeroNpcsItemMapsItemAssignedMembersItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMapsResponseDtoOutputHeroNpcsItemMapsItemAssignedMembersItemRolesItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMemberKillHistoryResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMemberKillHistoryResponseDtoDataItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMemberKillHistoryResponseDtoDataItemHeroNpc.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMemberKillHistoryResponseDtoDataItemMemberPoint.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMemberKillHistoryResponseDtoMember.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMemberKillHistoryResponseDtoSchema0.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMutationResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMutationResponseDtoHeroNpcsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMutationResponseDtoHeroNpcsItemMapsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMutationResponseDtoHeroNpcsItemMapsItemAssignedMembersItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMutationResponseDtoHeroNpcsItemMapsItemAssignedMembersItemRolesItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMutationResponseDtoSchema0.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventMutationResponseDtoScoringMode.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventOverviewResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventOverviewResponseDtoHeroNpcsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventOverviewResponseDtoSchema0.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventOverviewResponseDtoScoringMode.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventRankingEntryResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventRankingEntryResponseDtoMember.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventSettingsResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventTimerResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventTimerResponseDtoNpc.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutput.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputCoverage.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputCoverageBestHeroCoverage.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputCoverageRoughestHeroCoverage.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputEvent.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputHeroesItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputHeroesItemRarityTotals.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputHeroesItemTopHunter.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputLeaders.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputLeadersLongestDuty.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputLeadersMostFlexible.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputLeadersTopAfk.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputLeadersTopEfficiency.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputLeadersTopHunter.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputLeadersTopScorer.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputLoot.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputLootHeroBreakdownItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputLootHeroBreakdownItemRarityTotals.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputLootRarityTotals.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputOverview.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventWrappedApiResponseDtoOutputOverviewRarityTotals.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerAddHeroPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerAddMapPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerAssignMapToLocationPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerAssignMemberPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerCreateLocationPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerDeleteHeroPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerDeleteLocationPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerDeleteMapPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerGetLocationsPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerReorderLocationsPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerSelfAssignMemberPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerSelfUnassignMemberPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerUnassignMemberParams.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerUnassignMemberPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerUpdateHeroPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsAssignmentControllerUpdateLocationPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsMonitoringControllerCloseRespawnWindowPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsMonitoringControllerGetActiveGapForMapPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsMonitoringControllerGetActiveGapsForHeroPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsMonitoringControllerGetHeroCoverageGapsPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsMonitoringControllerGetHeroPresenceStatsPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsMonitoringControllerGetHeroRespawnConfigPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsMonitoringControllerGetKillTimelineDataPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsMonitoringControllerGetMapCoverageGapsPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsMonitoringControllerOpenRespawnWindowPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsRankingControllerGetEventHeroStatsPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsRankingControllerGetEventKillHistoryParams.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsRankingControllerGetEventKillHistoryPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsRankingControllerGetHeroKillHistoryParams.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsRankingControllerGetHeroKillHistoryPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsRankingControllerGetKillDetailPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsRankingControllerGetMemberKillHistoryParams.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsRankingControllerGetMemberKillHistoryPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsRankingControllerUpdateKillPointPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsSettingsControllerGetSettingsPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/eventsSettingsControllerUpdateSettingsPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildKillStatsResponseDtoOutput.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildKillStatsResponseDtoOutputMemberRankingItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildKillStatsResponseDtoOutputMemberRankingItemParticipationsByType.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildKillStatsResponseDtoOutputOverview.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildKillStatsResponseDtoOutputOverviewKillsByType.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildKillStatsResponseDtoOutputOverviewParticipationsByType.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildResponseDtoOutput.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildTimerSettingsResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildTopKillersByTypeResponseDtoOutput.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildTopKillersByTypeResponseDtoOutputEVENTHEROItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildTopKillersByTypeResponseDtoOutputHEROItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildTopKillersByTypeResponseDtoOutputTITANItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildTopNpcsResponseDtoOutput.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildTopNpcsResponseDtoOutputTopNpcsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildsControllerGetGuildByIdPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildsControllerGetGuildConfigPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildsControllerGetGuildDiscordSyncStatusPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildsControllerGetGuildPermissionsPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildsControllerGetUserGuildsParams.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildsControllerGetWorldsByGuildIdPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildsControllerRefreshGuildDiscordSyncPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildsControllerUpdateGuildConfigPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildsInternalControllerGetGuildByIdOrVanityUrlPathParameters.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/guildsInternalControllerGetUserPermissionsParams.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/heroCoverageGapResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/heroCoverageGapResponseDtoGapType.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/heroCoverageGapResponseDtoMap.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/heroPresenceStatsResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/heroPresenceStatsResponseDtoMemberStatsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/heroRespawnConfigResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/heroRespawnConfigResponseDtoWindowStatus.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/index.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/killDetailResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/killDetailResponseDtoEventConfig.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/killDetailResponseDtoEventConfigScoringMode.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/killDetailResponseDtoKill.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/killDetailResponseDtoKillHeroNpc.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/killDetailResponseDtoKillHeroNpcEvent.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/killDetailResponseDtoKillPointsItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/killDetailResponseDtoKillPointsItemMapDataItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/killDetailResponseDtoKillPointsItemMember.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/killDetailResponseDtoKillPointsItemMemberRolesItem.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/killDetailResponseDtoKillTimerCreatedBy.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/killDetailResponseDtoSchema0.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/killTimelineMapResponseDto.tsis excluded by!**/generated/**apps/web/src/lib/api/generated/main/model/killTimelineMapResponseDtoAssignmentsItem.tsis excluded by!**/generated/**
📒 Files selected for processing (82)
.gitignore.oxlintrc.jsonapps/api/openapi.yamlapps/api/src/events/dto/event-kill-response.dto.tsapps/api/src/events/dto/event-monitoring-response.dto.tsapps/api/src/events/dto/event-response.dto.tsapps/api/src/events/dto/event-wrapped-response.dto.tsapps/api/src/events/events-catalog.controller.tsapps/api/src/events/events-monitoring.controller.tsapps/api/src/events/events-ranking.controller.tsapps/api/src/events/services/event-kill.service.tsapps/api/src/main.tsapps/web/src/components/layout/event-timers-list.tsxapps/web/src/components/layout/guild-pinned-events-section.tsxapps/web/src/components/layout/guilds-sidebar-nav.tsxapps/web/src/components/layout/pinned-events-banner.tsxapps/web/src/features/guild/events/components/dialogs/event-participation-confirmation-dialog.tsxapps/web/src/features/guild/events/components/dialogs/event-summary-dialog.tsxapps/web/src/features/guild/events/components/dialogs/event-summary/build-steps.tsxapps/web/src/features/guild/events/components/dialogs/event-summary/hero-spotlight.tsxapps/web/src/features/guild/events/components/dialogs/event-summary/leader-card.tsxapps/web/src/features/guild/events/components/dialogs/event-summary/rarity-breakdown.tsxapps/web/src/features/guild/events/components/heroes/hero-card.tsxapps/web/src/features/guild/events/components/heroes/hero-timer-countdown.tsxapps/web/src/features/guild/events/components/heroes/hero-timer-display.tsxapps/web/src/features/guild/events/components/heroes/hero-window-status-badge.tsxapps/web/src/features/guild/events/components/kills/kill-history-card.tsxapps/web/src/features/guild/events/components/kills/kill-map-timeline-card.tsxapps/web/src/features/guild/events/components/kills/kill-maps-timeline-section.tsxapps/web/src/features/guild/events/components/kills/recent-kills-preview.tsxapps/web/src/features/guild/events/components/maps/event-map-grid.tsxapps/web/src/features/guild/events/components/maps/map-card.tsxapps/web/src/features/guild/events/components/maps/map-coverage-timeline.tsxapps/web/src/features/guild/events/components/ranking/event-ranking-preview.tsxapps/web/src/features/guild/events/components/ranking/event-ranking-table.tsxapps/web/src/features/guild/events/components/shared/member-badge.tsxapps/web/src/features/guild/events/components/stats/event-hero-loots.tsxapps/web/src/features/guild/events/event-detail.tsxapps/web/src/features/guild/events/event-edit-rulebook-page.tsxapps/web/src/features/guild/events/event-edit-scoring-page.tsxapps/web/src/features/guild/events/event-edit-settings-page.tsxapps/web/src/features/guild/events/event-kills-history.tsxapps/web/src/features/guild/events/event-member-kills-page.tsxapps/web/src/features/guild/events/event-ranking-page.tsxapps/web/src/features/guild/events/events.tsxapps/web/src/features/guild/events/hero-detail.tsxapps/web/src/features/guild/events/hooks/index.tsapps/web/src/features/guild/events/hooks/mutations/use-create-event.tsapps/web/src/features/guild/events/hooks/mutations/use-delete-event.tsapps/web/src/features/guild/events/hooks/mutations/use-event-mutations.tsapps/web/src/features/guild/events/hooks/mutations/use-toggle-event-pin.tsapps/web/src/features/guild/events/hooks/mutations/use-update-event-settings.tsapps/web/src/features/guild/events/hooks/queries/index.tsapps/web/src/features/guild/events/hooks/queries/use-event-hero-stats.tsapps/web/src/features/guild/events/hooks/queries/use-event-hero-timers.tsapps/web/src/features/guild/events/hooks/queries/use-event-kill-history.tsapps/web/src/features/guild/events/hooks/queries/use-event-loots.tsapps/web/src/features/guild/events/hooks/queries/use-event-maps.tsapps/web/src/features/guild/events/hooks/queries/use-event-member-kill-history.tsapps/web/src/features/guild/events/hooks/queries/use-event-overview.tsapps/web/src/features/guild/events/hooks/queries/use-event-participation-confirmations.tsapps/web/src/features/guild/events/hooks/queries/use-event-ranking.tsapps/web/src/features/guild/events/hooks/queries/use-event-settings.tsapps/web/src/features/guild/events/hooks/queries/use-event-wrapped.tsapps/web/src/features/guild/events/hooks/queries/use-events.tsapps/web/src/features/guild/events/hooks/queries/use-hero-active-gaps.tsapps/web/src/features/guild/events/hooks/queries/use-hero-kill-history.tsapps/web/src/features/guild/events/hooks/queries/use-hero-presence-stats.tsapps/web/src/features/guild/events/hooks/queries/use-hero-respawn-config.tsapps/web/src/features/guild/events/hooks/queries/use-kill-detail.tsapps/web/src/features/guild/events/hooks/queries/use-kill-timeline.tsapps/web/src/features/guild/events/hooks/queries/use-map-coverage-timer.tsapps/web/src/features/guild/events/hooks/queries/use-matching-loots.tsapps/web/src/features/guild/events/hooks/queries/use-ranking-edit-history.tsapps/web/src/features/guild/events/hooks/queries/use-recent-hero-kills.tsapps/web/src/features/guild/events/kill-detail.tsxapps/web/src/features/guild/events/types/api.tsapps/web/src/features/guild/events/utils/find-event-hero-timer.spec.tsapps/web/src/features/guild/events/utils/find-event-hero-timer.tsapps/web/src/features/guild/events/utils/normalize-bonus-breakdown.tsapps/web/src/features/guild/events/utils/scoring-rules.tsapps/web/src/lib/api-client/api-client.ts
💤 Files with no reviewable changes (16)
- apps/web/src/features/guild/events/hooks/index.ts
- apps/web/src/features/guild/events/hooks/queries/use-event-wrapped.ts
- apps/web/src/features/guild/events/hooks/queries/use-events.ts
- apps/web/src/features/guild/events/hooks/queries/use-event-ranking.ts
- apps/web/src/features/guild/events/hooks/queries/use-event-participation-confirmations.ts
- apps/web/src/features/guild/events/hooks/queries/use-event-maps.ts
- apps/web/src/features/guild/events/hooks/queries/use-hero-active-gaps.ts
- apps/web/src/features/guild/events/hooks/queries/use-event-hero-stats.ts
- apps/web/src/features/guild/events/hooks/queries/use-hero-presence-stats.ts
- apps/web/src/features/guild/events/hooks/queries/use-event-overview.ts
- apps/web/src/features/guild/events/hooks/queries/use-hero-respawn-config.ts
- apps/web/src/features/guild/events/hooks/queries/use-kill-timeline.ts
- apps/web/src/features/guild/events/hooks/queries/use-event-settings.ts
- apps/web/src/features/guild/events/hooks/queries/use-event-hero-timers.ts
- apps/web/src/features/guild/events/hooks/queries/use-ranking-edit-history.ts
- apps/web/src/features/guild/events/hooks/queries/index.ts
✅ Files skipped from review due to trivial changes (24)
- .oxlintrc.json
- apps/web/src/features/guild/events/components/dialogs/event-summary/rarity-breakdown.tsx
- .gitignore
- apps/web/src/features/guild/events/components/dialogs/event-summary/leader-card.tsx
- apps/web/src/features/guild/events/components/heroes/hero-timer-countdown.tsx
- apps/web/src/features/guild/events/components/dialogs/event-summary/hero-spotlight.tsx
- apps/web/src/features/guild/events/components/maps/map-card.tsx
- apps/web/src/features/guild/events/components/kills/kill-map-timeline-card.tsx
- apps/web/src/features/guild/events/components/heroes/hero-timer-display.tsx
- apps/web/src/features/guild/events/components/ranking/event-ranking-preview.tsx
- apps/web/src/features/guild/events/components/maps/event-map-grid.tsx
- apps/web/src/components/layout/pinned-events-banner.tsx
- apps/web/src/features/guild/events/components/stats/event-hero-loots.tsx
- apps/web/src/features/guild/events/utils/find-event-hero-timer.spec.ts
- apps/web/src/features/guild/events/utils/find-event-hero-timer.ts
- apps/web/src/features/guild/events/components/kills/recent-kills-preview.tsx
- apps/api/src/events/services/event-kill.service.ts
- apps/web/src/features/guild/events/components/maps/map-coverage-timeline.tsx
- apps/web/src/features/guild/events/event-member-kills-page.tsx
- apps/web/src/features/guild/events/hooks/queries/use-event-member-kill-history.ts
- apps/web/src/features/guild/events/utils/scoring-rules.ts
- apps/web/src/features/guild/events/utils/normalize-bonus-breakdown.ts
- apps/web/src/features/guild/events/types/api.ts
- apps/web/src/features/guild/events/hooks/queries/use-kill-detail.ts
🚧 Files skipped from review as they are similar to previous changes (21)
- apps/web/src/features/guild/events/components/shared/member-badge.tsx
- apps/web/src/features/guild/events/components/heroes/hero-card.tsx
- apps/web/src/features/guild/events/event-kills-history.tsx
- apps/web/src/features/guild/events/hooks/queries/use-event-kill-history.ts
- apps/web/src/features/guild/events/components/ranking/event-ranking-table.tsx
- apps/web/src/features/guild/events/hooks/mutations/use-delete-event.ts
- apps/web/src/features/guild/events/event-edit-scoring-page.tsx
- apps/web/src/features/guild/events/kill-detail.tsx
- apps/api/src/events/events-monitoring.controller.ts
- apps/web/src/components/layout/guilds-sidebar-nav.tsx
- apps/web/src/features/guild/events/components/heroes/hero-window-status-badge.tsx
- apps/web/src/features/guild/events/event-ranking-page.tsx
- apps/web/src/features/guild/events/hooks/queries/use-event-loots.ts
- apps/web/src/lib/api-client/api-client.ts
- apps/api/src/main.ts
- apps/web/src/features/guild/events/hooks/queries/use-matching-loots.ts
- apps/web/src/features/guild/events/events.tsx
- apps/web/src/features/guild/events/event-detail.tsx
- apps/web/src/features/guild/events/hooks/queries/use-map-coverage-timer.ts
- apps/web/src/features/guild/events/hooks/queries/use-recent-hero-kills.ts
- apps/api/src/events/dto/event-monitoring-response.dto.ts
| const EventKillParticipantMapDataResponseSchema = z.object({ | ||
| mapId: z.string(), | ||
| mapName: z.string(), |
There was a problem hiding this comment.
Align mapId type across event DTOs.
Line 30 defines mapId as string, while apps/api/src/events/dto/event-response.dto.ts Line 34 defines mapId as number for the same domain field name. This will produce conflicting generated client types and can break cross-endpoint consumers.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/api/src/events/dto/event-kill-response.dto.ts` around lines 29 - 31, The
EventKillParticipantMapDataResponseSchema defines mapId as z.string() but other
event DTOs (see EventResponse DTO's mapId) use a number; update
EventKillParticipantMapDataResponseSchema to use the same type as the canonical
event DTO (change mapId to z.number() if the canonical is numeric) so generated
client types remain consistent — adjust any related parsing or serialization in
code that constructs or consumes EventKillParticipantMapDataResponseSchema to
handle the numeric mapId.
Summary by CodeRabbit
Documentation
New Features
Bug Fixes