diff --git a/src/app.html b/src/app.html
index aedc548..4158c07 100644
--- a/src/app.html
+++ b/src/app.html
@@ -9,7 +9,7 @@
%sveltekit.head%
-
+
%sveltekit.body%
diff --git a/src/lib/api/matches.ts b/src/lib/api/matches.ts
index f2c7873..e42d932 100644
--- a/src/lib/api/matches.ts
+++ b/src/lib/api/matches.ts
@@ -1,6 +1,6 @@
import { apiClient } from './client';
import {
- parseMatchRounds,
+ parseMatchRoundsSafe,
parseMatchWeapons,
parseMatchChat,
parseMatchParseResponse
@@ -69,13 +69,22 @@ export const matchesAPI = {
* Get match round-by-round statistics
* @param matchId - Match ID
* @returns Round statistics and economy data
+ * @throws Error if data is invalid or demo not parsed yet
*/
async getMatchRounds(matchId: string | number): Promise {
const url = `/match/${matchId}/rounds`;
- const data = await apiClient.get(url);
+ const data = await apiClient.get(url);
- // Validate with Zod schema
- return parseMatchRounds(data);
+ // Validate with Zod schema using safe parse
+ // This handles cases where the demo hasn't been parsed yet
+ const result = parseMatchRoundsSafe(data);
+
+ if (!result.success) {
+ // If validation fails, it's likely the demo hasn't been parsed yet
+ throw new Error('Demo not parsed yet or invalid response format');
+ }
+
+ return result.data;
},
/**
@@ -117,30 +126,33 @@ export const matchesAPI = {
const limit = params?.limit || 50;
// CRITICAL: API returns a plain array, not a wrapped object
- // We request limit + 1 to detect if there are more pages
+ // NOTE: Backend has a hard limit of 20 matches per request
+ // We assume hasMore = true if we get exactly the limit we requested
const data = await apiClient.get(url, {
params: {
- limit: limit + 1, // Request one extra to check if there are more
+ limit: limit,
map: params?.map,
player_id: params?.player_id
}
});
- // Check if there are more matches (if we got the extra one)
- const hasMore = data.length > limit;
+ // Handle null or empty response
+ if (!data || !Array.isArray(data)) {
+ console.warn('[API] getMatches received null or invalid data');
+ return transformMatchesListResponse([], false, undefined);
+ }
- // Remove the extra match if we have more
- const matchesToReturn = hasMore ? data.slice(0, limit) : data;
+ // If we got exactly the limit, assume there might be more
+ // If we got less, we've reached the end
+ const hasMore = data.length === limit;
- // If there are more matches, use the timestamp of the last match for pagination
- // This timestamp is used in the next request: /matches/next/{timestamp}
- const lastMatch =
- matchesToReturn.length > 0 ? matchesToReturn[matchesToReturn.length - 1] : undefined;
- const nextPageTime =
- hasMore && lastMatch ? Math.floor(new Date(lastMatch.date).getTime() / 1000) : undefined;
+ // Get the timestamp from the LAST match BEFORE transformation
+ // The legacy API format has `date` as a Unix timestamp (number)
+ const lastLegacyMatch = data.length > 0 ? data[data.length - 1] : undefined;
+ const nextPageTime = hasMore && lastLegacyMatch ? lastLegacyMatch.date : undefined;
// Transform legacy API response to new format
- return transformMatchesListResponse(matchesToReturn, hasMore, nextPageTime);
+ return transformMatchesListResponse(data, hasMore, nextPageTime);
},
/**
@@ -153,28 +165,25 @@ export const matchesAPI = {
const limit = params?.limit || 20;
// API returns a plain array, not a wrapped object
+ // Backend has a hard limit of 20 matches per request
const data = await apiClient.getCancelable(url, 'match-search', {
params: {
- limit: limit + 1, // Request one extra to check if there are more
+ limit: limit,
map: params?.map,
player_id: params?.player_id
}
});
- // Check if there are more matches (if we got the extra one)
- const hasMore = data.length > limit;
+ // If we got exactly the limit, assume there might be more
+ const hasMore = data.length === limit;
- // Remove the extra match if we have more
- const matchesToReturn = hasMore ? data.slice(0, limit) : data;
-
- // If there are more matches, use the timestamp of the last match for pagination
- const lastMatch =
- matchesToReturn.length > 0 ? matchesToReturn[matchesToReturn.length - 1] : undefined;
- const nextPageTime =
- hasMore && lastMatch ? Math.floor(new Date(lastMatch.date).getTime() / 1000) : undefined;
+ // Get the timestamp from the LAST match BEFORE transformation
+ // The legacy API format has `date` as a Unix timestamp (number)
+ const lastLegacyMatch = data.length > 0 ? data[data.length - 1] : undefined;
+ const nextPageTime = hasMore && lastLegacyMatch ? lastLegacyMatch.date : undefined;
// Transform legacy API response to new format
- return transformMatchesListResponse(matchesToReturn, hasMore, nextPageTime);
+ return transformMatchesListResponse(data, hasMore, nextPageTime);
},
/**
diff --git a/src/lib/components/match/ShareCodeInput.svelte b/src/lib/components/match/ShareCodeInput.svelte
index a647d64..b642b6c 100644
--- a/src/lib/components/match/ShareCodeInput.svelte
+++ b/src/lib/components/match/ShareCodeInput.svelte
@@ -1,7 +1,7 @@