fd699b3e2c
Fixes from live debugging on the Deck: - check_update() was dead on-device: Decky Loader's embedded (PyInstaller) Python has no usable default CA paths, so every HTTPS fetch failed with CERTIFICATE_VERIFY_FAILED. Build the SSL context explicitly: default paths first, then the known system bundles (SteamOS/Arch, Debian, Fedora/Bazzite, openSUSE), then certifi if importable. Verification stays on; the check stays offline-tolerant with its 30-min cache. - "could not chmod runner" on every use: Decky extracts plugin zips without exec bits into a root-owned dir the unprivileged backend can't chmod. The Steam shortcut now launches the runner through /bin/sh with the script as a %command% argument — no exec bit needed, existing shortcuts migrate on reuse, the chmod attempt is gone. UI/structure: - index.tsx (660 lines) split into page/pair/settings/hooks/boundary modules; PluginErrorBoundary kept guarding every surface. - New About section/tab: visible version + channel, explicit check-for-updates (forces past the cache, always toasts an outcome), setup-guide link, leave- chord help, and a Force-stop backstop for a wedged stream. - Host rows open a details modal (address, protocol, pairing policy, paired state, fingerprint). Settings gain 1280×800 (Deck native), Xbox One and DualShock 4 pad types, and a host-compositor picker. - Update flows note the Decky store contact can stall a couple of minutes on networks that blackhole plugins.deckbrew.xyz (observed live). - "Punktfunk" in all user-facing strings; plugin id/paths/env unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
52 lines
2.0 KiB
TypeScript
52 lines
2.0 KiB
TypeScript
// Error boundary — contains ANY render failure in our UI so a single bad render can never take
|
||
// down the whole Quick Access "Decky" section (Decky's tab-level boundary shows the generic
|
||
// "Something went wrong while displaying this content" for the entire tab when one plugin
|
||
// throws). The realistic trigger is a future Steam client update that makes a @decky/ui
|
||
// component resolve to `undefined` (React then throws "Element type is invalid"). The fallback
|
||
// is built from ONLY plain DOM elements + inline styles, so it cannot itself depend on a
|
||
// (possibly broken) Steam-internal component — it is guaranteed to render.
|
||
import { Component, ErrorInfo, ReactNode } from "react";
|
||
|
||
export class PluginErrorBoundary extends Component<
|
||
{ children: ReactNode },
|
||
{ error: Error | null }
|
||
> {
|
||
state: { error: Error | null } = { error: null };
|
||
|
||
static getDerivedStateFromError(error: Error) {
|
||
return { error };
|
||
}
|
||
|
||
componentDidCatch(error: Error, info: ErrorInfo) {
|
||
// Surface it for diagnosis, but never rethrow — containment is the whole point.
|
||
// eslint-disable-next-line no-console
|
||
console.error("[punktfunk] contained UI render error:", error, info?.componentStack);
|
||
}
|
||
|
||
render() {
|
||
const { error } = this.state;
|
||
if (!error) return this.props.children;
|
||
return (
|
||
<div style={{ padding: "1em", lineHeight: 1.45 }}>
|
||
<div style={{ fontWeight: "bold", marginBottom: "0.4em" }}>
|
||
Punktfunk couldn’t draw this view
|
||
</div>
|
||
<div style={{ opacity: 0.8, marginBottom: "0.6em" }}>
|
||
The plugin hit a display error — your Steam Deck is fine. Reload Punktfunk from
|
||
Decky's plugin list, or update the plugin.
|
||
</div>
|
||
<div
|
||
style={{
|
||
opacity: 0.55,
|
||
fontFamily: "monospace",
|
||
fontSize: "0.8em",
|
||
wordBreak: "break-word",
|
||
}}
|
||
>
|
||
{String(error?.message ?? error)}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
}
|