Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
534836a
fix: intermittent `fetch failed` errors during GeoTIFF processing
SvenVw Mar 23, 2026
3b0373d
fix: lockfile
SvenVw Mar 24, 2026
6cf0fc4
feat: Add Sentry metric for how often the error page is shown
SvenVw Mar 24, 2026
7202197
feat: Ignore expected 405 Method Not Allowed errors caused by bots/cr…
SvenVw Mar 24, 2026
e9a3cd4
refactor: Set `emailVerfied` to true when using social sign in
SvenVw Mar 24, 2026
ef5945c
fix: type
SvenVw Mar 24, 2026
01d809c
fix: typo
SvenVw Mar 24, 2026
950e776
tests: add unit tests for geotiff functions
SvenVw Mar 24, 2026
e85eeda
fix: Treat HEAD failure as unknown size, not a hard error
SvenVw Mar 24, 2026
a167be5
fix: Abort can still hang behind the semaphore
SvenVw Mar 24, 2026
cc7d388
refactor: Pass signal into readRasters
SvenVw Mar 24, 2026
829f0ba
fix: Don't couple the URL cache to the first caller's signal
SvenVw Mar 24, 2026
6e5b06f
fix: Preserve the original abort/fetch failure.
SvenVw Mar 24, 2026
01f9674
refactor: Normalize page before tagging to avoid high-cardinality met…
SvenVw Mar 24, 2026
575c111
tests: fix
SvenVw Mar 24, 2026
b9c7e37
refactor: implement review feedback
SvenVw Mar 24, 2026
e99afdc
refactor: implement review feedback
SvenVw Mar 24, 2026
fd95ff0
refactor: implement review feedback
SvenVw Mar 24, 2026
3442ae3
fix: show the error page instead of blank page
SvenVw Mar 24, 2026
2354d97
fix: remove potential memory leak
SvenVw Mar 24, 2026
e287224
nitpicks
SvenVw Mar 24, 2026
00c0d9d
chore: bump version of packages for release
github-actions[bot] Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions fdm-app/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog fdm-app

## 0.28.7

### Patch Changes

- [#528](https://github.com/nmi-agro/fdm/pull/528) [`3442ae3`](https://github.com/nmi-agro/fdm/commit/3442ae3c92d8200b81b020ee7516bca4580c4056) Thanks [@SvenVw](https://github.com/SvenVw)! - Fix to show the error page instead of blank page

- [#528](https://github.com/nmi-agro/fdm/pull/528) [`7202197`](https://github.com/nmi-agro/fdm/commit/72021973454613231e9fbc5096684e138579a31f) Thanks [@SvenVw](https://github.com/SvenVw)! - Ignore expected 405 Method Not Allowed errors caused by bots/crawlers making OPTIONS requests

- [#528](https://github.com/nmi-agro/fdm/pull/528) [`6cf0fc4`](https://github.com/nmi-agro/fdm/commit/6cf0fc41b61755d14aa8dedb345fadb7b01bf2e9) Thanks [@SvenVw](https://github.com/SvenVw)! - Add Sentry metric for how often the error page is shown

- Updated dependencies [[`534836a`](https://github.com/nmi-agro/fdm/commit/534836a7493201c77b5c7766c86290d7168e6f76), [`e9a3cd4`](https://github.com/nmi-agro/fdm/commit/e9a3cd4de585c2e05fc215ff0c5e758005c48f73)]:
- @nmi-agro/fdm-calculator@0.12.2
- @nmi-agro/fdm-core@0.30.1

## 0.28.6

### Patch Changes
Expand Down
13 changes: 13 additions & 0 deletions fdm-app/app/components/custom/error.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import * as Sentry from "@sentry/react-router"
import { ArrowLeft, Copy, Home } from "lucide-react"
import { useEffect, useState } from "react"
import { NavLink, useNavigate } from "react-router"
import { Button } from "~/components/ui/button"
import { clientConfig } from "~/lib/config"
import { normalizePage } from "~/lib/url-utils"

/**
* Displays a full-screen error block with tailored messaging and navigation options.
Expand Down Expand Up @@ -36,6 +39,16 @@ export function ErrorBlock({
)
const navigate = useNavigate()

useEffect(() => {
if (clientConfig.analytics.sentry) {
Sentry.withScope((scope) => {
scope.setTag("status", status?.toString() ?? "unknown")
scope.setTag("page", normalizePage(page))
Sentry.metrics.count("error_block.shown", 1)
})
}
}, [status, page])

useEffect(() => {
if (copyState !== "idle") {
const timer = setTimeout(() => setCopyState("idle"), 5000)
Expand Down
5 changes: 3 additions & 2 deletions fdm-app/app/components/custom/navigation-progress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Loader2 } from "lucide-react"
import { useEffect, useRef, useState } from "react"
import { useLocation, useMatches, useNavigation } from "react-router"
import { clientConfig } from "~/lib/config"
import { normalizePage } from "~/lib/url-utils"

/**
* Shows a blurred overlay with a loading card when navigation takes longer than 500ms.
Expand Down Expand Up @@ -40,7 +41,7 @@ export function NavigationProgress() {
Sentry.withScope((scope) => {
scope.setTag(
"page",
startPathnameRef.current ?? pathname,
normalizePage(startPathnameRef.current ?? pathname),
)
Sentry.metrics.count("navigation_progress.shown", 1)
})
Expand All @@ -56,7 +57,7 @@ export function NavigationProgress() {
Sentry.withScope((scope) => {
scope.setTag(
"page",
startPathnameRef.current ?? pathname,
normalizePage(startPathnameRef.current ?? pathname),
)
Sentry.metrics.distribution(
"navigation_progress.duration_ms",
Expand Down
37 changes: 37 additions & 0 deletions fdm-app/app/lib/url-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,43 @@ export function getSearchParams(href: string) {
return searchParams ?? new URLSearchParams()
}

/**
* Normalises a pathname for use as a low-cardinality Sentry tag.
* Replaces dynamic segments with typed placeholders so the tag value
* represents the route shape rather than a specific resource.
*
* Handles:
* - FDM nanoid IDs (16 chars from the custom read-safe alphabet) → `:id`
* - Pure numeric segments (years, numeric IDs) → `:year`
* - Coordinate-like segments (digits mixed with dots or commas) → `:centroid`
*
* @param page - The raw pathname string (e.g. from `location.pathname`).
* @returns The normalised route pattern (e.g. `/farm/:id/:year/atlas/fields/:centroid`).
*/
export function normalizePage(page: string): string {
// Strip query string and hash (pathname typically excludes these, but be defensive)
const path = page.split("?")[0].split("#")[0]
return path
.split("/")
.map((segment) => {
if (!segment) return segment
// FDM nanoid IDs: exactly 16 chars from the custom read-safe alphabet
if (/^[6789BCDFGHJKLMNPQRTWbcdfghjkmnpqrtwza]{16}$/.test(segment)) {
return ":id"
}
// Pure numeric segments (years, numeric IDs)
if (/^\d+$/.test(segment)) {
return ":year"
}
// Coordinate-like segments: mix of digits with dots or commas
if (/[,.]/.test(segment) && /\d/.test(segment)) {
return ":centroid"
}
return segment
})
.join("/")
}

/**
* Checks if the given URL-like might be a full URL, and if so, if it is of the
* origin given. No origin checks are performed if neither a URI scheme nor a
Expand Down
1 change: 1 addition & 0 deletions fdm-app/app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ export function Layout() {
<NavigationProgress />
<Banner />
<Toaster />
<ErrorBoundary error={null} params={{}} />
<ScrollRestoration
getKey={(location) => {
return location.pathname
Expand Down
6 changes: 5 additions & 1 deletion fdm-app/instrument.server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ if (process.env.PUBLIC_SENTRY_DSN) {
profilesSampleRate: Number(
process.env.PUBLIC_SENTRY_PROFILE_SAMPLE_RATE ?? 1,
),
ignoreErrors: [/BodyStreamBuffer was aborted/],
ignoreErrors: [
/BodyStreamBuffer was aborted/,
// Ignore expected 405 Method Not Allowed errors caused by bots/crawlers making OPTIONS requests
/Invalid request method "OPTIONS"/,
],
environment: process.env.NODE_ENV ?? "development",
release: process.env.npm_package_version,
})
Expand Down
2 changes: 1 addition & 1 deletion fdm-app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nmi-agro/fdm-app",
"version": "0.28.6",
"version": "0.28.7",
"private": true,
"sideEffects": false,
"type": "module",
Expand Down
11 changes: 11 additions & 0 deletions fdm-calculator/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# fdm-calculator

## 0.12.2

### Patch Changes

- [#528](https://github.com/nmi-agro/fdm/pull/528) [`534836a`](https://github.com/nmi-agro/fdm/commit/534836a7493201c77b5c7766c86290d7168e6f76) Thanks [@SvenVw](https://github.com/SvenVw)! - Fix intermittent `fetch failed` errors during GeoTIFF processing by implementing a multi-layered defense strategy:
- **Hybrid Loading**: Small files (<= 2MB) are now buffered in RAM to eliminate excessive HTTP Range requests.
- **Concurrency Throttling**: Added a semaphore to limit concurrent raster reads, protecting the socket pool.
- **Robustness**: Integrated 10s timeouts, `AbortSignal` support for request cancellation, and automatic retries with exponential backoff for transient network failures.
- Updated dependencies [[`e9a3cd4`](https://github.com/nmi-agro/fdm/commit/e9a3cd4de585c2e05fc215ff0c5e758005c48f73)]:
- @nmi-agro/fdm-core@0.30.1

## 0.12.1

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion fdm-calculator/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@nmi-agro/fdm-calculator",
"private": false,
"version": "0.12.1",
"version": "0.12.2",
"description": "Calculate various insights based on the Farm Data Model",
"license": "MIT",
"homepage": "https://github.com/nmi-agro/fdm",
Expand Down
Loading
Loading