Merge pull request #271 from saphid/feat/framey-ui-fallbacks

Framey: restore detached settings and private Steam JSON cache
This commit is contained in:
Alex Southwell authored and GitHub committed 2026-10-26 00:39:30 +00:00
commit f2e73d98f4
8 files changed
+212 -41

No files matched your search

@@ -0,0 +1,107 @@
{
"checkedAtUtc": "2026-10-26T00:29:00Z",
"scope": "Exact archived frontends only. Production Framey host with bounded SteamClient JSON cache, image fallback and inert Steam subscriptions/context. Opaque iframe; all backend calls and network denied. No headset or plugin backends used in this follow-up.",
"baseHostCommit": "52a0974",
"before": {
"ready": 96,
"failed": 20
},
"after": {
"ready": 98,
"failed": 18
},
"regressions": [],
"observations": [
{
"id": 13,
"name": "Pause Games",
"ready": true,
"error": null,
"logs": [],
"methods": [
"load_settings"
]
},
{
"id": 43,
"name": "Tailscale Control",
"ready": true,
"error": null,
"logs": [],
"methods": [
"get_tailscale_state"
]
},
{
"id": 46,
"name": "Steamback",
"ready": false,
"error": "Cannot read properties of undefined (reading 'm_CurrentUser')",
"logs": [],
"methods": []
},
{
"id": 66,
"name": "PlayTime",
"ready": false,
"error": "Cannot read properties of undefined (reading 'm_mapApps')",
"logs": [
{
"kind": "error",
"message": "%c PlayTime %c ERROR background: #16a085; color: black; background: #FF000040; Impossible to get \"RunningApps\" observe. Events will not be attached."
},
{
"kind": "error",
"message": "%c PlayTime %c ERROR background: #16a085; color: black; background: #FF000040; Unable to get settings, saving defaults Error: Not found"
}
],
"methods": [
"fetch_playtime_information",
"statistics_for_last_two_weeks"
]
},
{
"id": 120,
"name": "Reroll",
"ready": true,
"error": null,
"logs": [],
"methods": [
"get_setting",
"version"
]
}
],
"tailscaleFocusedCheck": {
"rendered": [
"Settings",
"Toggle Tailscale",
"Exit Node IP",
"Toggle LAN Access",
"Advanced Settings",
"Device Status",
"Tailscale Setup"
],
"assetError": "Hardcoded localhost:1337 QR SVG blocked by image CSP",
"actions": "Inspected only; no toggles, exit nodes, installs or connection actions"
},
"pauseGamesFocusedCheck": {
"rendered": [
"Pause before Suspend",
"Pause on focus loss"
],
"actions": "Inspected only; no process signaling or suspend actions"
},
"storageChecks": [
"Per-plugin cache survives panel reopen",
"Missing key rejects Not found",
"JSON serialization and cache quota enforced",
"Malformed and stale-session cache updates rejected"
],
"unverified": [
"Real backends for these plugins",
"Tailscale network state/actions",
"Live games and pause/resume",
"Worn VR/controller/keyboard"
]
}
+8 -8
View File
@@ -4,7 +4,7 @@ Snapshot: 2026-10-25T23:19:48.854504+00:00; 116 current visible official plugins
This table and both store views use [`ui/framey-compatibility.json`](../ui/framey-compatibility.json). Results apply only to the exact store ID, version and SHA-256. A changed digest/version is **unverified**. Regenerate this document with `python3 scripts/framey-compatibility-doc.py`; use `--check` in review.
**Works: 1 · Partial: 42 · Broken: 62 · N/A: 11.**
**Works: 1 · Partial: 44 · Broken: 60 · N/A: 11.**
- **Works** requires verified useful plugin behavior with its real backend. Read the reason for the verified scope and remaining limits; it does not imply worn-VR verification.
- **Partial** means a limited frontend/settings surface initialized or rendered. Backend-dependent functionality remains unverified; it is not an end-to-end success claim.
@@ -27,7 +27,7 @@ Open the browser audit URL in local Chromium, run `runAudit()` and inspect/downl
The current published digests are pinned in the JSON; if the store changed, retain/download those exact archives for reproduction. Audit downloads permit larger ZIPs for inspection; production installer limits remain 50 MiB ZIP / 150 MiB unpacked / 30 MiB per member.
After the VR job released the shared lock, this audit acquired it and used a private temporary Decky 3.3.0 ARM64 user service. Read-only ProtonDB `get_setting` and Steam Status `get_settings` calls succeeded through the live Steam CEF websocket. The service and private base were removed and the lock released; normal managed services stayed inactive, battery was 100 → 99, and no power setting was changed. [Redacted results](evidence/framey-official-backend-2026-10-25.json) record exactly what ran. A [2026-10-26 follow-up](evidence/framey-events-backend-2026-10-26.json) verified default Notebook drawing/save/reopen across a real backend restart and Simple Timer start/cancel, countdown/completion events, a visible toast and persisted recents/subtle mode. Only private test settings were written. Simple Timer remains partial because its own expired-timer startup raises a missing `timer_task` error; sound/suspend are unsupported. All other official backends remain unexecuted. The separate VR job proves Frame Control/sample compositor rendering, not any official plugin. No worn-VR official-plugin result is claimed. Earlier focused checks cover [ProtonDB](evidence/framey-browser-2026-10-25.md), [Steam Status/cache](evidence/framey-cache-browser-2026-10-25.md), [Storage Cleaner](evidence/framey-api-v1-browser-2026-10-25.md), and [legacy MusicControl](evidence/framey-legacy-2026-10-25.md).
After the VR job released the shared lock, this audit acquired it and used a private temporary Decky 3.3.0 ARM64 user service. Read-only ProtonDB `get_setting` and Steam Status `get_settings` calls succeeded through the live Steam CEF websocket. The service and private base were removed and the lock released; normal managed services stayed inactive, battery was 100 → 99, and no power setting was changed. [Redacted results](evidence/framey-official-backend-2026-10-25.json) record exactly what ran. A [2026-10-26 follow-up](evidence/framey-events-backend-2026-10-26.json) verified default Notebook drawing/save/reopen across a real backend restart and Simple Timer start/cancel, countdown/completion events, a visible toast and persisted recents/subtle mode. Only private test settings were written. Simple Timer remains partial because its own expired-timer startup raises a missing `timer_task` error; sound/suspend are unsupported. All other official backends remain unexecuted. The separate VR job proves Frame Control/sample compositor rendering, not any official plugin. No worn-VR official-plugin result is claimed. A [local UI follow-up](evidence/framey-ui-fallbacks-2026-10-26.json) rendered Pause Games and Tailscale Control settings with all backend/network actions denied; it does not verify process pausing or Tailscale changes. Earlier focused checks cover [ProtonDB](evidence/framey-browser-2026-10-25.md), [Steam Status/cache](evidence/framey-cache-browser-2026-10-25.md), [Storage Cleaner](evidence/framey-api-v1-browser-2026-10-25.md), and [legacy MusicControl](evidence/framey-legacy-2026-10-25.md).
## Every current plugin
@@ -40,7 +40,7 @@ The API column shows manifest / actual bundled frontend API. Many manifests say
| 10: vibrantDeck 2.0.1 | legacy / legacy | N/A | Not supported on Frame: Changes X11 gamescope color properties, not the Frame SteamVR compositor. | static archive, local browser, fake-Frame |
| 11: Fantastic 0.5.1 | legacy / legacy | N/A | Not supported on Frame: Targets Steam Deck fan hardware; no Frame fan-control mapping is provided. | static archive, local browser, fake-Frame |
| 12: MusicControl 1.1.6 | legacy / legacy | partial | Legacy media controls initialize; player discovery and playback are unverified. | static archive, local browser, fake-Frame |
| 13: Pause Games 1.0.3 | 1 / 2 | broken | Frontend audit failed: SteamClient.System.UI.RegisterForSystemKeyEvents is not a function. | static archive, local browser, fake-Frame |
| 13: Pause Games 1.0.3 | 1 / 2 | partial | Settings render locally with inert system-key subscriptions and empty detached Steam context. Live-game discovery, process pause/resume and suspend integration are unsupported/unverified; no backend actions ran. | static archive, local browser, fake-Frame |
| 14: ProtonDB Badges 1.3.4 | 2 / 2 | partial | Settings render locally and read-only get_setting RPC returned the default through real Decky 3.3.0 on ARM64 Frame. Steam game-page badges have no patch target; live writes and VR controls unverified. | static archive, local browser, fake-Frame, real Frame SSH |
| 16: Audio Loader 1.6.1 | legacy / legacy | broken | This plugin needs root and is not supported by the Frame user service. Frontend audit failed: Cannot read properties of null (reading 'm_GamepadUIAudioStore'). | static archive, local browser, fake-Frame |
| 18: Bluetooth 3.1.1 | 1 / 2 | partial | Controls render with fixture replies; actual Bluetooth discovery, labels and connections remain unverified. | static archive, local browser, fake-Frame |
@@ -59,9 +59,9 @@ The API column shows manifest / actual bundled frontend API. Many manifests say
| 37: Discord Status 1.5.0 | 1 / 2 | broken | RunningApps and appStore are absent; Discord activity integration fails after initialization. | static archive, local browser, fake-Frame |
| 38: Volume Mixer 1.2.1-1 | legacy / legacy | partial | Initializer succeeds; user PulseAudio/PipeWire mixer backend and volume changes unverified. | static archive, local browser, fake-Frame |
| 40: Controller Tools 2.0.2 | 1 / 2 | broken | Plugin contains a non-ARM64 Linux binary: ControllerTools/bin/backend. Frontend audit failed: Audit blocks WebSocket. | static archive, local browser, fake-Frame |
| 43: Tailscale Control 0.1.3 | legacy / legacy | broken | Initializer succeeds but React rejects a missing component (#130); no usable control claim. | static archive, local browser, fake-Frame |
| 43: Tailscale Control 0.1.3 | legacy / legacy | partial | Settings render locally after the SuspensefulImage fallback. Tailscale daemon/state, connection and exit-node changes unverified; bundled localhost QR asset remains unavailable. No network settings were changed. | static archive, local browser, fake-Frame |
| 44: DeckMTP 1.0.5 | legacy / legacy | broken | Plugin contains a non-ARM64 Linux binary: DeckMTP/bin/umtprd. | static archive, local browser, fake-Frame |
| 46: Steamback 1.0.0-1 | legacy / legacy | broken | Unsafe plugin archive member. Frontend audit failed: App is not defined. | static archive, local browser, fake-Frame |
| 46: Steamback 1.0.0-1 | legacy / legacy | broken | Frontend audit failed: Cannot read properties of undefined (reading 'm_CurrentUser'). Steam account/app context is unavailable. | static archive, local browser, fake-Frame |
| 48: Quick Launch 1.2.1 | legacy / legacy | broken | This plugin needs root and is not supported by the Frame user service. | static archive, local browser, fake-Frame |
| 49: Decky Cloud Save 1.4.2 | legacy / legacy | broken | Unsafe plugin archive member. | static archive, local browser, fake-Frame |
| 50: Storage Cleaner 1.4.0 | 1 / 2 | partial | Empty-data panel rendered; cleanup was deliberately not run because it can remove local data. | static archive, local browser, fake-Frame |
@@ -76,7 +76,7 @@ The API column shows manifest / actual bundled frontend API. Many manifests say
| 63: Free Loader 1.6.0 | 1 / 2 | broken | Unsafe plugin archive member. | static archive, local browser, fake-Frame |
| 64: Syncthing 0.2.7 | legacy / legacy | broken | Plugin contains a non-ARM64 Linux binary: decky-syncthing/bin/decky-syncthing-watchdog. | static archive, local browser, fake-Frame |
| 65: Decky Terminal 0.5.3 | 1 / 2 | partial | Local routes initialize after parameter-route support; no shell commands were run. | static archive, local browser, fake-Frame |
| 66: PlayTime 3.2.5 | 1 / 2 | broken | Frontend audit failed: Cannot read properties of undefined (reading 'GetJSON'). | static archive, local browser, fake-Frame |
| 66: PlayTime 3.2.5 | 1 / 2 | broken | Private SteamClient JSON cache now works; initialization still fails on missing Steam appStore.m_mapApps. Live app data and MobX game observations are unavailable; backend actions were denied. | static archive, local browser, fake-Frame |
| 67: Battery Tracker 0.2.0 | legacy / legacy | broken | This plugin needs root and is not supported by the Frame user service. | static archive, local browser, fake-Frame |
| 68: Wine Cellar 0.2.1 | 1 / 2 | broken | Plugin contains a non-ARM64 Linux binary: decky-wine-cellar/bin/backend. Frontend audit failed: Audit blocks WebSocket. | static archive, local browser, fake-Frame |
| 70: MicroSDeck 0.11.2 | legacy / 2 | broken | Plugin contains a non-ARM64 Linux binary: MicroSDeck/bin/backend. | static archive, local browser, fake-Frame |
@@ -126,7 +126,7 @@ The API column shows manifest / actual bundled frontend API. Many manifests say
| 117: DeckyParty File Manager 1.0.0 | legacy / legacy | partial | Initializer succeeds; privileged file operations and backend are unverified. No file changes were run. | static archive, local browser, fake-Frame |
| 118: Speed Test 1.0.2 | 1 / 2 | partial | Initializer succeeds; automatic bandwidth tests were blocked by the audit network policy. | static archive, local browser, fake-Frame |
| 119: Decky Clipboard 1.0.1 | 1 / 2 | broken | Plugin contains a non-ARM64 Linux binary: decky-clipboard/bin/xclip. | static archive, local browser, fake-Frame |
| 120: Reroll 0.2.1 | 1 / 2 | broken | Plugin contains a non-ARM64 Linux binary: Reroll/bin/memscan.so. Frontend audit failed: window.SteamClient.Apps.RegisterForGameActionUserRequest is not a function. | static archive, local browser, fake-Frame |
| 120: Reroll 0.2.1 | 1 / 2 | broken | Frontend now initializes with inert game-action subscriptions, but the archive contains x86_64 memscan.so and requests root. No process-memory access was run. | static archive, local browser, fake-Frame |
| 121: DeckPass 1.1.1 | 1 / 2 | partial | Initializer succeeds; KeePass Flatpak discovery and secrets integration were not exercised. | static archive, local browser, fake-Frame |
| 123: Steam Status 1.2.3 | 2 / 2 | partial | Settings/public status rendered locally; cache errors fixed. Read-only get_settings RPC returned actual Decky 3.3.0 defaults on ARM64 Frame. Persistence, live backend diagnostics and VR controls unverified. | static archive, local browser, fake-Frame, real Frame SSH |
| 124: AlarMe 1.6.3 | 1 / 2 | partial | Initializer succeeds; timers, reminders, suspend inhibition and audio are unverified. | static archive, local browser, fake-Frame |
@@ -301,7 +301,7 @@ All published Linux native payloads in this snapshot are x86_64; no published aa
| Decky-Framegen | bin/nvngx.dll, bin/dlssg_to_fsr3_amd_is_better.dll, bin/nvapi64.dll | Windows DLL payload targets x86 game translation rather than a native ARM backend; archive is 75,140,408 bytes, beyond the 50 MiB installer limit. |
| HueSync | bin/hello, py_modules/portio.so | portio and handheld LED backends depend on x86 I/O/unsupported hardware; ARM64 compilation alone is insufficient. |
| Decky Clipboard | bin/xclip | xclip needs ARM64 X11 libraries/server; root and gamescope assumptions also block this archive. |
| Reroll | bin/memscan.so | memscan.so needs ARM64 process-memory support and ABI testing; root requirement and missing Steam hook remain. |
| Reroll | bin/memscan.so | memscan.so needs ARM64 process-memory support and ABI testing; root requirement remains. Frontend initializes but no memory access was tested. |
| Decky Localsend | bin/localsend-core | LocalSend-Go commit 66edc509a28b9f877e7374504892dcbc653a4da4 cross-compiled successfully with CGO_ENABLED=0 GOOS=linux GOARCH=arm64. Static aarch64 ELF SHA-256 e79238f6051ce34f172f765ae918d3d902b819e27377989a55e5b1eba10e46f9. Not executed; source tip is not proven to match the shipped helper/protocol. Official ZIP is still x86_64. |
| Launch Options | bin/hello | Remove the template x86 bin/hello or publish an ARM64 rebuild; missing Steam module mapping also prevents frontend initialization. |
| Decky-Clipper | bin/gstreamer-1.0/libgstproxy.so, bin/gstreamer-1.0/libgstmidi.so, bin/gstreamer-1.0/libgstmpegtsmux.so, bin/gstreamer-1.0/gst-plugin-scanner, bin/gstreamer-1.0/libgstivfparse.so, … 115 total; full list in JSON | Rebuild all bundled GStreamer libraries/plugins for ARM64 and verify capture/codec ABI against Frame SteamVR; gamescope capture differs. |
+11
View File
@@ -113,6 +113,17 @@ work. IndexedDB is hidden because the browser exposes it but denies access in
an opaque iframe; localForage can then select Framey's bounded localStorage.
Direct IndexedDB users remain unsupported.
`SuspensefulImage` renders a native image. SteamClient `Storage.GetJSON` and
`SetObject` use the same bounded per-plugin cache, including panel reopen
persistence; they do not read Steam's account/global JSON store. Missing keys
reject with `Not found`. Detached `SteamUIStore.RunningApps` is a frozen empty
list, and the suspend store has no methods. Optional Steam app/account globals
are undefined. These fallbacks let settings render without inventing live
games or account identity. [The exact-bundle follow-up](evidence/framey-ui-fallbacks-2026-10-26.json)
verifies Pause Games and Tailscale Control settings in local Chromium; their
primary backend actions remain unverified. PlayTime still requires Steam's
real app store and game observers.
The fake Frame integration test now writes a Decky setting through Framey's
scoped backend endpoint, reads it in a new CEF request, updates the plugin,
then checks it again. It also confirms removal blocks method calls and a
+2
View File
@@ -54,6 +54,8 @@ def render(data):
'All other official backends remain unexecuted. '
'The separate VR job proves Frame Control/sample compositor rendering, not any official plugin. '
'No worn-VR official-plugin result is claimed. '
'A [local UI follow-up](evidence/framey-ui-fallbacks-2026-10-26.json) rendered Pause Games and Tailscale Control settings '
'with all backend/network actions denied; it does not verify process pausing or Tailscale changes. '
'Earlier focused checks cover [ProtonDB](evidence/framey-browser-2026-10-25.md), '
'[Steam Status/cache](evidence/framey-cache-browser-2026-10-25.md), '
'[Storage Cleaner](evidence/framey-api-v1-browser-2026-10-25.md), and '
+20 -1
View File
@@ -20,7 +20,7 @@ const window={React,ReactDOM:{createRoot:node=>{
const listeners=[];const messages=[];const parent={postMessage:message=>messages.push(message)};
const context=vm.createContext({window,document:{getElementById:id=>{
if(!elements.has(id))elements.set(id,new Element());return elements.get(id);},createElement:()=>new Element()},
navigator:{language:'en'}, parent,addEventListener:(type,handler)=>listeners.push({type,handler}),
navigator:{language:'en'}, parent,DOMException,addEventListener:(type,handler)=>listeners.push({type,handler}),
setTimeout:()=>1,clearTimeout(){}});
vm.runInContext(testSource,context);
// Official @decky/rollup bundles use the automatic JSX runtime, including keyed lists.
@@ -175,6 +175,25 @@ assert.equal(unsubscribe.unregister,unsubscribe);
unsubscribe.unregister();unsubscribe();assert.equal(eventCount,0);
assert.equal(window.SteamClient.System.ShutdownPC,undefined);
assert.equal(window.DFL.Router.MainRunningApp,undefined);
assert.equal(window.DFL.Router.RunningApps.length,0);
assert.equal(window.DFL.Router.RunningApps,window.SteamUIStore.RunningApps);
assert.ok(Object.isFrozen(window.SteamUIStore));
assert.ok(Object.isFrozen(window.SuspendResumeStore));
assert.equal(window.SuspendResumeStore.InitiateSleep,undefined);
for(const name of ['App','appStore','appInfoStore','collectionStore'])assert.equal(window[name],undefined);
for(const register of [window.SteamClient.System.UI.RegisterForSystemKeyEvents,
window.SteamClient.Apps.RegisterForGameActionUserRequest]){
const dispose=register(()=>eventCount++);assert.equal(dispose.unregister,dispose);dispose();
}
assert.equal(eventCount,0);
const image=window.DFL.SuspensefulImage({src:'data:image/svg+xml,<svg/>',alt:'Setup',style:{width:50}});
assert.equal(image.type,'img');assert.equal(image.props.alt,'Setup');assert.equal(image.props.style.width,50);
await assert.rejects(window.SteamClient.Storage.GetJSON('missing'),/Not found/);
await window.SteamClient.Storage.SetObject('settings',{enabled:false,count:3});
assert.equal(await window.SteamClient.Storage.GetJSON('settings'),'{"enabled":false,"count":3}');
assert.equal(window.localStorage.getItem('steam-client:settings'),'{"enabled":false,"count":3}');
await assert.rejects(window.SteamClient.Storage.SetObject('large','x'.repeat(65537)),/Framey plugin cache is full/);
await assert.rejects(window.SteamClient.Storage.SetObject('undefined',undefined),/JSON value/);
assert.equal(window.indexedDB,undefined); // localForage must use bounded plugin storage.
const unpatch=window.DFL.beforePatch({},'method',()=>{});
assert.equal(unpatch.unpatch,unpatch);unpatch.unpatch();
+7 -4
View File
@@ -38,7 +38,7 @@ function iframe(){
for(const message of queued)onParent({source:proxy,data:message});
live=true;
const send=message=>onParent({source:proxy,data:message});
return {storage:frameWindow.localStorage,send};
return {storage:frameWindow.localStorage,steamStorage:frameWindow.SteamClient.Storage,send};
}
let first=iframe();
assert.equal(first.storage.getItem('status-cache'),null);
@@ -46,6 +46,7 @@ first.storage.setItem('status-cache','{"online":true}');
assert.equal(values.get('framey-plugin-cache-v1:14'),'{"status-cache":"{\\"online\\":true}"}');
first.storage.setItem('temporary','discard');
first.storage.removeItem('temporary');
await first.steamStorage.SetObject('playtime-settings',{count:3});
const oldSession=session;
vm.runInContext('openFrameyPanel(14,"Steam Status")',parent);
session=vm.runInContext('frameySession',parent);
@@ -57,13 +58,15 @@ assert.equal(reopenedURL.searchParams.get('session'),session);
assert.equal(reopenedURL.hash.slice(1),session);
let reopened=iframe();
assert.equal(reopened.storage.getItem('status-cache'),'{"online":true}');
assert.equal(reopened.storage.length,1);
assert.equal(reopened.storage.length,2);
assert.equal(reopened.storage.key(0),'status-cache');
assert.equal(await reopened.steamStorage.GetJSON('playtime-settings'),'{"count":3}');
assert.throws(()=>reopened.storage.setItem('huge','x'.repeat(65537)),/Framey plugin cache is full/);
// A malformed or over-limit message from a plugin must not poison saved data.
const savedCache=values.get('framey-plugin-cache-v1:14');
reopened.send({type:'framey:cache:save',session,entries:{huge:'x'.repeat(65537)}});
assert.equal(values.get('framey-plugin-cache-v1:14'),'{"status-cache":"{\\"online\\":true}"}');
assert.equal(values.get('framey-plugin-cache-v1:14'),savedCache);
reopened.send({type:'framey:cache:save',session:oldSession,entries:{poison:'yes'}});
assert.equal(values.get('framey-plugin-cache-v1:14'),'{"status-cache":"{\\"online\\":true}"}');
assert.equal(values.get('framey-plugin-cache-v1:14'),savedCache);
reopened.storage.clear();
assert.equal(values.get('framey-plugin-cache-v1:14'),'{}');
+35 -25
View File
@@ -3,7 +3,7 @@
"checkedAtUtc": "2026-10-25T23:19:48.854504+00:00",
"source": "https://plugins.deckbrew.xyz/plugins",
"hostCommit": "779f9c5",
"method": "Exact SHA-256 verified archives. All frontends attempted in opaque-iframe Chromium for 1.2 s with backend calls and network denied; ready means initializer only. No official backend code was executed. See docs/framey-compatibility.md.",
"method": "Exact SHA-256 verified archives. All frontends attempted in opaque-iframe Chromium for 1.2 s with backend calls and network denied; ready means initializer only. Backend calls were denied in the baseline browser audit. Scoped live backend follow-ups are recorded separately in docs/framey-compatibility.md.",
"plugins": [
{
"id": 1,
@@ -579,8 +579,8 @@
"https://github.com/wynn1212/SDH-PauseGames",
"https://github.com/wynn1212/SDH-PauseGames.git"
],
"status": "broken",
"reason": "Frontend audit failed: SteamClient.System.UI.RegisterForSystemKeyEvents is not a function.",
"status": "partial",
"reason": "Settings render locally with inert system-key subscriptions and empty detached Steam context. Live-game discovery, process pause/resume and suspend integration are unsupported/unverified; no backend actions ran.",
"blockInstall": false,
"verification": [
"static archive",
@@ -590,8 +590,8 @@
"browser": {
"id": 13,
"name": "Pause Games",
"ready": false,
"error": "SteamClient.System.UI.RegisterForSystemKeyEvents is not a function",
"ready": true,
"error": null,
"logs": [],
"methods": [
"load_settings"
@@ -3155,8 +3155,8 @@
"https://github.com/saumya-banthia/tailscale-control.git",
"https://github.com/tailscale-dev/deck-tailscale"
],
"status": "broken",
"reason": "Initializer succeeds but React rejects a missing component (#130); no usable control claim.",
"status": "partial",
"reason": "Settings render locally after the SuspensefulImage fallback. Tailscale daemon/state, connection and exit-node changes unverified; bundled localhost QR asset remains unavailable. No network settings were changed.",
"blockInstall": false,
"verification": [
"static archive",
@@ -3168,13 +3168,10 @@
"name": "Tailscale Control",
"ready": true,
"error": null,
"logs": [
{
"kind": "error",
"message": "Error: Minified React error #130; visit https://reactjs.org/docs/error-decoder.html?invariant=130&args[]=undefined&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings."
}
],
"methods": []
"logs": [],
"methods": [
"get_tailscale_state"
]
},
"archiveValidation": {
"id": 43,
@@ -3355,7 +3352,7 @@
"https://github.com/geeksville/steamback.git"
],
"status": "broken",
"reason": "Unsafe plugin archive member. Frontend audit failed: App is not defined.",
"reason": "Frontend audit failed: Cannot read properties of undefined (reading 'm_CurrentUser'). Steam account/app context is unavailable.",
"blockInstall": true,
"verification": [
"static archive",
@@ -3366,7 +3363,7 @@
"id": 46,
"name": "Steamback",
"ready": false,
"error": "App is not defined",
"error": "Cannot read properties of undefined (reading 'm_CurrentUser')",
"logs": [],
"methods": []
},
@@ -4926,7 +4923,7 @@
"https://github.com/your-username/PlayTime"
],
"status": "broken",
"reason": "Frontend audit failed: Cannot read properties of undefined (reading 'GetJSON').",
"reason": "Private SteamClient JSON cache now works; initialization still fails on missing Steam appStore.m_mapApps. Live app data and MobX game observations are unavailable; backend actions were denied.",
"blockInstall": false,
"verification": [
"static archive",
@@ -4937,9 +4934,21 @@
"id": 66,
"name": "PlayTime",
"ready": false,
"error": "Cannot read properties of undefined (reading 'GetJSON')",
"logs": [],
"methods": []
"error": "Cannot read properties of undefined (reading 'm_mapApps')",
"logs": [
{
"kind": "error",
"message": "%c PlayTime %c ERROR background: #16a085; color: black; background: #FF000040; Impossible to get \"RunningApps\" observe. Events will not be attached."
},
{
"kind": "error",
"message": "%c PlayTime %c ERROR background: #16a085; color: black; background: #FF000040; Unable to get settings, saving defaults Error: Not found"
}
],
"methods": [
"fetch_playtime_information",
"statistics_for_last_two_weeks"
]
},
"archiveValidation": {
"id": 66,
@@ -10375,7 +10384,7 @@
"https://github.com/kayon/memscan"
],
"status": "broken",
"reason": "Plugin contains a non-ARM64 Linux binary: Reroll/bin/memscan.so. Frontend audit failed: window.SteamClient.Apps.RegisterForGameActionUserRequest is not a function.",
"reason": "Frontend now initializes with inert game-action subscriptions, but the archive contains x86_64 memscan.so and requests root. No process-memory access was run.",
"blockInstall": true,
"verification": [
"static archive",
@@ -10385,11 +10394,12 @@
"browser": {
"id": 120,
"name": "Reroll",
"ready": false,
"error": "window.SteamClient.Apps.RegisterForGameActionUserRequest is not a function",
"ready": true,
"error": null,
"logs": [],
"methods": [
"get_setting"
"get_setting",
"version"
]
},
"archiveValidation": {
@@ -10399,7 +10409,7 @@
},
"backend": "Python + native payload",
"hardware": "No specific hardware requirement detected statically; runtime requirements unverified.",
"nativePort": "memscan.so needs ARM64 process-memory support and ABI testing; root requirement and missing Steam hook remain.",
"nativePort": "memscan.so needs ARM64 process-memory support and ABI testing; root requirement remains. Frontend initializes but no memory access was tested.",
"uiSurfaces": [
"QAM/global tabs",
"Steam stores"
+22 -3
View File
@@ -11,6 +11,11 @@
: R.createElement(type, elementProps);
};
window.SP_JSX = {jsx, jsxs:jsx, Fragment:R.Fragment};
// Let plugins use optional chaining for Steam-only globals without inventing
// user identity or suspend state in this isolated document.
for (const name of ['App','appStore','appInfoStore','collectionStore']) window[name] = undefined;
window.SuspendResumeStore = Object.freeze({});
window.SteamUIStore = Object.freeze({RunningApps:Object.freeze([]), MainRunningApp:undefined});
// Steam normally fills these token maps. Official plugins can safely use
// their own fallback strings when the isolated panel has no Steam tokens.
window.LocalizationManager = {m_rgLocalesToUse:[navigator.language || 'en'],
@@ -284,6 +289,7 @@
DialogButton: passthrough('button'), DialogButtonPrimary: passthrough('button'), ConfirmModal,
DialogButtonSecondary: passthrough('button'), Button: ButtonItem, GamepadButton: passthrough('button'),
Toggle: ToggleField, Spinner, SteamSpinner:Spinner, Tabs, SidebarNavigation,
SuspensefulImage:({alt='', ...props})=>R.createElement('img', {...props, alt}),
Marquee:passthrough('span'), DialogBody:passthrough('div'), DialogBodyText:passthrough('p'),
DialogHeader:passthrough('h2'), DialogSubHeader:passthrough('h3'), DialogFooter:passthrough('footer'),
DialogLabel:passthrough('label'), DialogControlsSection:passthrough('section'),
@@ -326,17 +332,30 @@
Settings:{GetCurrentLanguage:async()=>steamLanguage(),
...register(['RegisterForSettingsChanges'])},
Apps:register(['RegisterForAppDetails','RegisterForGameActionTaskChange',
'RegisterForGameActionStart','RegisterForGameActionEnd']),
'RegisterForGameActionStart','RegisterForGameActionEnd','RegisterForGameActionUserRequest']),
GameSessions:register(['RegisterForAppLifetimeNotifications','RegisterForScreenshotNotification']),
System:{...register(['RegisterForOnResumeFromSuspend','RegisterForOnSuspendRequest']),
UI:register(['RegisterForFocusChangeEvents'])},
UI:register(['RegisterForFocusChangeEvents','RegisterForSystemKeyEvents'])},
Input:register(['RegisterForControllerInputMessages','RegisterForControllerStateChanges']),
User:register(['RegisterForLoginStateChange','RegisterForPrepareForSystemSuspendProgress',
'RegisterForResumeSuspendedGamesProgress','RegisterForCurrentUserChanges']),
Overlay:register(['RegisterForOverlayActivated']),
UI:register(['RegisterForUIModeChanged']),
// This is private plugin cache, not Steam's account/global JSON store.
Storage:{
GetJSON:async key=>{
const value=storage.getItem('steam-client:'+String(key));
if(value===null)throw Error('Not found');
return value;
},
SetObject:async(key,value)=>{
const encoded=JSON.stringify(value);
if(encoded===undefined)throw Error('SteamClient.Storage requires a JSON value');
storage.setItem('steam-client:'+String(key),encoded);
},
},
};
DFL.Router = {...DFL.Navigation, MainRunningApp:undefined};
DFL.Router = {...DFL.Navigation, ...window.SteamUIStore};
DFL.DialogButton.render = () => ({type: DFL.DialogButton});
const toaster = {toast: ({title, body, subtext, icon, logo, duration, showToast=true, onClick}={}) => {
const data = {title, body, subtext, icon, logo};