All versions since v3.0.1
v3.0.1
What’s new
BridgePort v3.0.1 is a reliability patch. Under sustained concurrent write load, a freshly-booted instance could intermittently return transient 500s (typically on GET /api/auth/me) whenever a second writer held the SQLite write lock. Those statements are now automatically retried, and genuinely unresolvable contention returns a retryable 503 instead of an opaque 500. No database migrations — upgrade is drop-in.
Fixes
Transient 500s under sustained write contention (#299)
BridgePort serves requests through a single synchronous better-sqlite3 connection, so it never self-contends — but when a second writer held the write lock (a long external transaction, a WAL checkpoint, or a test harness resetting state), two SQLite modes surfaced as opaque 500s:
SQLITE_BUSY— lock held pastbusy_timeout, mapped to PrismaP1008.SQLITE_BUSY_SNAPSHOT— a stale read snapshot upgrading to a write; returned immediately, sobusy_timeoutcould never absorb it.
The fix:
- Automatic retry — a Prisma client extension retries transient contention (
P1008/P1017/P2024/P2034,SQLITE_BUSY/locked) with jittered exponential backoff. Retry is per-statement and verified safe — no double-writes, including inside an interactive$transaction. - Retryable
503, not opaque500— when retries are exhausted, the request returns503 Service Unavailablewith aRetry-Afterheader, logged atwarnand kept out of Sentry.
Measured with a concurrent CRUD + /api/auth/me repro under a bursting external write lock: 24 → 0 500s.
API changes
No endpoints or fields were added, changed, or removed. One behavior change: transient database-contention errors now return 503 (with Retry-After) instead of 500. Monitoring or alerting that treats all 5xx as outages should treat these 503s as retryable.
Configuration
- New
DB_RETRY_*knobs tune retry attempts and backoff — sensible defaults, no action required. SQLITE_BUSY_TIMEOUT_MSdefault lowered5000→1000.better-sqlite3’s busy-wait is synchronous and blocks the event loop, so the per-attempt wait is kept short while the async retry loop (which frees the loop between attempts) carries longer contention.
See Configuration.
Database migrations
None — this release makes no schema changes.
Ecosystem
Alongside the 3.x line, BridgePort now has first-class infrastructure-as-code tooling (versioned independently of the platform):
- Terraform / OpenTofu provider — manage environments, servers, config, secrets, registries, images, and services declaratively. Live on both the Terraform and OpenTofu registries; source at
terraform-provider-bridgeport. - Go SDK —
github.com/bridgeinpt/bridgeport/client, a typed read + write client for the HTTP API.
Upgrade
Drop-in — pull and restart, no migrations or config changes required.
docker pull ghcr.io/bridgeinpt/bridgeport:v3.0.1-----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgEyiv4hf6iBgr34ICjN6HnEP/vs Yr31eNU5HhdkQaYd4AAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQAQzL5g91VpEHH4vS6L7IftJp7NJQnkfYUd7BLVWvTbALcCIjoqnf65ol/jEO0QbKz HDrnnGVhKOtcKUU3Y4GgY= -----END SSH SIGNATURE-----
v3.0.2 Latest
What’s new
A drop-in patch — no migrations, no config changes. It fixes over-aggressive rate limiting that could surface a normal dashboard load as a 500, makes the frontend self-heal stale chunks after an upgrade, refreshes the app icons, and — the headline — launches the public documentation site at bridgeport.bridgein.com.
Fixes
Rate limiting no longer trips on normal page loads (#312)
The global limiter (100 req/min per IP) was applied to every route, including static-asset serving and the SPA shell — so a single dashboard load (HTML + a dozen hashed JS/CSS chunks + 30s polling) could exhaust the budget for one legitimate user. The rejection on the static route was then mis-classified as a 500 and captured to error monitoring.
- Static/SPA
GET/HEADrequests are now exempt from the limiter;/api/*and/mcpstay throttled — the limiter protects the programmatic surface, not local file serving. - Genuine rate-limit responses now return a correct
429 Too Many RequestswithRetry-Afterinstead of a 500, and no longer spam error monitoring.
If you front BridgePort with a reverse proxy or CDN, that’s the right layer to DoS-protect static serving.
Frontend self-heals stale chunks after a deploy (#312)
A vite:preloadError handler now does a one-shot, cooldown-guarded reload when a lazy-loaded route chunk fails to fetch — typically right after an upgrade swaps the hashed assets. “Failed to fetch dynamically imported module” errors recover transparently instead of dead-ending the page.
Improvements
Refreshed app icons (#310)
New favicon and PWA/app-tile icons in the brand aesthetic — the red crane mark on dark #0a0e14 tiles, with a transparent favicon that adapts to light and dark browser tab strips.
Security
- CVE-2026-12143 / GHSA-hmw2-7cc7-3qxx — CRLF injection in
form-data(< 4.0.6), high severity, pinned to ≥ 4.0.6. This dependency lives only in the docs-site build toolchain (website/) and never reaches the app runtime or the Docker image, so the running app was never exposed — closed for hygiene. (#309)
Documentation
Public documentation site launched (#307, #308, #311, #313)
BridgePort now has a full docs site at bridgeport.bridgein.com, built with Astro Starlight from the repo’s docs/ — a single source, so the site and GitHub never drift. Highlights:
- Full-text search, dark/light, branded to match the app UI
- API reference auto-generated from the OpenAPI spec
- Architecture & flow diagrams rendered from Mermaid
- A changelog sourced from these GitHub Releases (so this release will appear there automatically)
- Real product screenshots (dashboard, monitoring, services)
- An
llms.txtendpoint so AI agents can consume the docs - Auto-deploys via Cloudflare on every docs change and on each published release
API changes
None. (Rate-limit responses now return 429 instead of an erroneous 500 — a fix, not a surface change; see Fixes.)
-----BEGIN SSH SIGNATURE-----
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgEyiv4hf6iBgr34ICjN6HnEP/vs
Yr31eNU5HhdkQaYd4AAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
AAAAQLoiwVIhyZuzlKhDAlmko0bhVpoKrbuRyBug03RBdL0BFftf7YkHAREPYq7n9qD4Hh
r2jduikwYktaNiQCaXrQI=
-----END SSH SIGNATURE-----