-
Notifications
You must be signed in to change notification settings - Fork 351
Add IPAPI integration for enhanced geolocation data #606
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
- Added IPAPI_KEY environment variable to docker-compose configuration for cloud services. - Updated settings.local.json to include a new WebFetch domain for ipapi.is. - Enhanced geolocation functionality in the server by integrating IPAPI for IP lookups, including additional fields for company and ASN data. - Refactored getLocation function to utilize IPAPI when in cloud environment, improving accuracy and detail of geolocation responses. - Updated tracking utilities to accommodate new geolocation data structure, ensuring comprehensive analytics capabilities.
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Warning Rate limit exceeded@goldflag has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 10 minutes and 5 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
WalkthroughAdds ipapi.is and IPAPI_KEY support for cloud geolocation; extends ClickHouse events schema with timezone/ASN/company/proxy fields; refactors geolocation to batch IP lookups returning ip→LocationResponse; updates tracking, pageview enrichment, validation, filters, and UI to consume enriched geo data; tweaks 401 message. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client
participant Tracker as PageviewQueue
participant Geo as Geolocation Service
participant IPAPI as ipapi.is
participant GeoDB as Local GeoIP DB
participant CH as ClickHouse
Client->>Tracker: Send batch of pageviews (with IPs)
Tracker->>Geo: getLocation(ips[])
alt Cloud mode (IS_CLOUD && IPAPI_KEY)
Geo->>IPAPI: Batch fetch metadata for unique IPs
IPAPI-->>Geo: Map of IP → enriched LocationResponse
else Local mode
loop per unique IP
Geo->>GeoDB: city(ip)
GeoDB-->>Geo: nullable geo result
end
end
Geo-->>Tracker: Record<string, LocationResponse>
Tracker->>CH: Bulk insert pageviews enriched with new fields
CH-->>Tracker: Ack
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (1)
server/src/db/geolocation/geolocation.ts (1)
206-222
: Guard against NaN abuse scores and spurious company/ASN objects.When IPAPI omits the
company
/asn
blocks or their abuse scores, the current code still instantiates those sub-objects and callsNumber(undefined)
, yieldingNaN
. That leaks into downstream analytics payloads and storage even though no enrichment data exists. Let’s only build those objects when the API actually returned them, and only parse the abuse score when we have a string to work with.- results[ip] = { + const companyAbuseScore = item.company?.abuser_score; + const asnAbuseScore = item.asn?.abuser_score; + + results[ip] = { city: item.location?.city, country: item.location?.country, countryIso: item.location?.country_code, latitude: item.location?.latitude, longitude: item.location?.longitude, timeZone: item.location?.timezone, vpn: item.vpn?.service, crawler: typeof item.is_crawler === "string" ? item.is_crawler : undefined, datacenter: item.datacenter?.datacenter, isProxy: item.is_proxy, isTor: item.is_tor, isSatellite: item.is_satellite, - - company: { - name: item.company?.name, - domain: item.company?.domain, - type: item.company?.type, - abuseScore: Number(item.company?.abuser_score?.split(" ")[0]), - }, - - asn: { - asn: item.asn?.asn, - org: item.asn?.org, - domain: item.asn?.domain, - type: item.asn?.type, - abuseScore: Number(item.asn?.abuser_score?.split(" ")[0]), - }, + company: item.company + ? { + name: item.company.name, + domain: item.company.domain, + type: item.company.type, + abuseScore: companyAbuseScore ? Number.parseFloat(companyAbuseScore.split(" ")[0]) : undefined, + } + : undefined, + asn: item.asn + ? { + asn: item.asn.asn, + org: item.asn.org, + domain: item.asn.domain, + type: item.asn.type, + abuseScore: asnAbuseScore ? Number.parseFloat(asnAbuseScore.split(" ")[0]) : undefined, + } + : undefined, };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
.claude/settings.local.json
(1 hunks)docker-compose.cloud.yml
(1 hunks)server/src/db/clickhouse/clickhouse.ts
(1 hunks)server/src/db/geolocation/geolocation.ts
(4 hunks)server/src/index.ts
(1 hunks)server/src/services/replay/trackingUtils.ts
(1 hunks)server/src/services/tracker/pageviewQueue.ts
(2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
{client,server}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
{client,server}/**/*.{ts,tsx}
: Use TypeScript with strict typing throughout both client and server
Use try/catch blocks with specific error types for error handling
Use camelCase for variables and functions, PascalCase for components and types
Group imports by external, then internal, and sort alphabetically within groups
Files:
server/src/db/geolocation/geolocation.ts
server/src/services/tracker/pageviewQueue.ts
server/src/services/replay/trackingUtils.ts
server/src/index.ts
server/src/db/clickhouse/clickhouse.ts
server/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Backend: Use Fastify, Drizzle ORM (Postgres), ClickHouse, and Zod
Files:
server/src/db/geolocation/geolocation.ts
server/src/services/tracker/pageviewQueue.ts
server/src/services/replay/trackingUtils.ts
server/src/index.ts
server/src/db/clickhouse/clickhouse.ts
🧬 Code graph analysis (3)
server/src/db/geolocation/geolocation.ts (1)
server/src/lib/logger/logger.ts (1)
logger
(67-67)
server/src/services/tracker/pageviewQueue.ts (1)
server/src/db/geolocation/geolocation.ts (1)
getLocation
(229-253)
server/src/services/replay/trackingUtils.ts (1)
server/src/db/geolocation/geolocation.ts (1)
getLocation
(229-253)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Build Client Images (ubuntu-24.04-arm, linux/arm64)
- GitHub Check: Build Client Images (ubuntu-latest, linux/amd64)
const geoData = await getLocation([ipAddress]); | ||
|
||
const countryCode = geoData?.countryIso || ""; | ||
const regionCode = geoData?.subdivisions?.[0]?.isoCode || ""; | ||
const latitude = geoData?.latitude || 0; | ||
const longitude = geoData?.longitude || 0; | ||
const city = geoData?.city || ""; | ||
const countryCode = geoData?.[ipAddress]?.countryIso || ""; | ||
const regionCode = geoData?.[ipAddress]?.subdivisions?.[0]?.isoCode || ""; | ||
const latitude = geoData?.[ipAddress]?.latitude || 0; | ||
const longitude = geoData?.[ipAddress]?.longitude || 0; | ||
const city = geoData?.[ipAddress]?.city || ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reintroduce defensive geo lookup handling
Dropping the try/catch
means any transient network/IPAPI failure now rejects parseTrackingData
, so replay/pageview ingestion blows up instead of gracefully omitting geo info as before. Please restore the guard so we still emit tracking data when lookup fails.
- const geoData = await getLocation([ipAddress]);
+ const geoData = await getLocation([ipAddress]).catch(_error => {
+ return {} as Awaited<ReturnType<typeof getLocation>>;
+ });
📝 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 geoData = await getLocation([ipAddress]); | |
const countryCode = geoData?.countryIso || ""; | |
const regionCode = geoData?.subdivisions?.[0]?.isoCode || ""; | |
const latitude = geoData?.latitude || 0; | |
const longitude = geoData?.longitude || 0; | |
const city = geoData?.city || ""; | |
const countryCode = geoData?.[ipAddress]?.countryIso || ""; | |
const regionCode = geoData?.[ipAddress]?.subdivisions?.[0]?.isoCode || ""; | |
const latitude = geoData?.[ipAddress]?.latitude || 0; | |
const longitude = geoData?.[ipAddress]?.longitude || 0; | |
const city = geoData?.[ipAddress]?.city || ""; | |
const geoData = await getLocation([ipAddress]).catch(_error => { | |
return {} as Awaited<ReturnType<typeof getLocation>>; | |
}); | |
const countryCode = geoData?.[ipAddress]?.countryIso || ""; | |
const regionCode = geoData?.[ipAddress]?.subdivisions?.[0]?.isoCode || ""; | |
const latitude = geoData?.[ipAddress]?.latitude || 0; | |
const longitude = geoData?.[ipAddress]?.longitude || 0; | |
const city = geoData?.[ipAddress]?.city || ""; |
🤖 Prompt for AI Agents
In server/src/services/replay/trackingUtils.ts around lines 40 to 46, the direct
call to getLocation([ipAddress]) can throw and now bubbles up; reintroduce
defensive handling by wrapping the geo lookup in a try/catch, on success extract
countryCode/regionCode/latitude/longitude/city as currently done, and on any
error (or if geoData is undefined) set those variables to their safe defaults
(empty strings or zeros) and optionally log a debug/warn message; ensure
parseTrackingData continues and returns tracking data without geo info when
lookup fails.
const geoData = await getLocation(ips); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prevent getLocation failures from freezing the queue
await getLocation(ips)
now executes before the try/finally
that resets this.processing
. If IPAPI errors (network, quota, etc.), the rejection propagates, processing
stays true
, and the queue stops draining. Please catch the lookup failure, log it, and continue with empty geo data so the worker keeps running.
- const geoData = await getLocation(ips);
+ let geoData: Awaited<ReturnType<typeof getLocation>> | undefined;
+ try {
+ geoData = await getLocation(ips);
+ } catch (error) {
+ this.logger.error(error, "Failed to fetch geo data");
+ geoData = {} as Awaited<ReturnType<typeof getLocation>>;
+ }
📝 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 geoData = await getLocation(ips); | |
// Replace the single await call with a safe wrapper | |
let geoData: Awaited<ReturnType<typeof getLocation>> | undefined; | |
try { | |
geoData = await getLocation(ips); | |
} catch (error) { | |
this.logger.error(error, "Failed to fetch geo data"); | |
geoData = {} as Awaited<ReturnType<typeof getLocation>>; | |
} |
🤖 Prompt for AI Agents
In server/src/services/tracker/pageviewQueue.ts around lines 45-46, calling
await getLocation(ips) occurs before the try/finally that resets this.processing
which lets failures leave processing=true and freeze the queue; wrap the
getLocation call in a try/catch (or move it inside the existing try) so any
rejection is caught, log the error with context, and fall back to an
empty/default geoData object so processing continues; keep the finally block
that sets this.processing = false untouched so the flag is always cleared.
…flags - Updated the handling of is_proxy, is_tor, and is_satellite properties to set them to null if they are undefined, improving data consistency in the pageviewQueue service.
- Updated the assignment of company_abuse_score and asn_abuse_score to use nullish coalescing for better handling of undefined values. - Simplified the assignment of is_proxy, is_tor, and is_satellite properties to default to null if they are undefined, enhancing data consistency in the pageviewQueue service.
- Introduced new filter options for timezone, VPN, crawler, datacenter, company, company type, company domain, ASN org, ASN type, and ASN domain in the Filters component. - Updated the getParameterNameLabel function to include labels for the new filter parameters. - Enhanced the Countries component to support a new tab for timezones. - Modified the Events component layout for improved display. - Updated query validation and shared filter types to accommodate new parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
client/src/app/[site]/main/components/sections/Network.tsx (1)
52-86
: Prefer user-friendly boolean labels in Network tabsRight now the VPN/Crawler/Datacenter rows surface the literal
true
/false
strings, which reads a bit raw in the UI. A tiny helper keeps the filter payloads untouched while presenting “Yes”/“No” (with an “Unknown” fallback) to match how we phrase other boolean pivots.export function Network() { const [tab, setTab] = useState<Tab>("vpn"); const [expanded, setExpanded] = useState(false); const close = () => { setExpanded(false); }; + const formatBooleanLabel = (value: string | null | undefined) => { + if (value === "true") return "Yes"; + if (value === "false") return "No"; + return "Unknown"; + }; + return ( @@ <TabsContent value="vpn"> <StandardSection filterParameter="vpn" title="VPN" getValue={e => e.value} getKey={e => e.value} - getFilterLabel={e => e.value} + getFilterLabel={e => formatBooleanLabel(e.value)} expanded={expanded} close={close} - getLabel={e => e.value} + getLabel={e => formatBooleanLabel(e.value)} /> </TabsContent> <TabsContent value="crawler"> <StandardSection filterParameter="crawler" title="Crawler" getValue={e => e.value} getKey={e => e.value} - getFilterLabel={e => e.value} + getFilterLabel={e => formatBooleanLabel(e.value)} expanded={expanded} close={close} - getLabel={e => e.value} + getLabel={e => formatBooleanLabel(e.value)} /> </TabsContent> <TabsContent value="datacenter"> <StandardSection filterParameter="datacenter" title="Datacenter" getValue={e => e.value} getKey={e => e.value} - getFilterLabel={e => e.value} + getFilterLabel={e => formatBooleanLabel(e.value)} expanded={expanded} close={close} - getLabel={e => e.value} + getLabel={e => formatBooleanLabel(e.value)} /> </TabsContent>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
client/src/app/[site]/components/shared/Filters/const.tsx
(4 hunks)client/src/app/[site]/components/shared/Filters/utils.ts
(1 hunks)client/src/app/[site]/main/components/sections/Countries.tsx
(3 hunks)client/src/app/[site]/main/components/sections/Events.tsx
(2 hunks)client/src/app/[site]/main/components/sections/Network.tsx
(1 hunks)client/src/app/[site]/main/page.tsx
(2 hunks)server/src/api/analytics/query-validation.ts
(1 hunks)shared/src/filters.ts
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
{client,server}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
{client,server}/**/*.{ts,tsx}
: Use TypeScript with strict typing throughout both client and server
Use try/catch blocks with specific error types for error handling
Use camelCase for variables and functions, PascalCase for components and types
Group imports by external, then internal, and sort alphabetically within groups
Files:
client/src/app/[site]/main/components/sections/Network.tsx
client/src/app/[site]/components/shared/Filters/const.tsx
client/src/app/[site]/main/components/sections/Events.tsx
server/src/api/analytics/query-validation.ts
client/src/app/[site]/main/page.tsx
client/src/app/[site]/main/components/sections/Countries.tsx
client/src/app/[site]/components/shared/Filters/utils.ts
client/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Frontend: Use Next.js, Tailwind CSS, Shadcn UI, Tanstack Query, Zustand, Luxon, Nivo, and react-hook-form
Files:
client/src/app/[site]/main/components/sections/Network.tsx
client/src/app/[site]/components/shared/Filters/const.tsx
client/src/app/[site]/main/components/sections/Events.tsx
client/src/app/[site]/main/page.tsx
client/src/app/[site]/main/components/sections/Countries.tsx
client/src/app/[site]/components/shared/Filters/utils.ts
server/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Backend: Use Fastify, Drizzle ORM (Postgres), ClickHouse, and Zod
Files:
server/src/api/analytics/query-validation.ts
🧬 Code graph analysis (3)
client/src/app/[site]/main/components/sections/Network.tsx (1)
client/src/app/[site]/components/shared/StandardSection/StandardSection.tsx (1)
StandardSection
(16-132)
client/src/app/[site]/main/page.tsx (1)
client/src/app/[site]/main/components/sections/Network.tsx (1)
Network
(21-164)
client/src/app/[site]/main/components/sections/Countries.tsx (1)
client/src/app/[site]/components/shared/StandardSection/StandardSection.tsx (1)
StandardSection
(16-132)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build Client Images (ubuntu-24.04-arm, linux/arm64)
- GitHub Check: Build Client Images (ubuntu-latest, linux/amd64)
- GitHub Check: Build Backend Images (ubuntu-24.04-arm, linux/arm64)
🔇 Additional comments (5)
client/src/app/[site]/components/shared/Filters/utils.ts (1)
54-73
: New geo/network filter labels wired correctlyThese cases cover every new
FilterParameter
literal so the UI keeps presenting human-friendly labels once the enriched geo data flows through. Nice sync with the shared types.client/src/app/[site]/main/components/sections/Events.tsx (2)
24-30
: Scroll limiting keeps long event lists containedThe
max-h
plusoverflow-y-auto
pairing prevents tall result sets from stretching the layout while preserving the loader overlay setup. Looks good.
64-64
: Card height adjustment aligns with the new list windowLocking the card height to 405px pairs cleanly with the 344px scroll area, keeping the section visually balanced with neighboring cards.
shared/src/filters.ts (1)
28-38
: Shared filter parameter union matches the new facetsThe union now includes the timezone/VPN/company/ASN keys, keeping shared typing in sync with both server validation and the client filter options.
server/src/api/analytics/query-validation.ts (1)
213-222
: Server filter schema updated for enriched geo fieldsAdding the new literals to
filterParamSchema
ensures backend validation accepts the expanded geo/network filters emitted by the client and shared types.
…ng options - Updated tab labels for VPN, Crawler, and Datacenter to be more descriptive. - Added custom rendering for VPN and Crawler labels to include icons. - Enhanced the display of domain labels with favicons and links for better user experience. - Removed unnecessary skeleton loading elements from SessionDetails component for cleaner UI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (13)
client/public/crawlers/Ahrefs.svg
is excluded by!**/*.svg
client/public/crawlers/Apple.svg
is excluded by!**/*.svg
client/public/crawlers/Bing.svg
is excluded by!**/*.svg
client/public/crawlers/DuckDuckGo.svg
is excluded by!**/*.svg
client/public/crawlers/Google.svg
is excluded by!**/*.svg
client/public/crawlers/Yandex.svg
is excluded by!**/*.svg
client/public/vpns/AirVPN.svg
is excluded by!**/*.svg
client/public/vpns/ExpressVPN.svg
is excluded by!**/*.svg
client/public/vpns/Mullvad.svg
is excluded by!**/*.svg
client/public/vpns/NordVPN.svg
is excluded by!**/*.svg
client/public/vpns/PIA.svg
is excluded by!**/*.svg
client/public/vpns/ProtonVPN.svg
is excluded by!**/*.svg
client/public/vpns/Surfshark.svg
is excluded by!**/*.svg
📒 Files selected for processing (4)
client/src/app/[site]/components/shared/icons/Crawler.tsx
(1 hunks)client/src/app/[site]/components/shared/icons/VPN.tsx
(1 hunks)client/src/app/[site]/main/components/sections/Network.tsx
(1 hunks)client/src/components/Sessions/SessionDetails.tsx
(0 hunks)
💤 Files with no reviewable changes (1)
- client/src/components/Sessions/SessionDetails.tsx
🧰 Additional context used
📓 Path-based instructions (2)
{client,server}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
{client,server}/**/*.{ts,tsx}
: Use TypeScript with strict typing throughout both client and server
Use try/catch blocks with specific error types for error handling
Use camelCase for variables and functions, PascalCase for components and types
Group imports by external, then internal, and sort alphabetically within groups
Files:
client/src/app/[site]/components/shared/icons/VPN.tsx
client/src/app/[site]/components/shared/icons/Crawler.tsx
client/src/app/[site]/main/components/sections/Network.tsx
client/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Frontend: Use Next.js, Tailwind CSS, Shadcn UI, Tanstack Query, Zustand, Luxon, Nivo, and react-hook-form
Files:
client/src/app/[site]/components/shared/icons/VPN.tsx
client/src/app/[site]/components/shared/icons/Crawler.tsx
client/src/app/[site]/main/components/sections/Network.tsx
🧬 Code graph analysis (1)
client/src/app/[site]/main/components/sections/Network.tsx (4)
client/src/app/[site]/components/shared/StandardSection/StandardSection.tsx (1)
StandardSection
(16-132)client/src/app/[site]/components/shared/icons/VPN.tsx (1)
VPN
(14-24)client/src/app/[site]/components/shared/icons/Crawler.tsx (1)
Crawler
(13-29)client/src/components/Favicon.tsx (1)
Favicon
(4-29)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Build Client Images (ubuntu-latest, linux/amd64)
- GitHub Check: Build Client Images (ubuntu-24.04-arm, linux/arm64)
<div className="w-10"> | ||
<Button size="smIcon" onClick={() => setExpanded(!expanded)}> | ||
<Expand /> | ||
</Button> | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Give the expand button an accessible label.
This icon-only trigger has no accessible name because the Expand
icon is rendered aria-hidden
, so assistive tech users just hear “button”. Add an aria-label
(or visible text) that reflects the current action.
- <Button size="smIcon" onClick={() => setExpanded(!expanded)}>
- <Expand />
- </Button>
+ <Button
+ size="smIcon"
+ onClick={() => setExpanded(!expanded)}
+ aria-label={expanded ? "Collapse network section" : "Expand network section"}
+ >
+ <Expand />
+ </Button>
📝 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.
<div className="w-10"> | |
<Button size="smIcon" onClick={() => setExpanded(!expanded)}> | |
<Expand /> | |
</Button> | |
</div> | |
<div className="w-10"> | |
<Button | |
size="smIcon" | |
onClick={() => setExpanded(!expanded)} | |
aria-label={expanded ? "Collapse network section" : "Expand network section"} | |
> | |
<Expand /> | |
</Button> | |
</div> |
🤖 Prompt for AI Agents
In client/src/app/[site]/main/components/sections/Network.tsx around lines 49 to
53, the icon-only Expand button has no accessible name because the Expand icon
is aria-hidden; add an accessible label by passing an aria-label that reflects
the current state (e.g., aria-label={expanded ? "Collapse network" : "Expand
network"}) and also include aria-expanded={expanded} on the button so assistive
tech users know the action and state.
…sed on cloud environment - Updated MainPageContent to include conditional rendering of the Network component when IS_CLOUD is true. - Enhanced the Network component by reorganizing imports for better structure and readability. - Removed unused tooltip elements from SessionCard to streamline the UI.
- Updated getLocation function to accept an optional parameter for local IP usage. - Modified conditional logic to allow local geolocation retrieval when specified. - Adjusted tracking utilities to utilize the new local IP lookup feature for improved data accuracy.
- Updated getLocation function to streamline local IP retrieval by introducing getLocationFromLocal. - Adjusted response handling to ensure accurate mapping of IP addresses to location data. - Enhanced conditional logic for cloud environment checks while maintaining support for local lookups.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
server/src/db/geolocation/geolocation.ts
(4 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
{client,server}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
{client,server}/**/*.{ts,tsx}
: Use TypeScript with strict typing throughout both client and server
Use try/catch blocks with specific error types for error handling
Use camelCase for variables and functions, PascalCase for components and types
Group imports by external, then internal, and sort alphabetically within groups
Files:
server/src/db/geolocation/geolocation.ts
server/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Backend: Use Fastify, Drizzle ORM (Postgres), ClickHouse, and Zod
Files:
server/src/db/geolocation/geolocation.ts
🧬 Code graph analysis (1)
server/src/db/geolocation/geolocation.ts (1)
server/src/lib/logger/logger.ts (1)
logger
(67-67)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Build Client Images (ubuntu-latest, linux/amd64)
- GitHub Check: Build Client Images (ubuntu-24.04-arm, linux/arm64)
company: { | ||
name: item.company?.name, | ||
domain: item.company?.domain, | ||
type: item.company?.type, | ||
abuseScore: Number(item.company?.abuser_score?.split(" ")[0]), | ||
}, | ||
|
||
asn: { | ||
asn: item.asn?.asn, | ||
org: item.asn?.org, | ||
domain: item.asn?.domain, | ||
type: item.asn?.type, | ||
abuseScore: Number(item.asn?.abuser_score?.split(" ")[0]), | ||
}, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix crash when abuse_score is absent
item.company?.abuser_score?.split(" ")[0]
(and the ASN variant) still indexes [0]
on the result even when abuser_score
is undefined
, so the first IPAPI response missing that field will throw a TypeError
and take down the lookup. Please guard the index before converting to a number.
- results[ip] = {
+ const companyAbuseScoreRaw = item.company?.abuser_score;
+ const companyAbuseScore =
+ companyAbuseScoreRaw != null ? Number.parseFloat(companyAbuseScoreRaw) : undefined;
+ const asnAbuseScoreRaw = item.asn?.abuser_score;
+ const asnAbuseScore =
+ asnAbuseScoreRaw != null ? Number.parseFloat(asnAbuseScoreRaw) : undefined;
+
+ results[ip] = {
city: item.location?.city,
@@
company: {
name: item.company?.name,
domain: item.company?.domain,
type: item.company?.type,
- abuseScore: Number(item.company?.abuser_score?.split(" ")[0]),
+ abuseScore: companyAbuseScore,
},
@@
asn: {
asn: item.asn?.asn,
org: item.asn?.org,
domain: item.asn?.domain,
type: item.asn?.type,
- abuseScore: Number(item.asn?.abuser_score?.split(" ")[0]),
+ abuseScore: asnAbuseScore,
},
📝 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.
company: { | |
name: item.company?.name, | |
domain: item.company?.domain, | |
type: item.company?.type, | |
abuseScore: Number(item.company?.abuser_score?.split(" ")[0]), | |
}, | |
asn: { | |
asn: item.asn?.asn, | |
org: item.asn?.org, | |
domain: item.asn?.domain, | |
type: item.asn?.type, | |
abuseScore: Number(item.asn?.abuser_score?.split(" ")[0]), | |
}, | |
}; | |
const companyAbuseScoreRaw = item.company?.abuser_score; | |
const companyAbuseScore = | |
companyAbuseScoreRaw != null | |
? Number.parseFloat(companyAbuseScoreRaw) | |
: undefined; | |
const asnAbuseScoreRaw = item.asn?.abuser_score; | |
const asnAbuseScore = | |
asnAbuseScoreRaw != null | |
? Number.parseFloat(asnAbuseScoreRaw) | |
: undefined; | |
results[ip] = { | |
company: { | |
name: item.company?.name, | |
domain: item.company?.domain, | |
type: item.company?.type, | |
abuseScore: companyAbuseScore, | |
}, | |
asn: { | |
asn: item.asn?.asn, | |
org: item.asn?.org, | |
domain: item.asn?.domain, | |
type: item.asn?.type, | |
abuseScore: asnAbuseScore, | |
}, | |
}; |
🤖 Prompt for AI Agents
In server/src/db/geolocation/geolocation.ts around lines 206 to 220, the code
calls item.company?.abuser_score?.split(" ")[0] (and the same for item.asn)
which will throw if abuser_score is undefined because it still indexes [0];
change this to safely extract the numeric part by first checking that
abuser_score is a string (or non-null), then splitting and verifying the split
array has an element 0 before passing it to Number (or use a parseInt fallback),
and return a safe default (null or 0) when absent so the lookup does not crash.
} catch (error) { | ||
console.error("Error fetching location:", error); | ||
return { error: "Failed to fetch location" }; | ||
logger.error("Error fetching from IPAPI:", error); | ||
return {}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fall back to the local GeoIP reader on IPAPI failures
When fetch
throws (network error, timeout, etc.) we now return an empty map, which discards all geolocation data in cloud environments. Please reuse the existing local fallback so analytics still receive best-effort geo data.
} catch (error) {
logger.error("Error fetching from IPAPI:", error);
- return {};
+ return getLocationFromLocal(ips);
}
📝 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.
} catch (error) { | |
console.error("Error fetching location:", error); | |
return { error: "Failed to fetch location" }; | |
logger.error("Error fetching from IPAPI:", error); | |
return {}; | |
} | |
} catch (error) { | |
logger.error("Error fetching from IPAPI:", error); | |
return getLocationFromLocal(ips); | |
} |
🤖 Prompt for AI Agents
In server/src/db/geolocation/geolocation.ts around lines 223-226, the catch
block currently logs IPAPI errors and returns an empty object which discards geo
data; instead call and return the existing local GeoIP reader fallback used
elsewhere in this module (reuse the same function or code path that looks up IP
locally), log the error as before, and return the fallback result so analytics
receive best-effort geolocation when IPAPI fails.
…acking utilities - Added 'region' field to LocationResponse type for improved geolocation data. - Updated geolocation extraction logic to map 'subdivisions' to 'region'. - Refactored tracking utilities to utilize the new 'region' field, enhancing data accuracy in tracking functions.
Summary by CodeRabbit
New Features
Refactor
Chores
Style