feat(diagnostics): active connect-failure triage + Sentry + in-app share (#2)
* feat(diagnostics): active connect-failure triage + Sentry + in-app share Replaces the opaque "Connection Failed" / "Network request failed" dead-end with on-device diagnostics that classify *why* a connect attempt failed. On failure (quick connect and edit-connection test), the app now: - runs parallel probes: target /global/health, target root, and a public 204 endpoint (internet reachability check) - classifies the cause: malformed-url, no-internet, server-unreachable, health-failed, tls-error, timeout - shows a plain-English summary + a "Share report" button that copies a full report (target URL, per-probe results w/ error.cause, device/app info, recent log ring-buffer) to the clipboard and opens the share sheet - captures the same structured context to Sentry (auto-upload), gated on EXPO_PUBLIC_SENTRY_DSN so dev/CI builds work without secrets New: src/lib/logbuffer.ts (ring buffer + logger), src/lib/diagnostics.ts (regex URL parse — Hermes URL is incomplete — probe + report + share), src/lib/sentry.ts (no-op-without-DSN wrapper, scrubs basic-auth from URLs). Wired Sentry.wrap around RootLayout and initSentry() at module load. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ci(sentry): wire Sentry DSN + source-map upload env into build; bump to 0.2.2 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,8 @@ import { router, useLocalSearchParams } from "expo-router"
|
||||
import { Ionicons } from "@expo/vector-icons"
|
||||
import { useConnections } from "../../src/stores/connections"
|
||||
import type { ConnectionType } from "../../src/lib/types"
|
||||
import { probeConnection, shareReport } from "../../src/lib/diagnostics"
|
||||
import { captureDiagnostic } from "../../src/lib/sentry"
|
||||
|
||||
const CONNECTION_TYPES: Array<{
|
||||
type: ConnectionType
|
||||
@@ -79,14 +81,25 @@ export default function EditConnectionScreen() {
|
||||
},
|
||||
password || undefined,
|
||||
)
|
||||
|
||||
if (result.ok) {
|
||||
setIsTesting(false)
|
||||
Alert.alert("Success", "Connection successful!")
|
||||
return
|
||||
}
|
||||
|
||||
// Failed: run active diagnostics, capture to Sentry, offer a shareable report.
|
||||
const report = await probeConnection(
|
||||
url.trim(),
|
||||
username.trim() && password ? { username: username.trim(), password } : undefined,
|
||||
)
|
||||
captureDiagnostic(report, result.error ? new Error(result.error) : undefined)
|
||||
setIsTesting(false)
|
||||
|
||||
Alert.alert(
|
||||
result.ok ? "Success" : "Failed",
|
||||
result.ok
|
||||
? "Connection successful!"
|
||||
: `Could not connect to ${url.trim()}\n\n${result.error || "Check the URL and credentials."}`,
|
||||
)
|
||||
Alert.alert("Connection Failed", `${report.summary}\n\n(${result.error || "no detail"})`, [
|
||||
{ text: "OK", style: "cancel" },
|
||||
{ text: "Share report", onPress: () => shareReport(report) },
|
||||
])
|
||||
}
|
||||
|
||||
const handleSave = async () => {
|
||||
|
||||
Reference in New Issue
Block a user