mirror of
https://github.com/k1tbyte/Wand-Enhancer.git
synced 2026-08-28 17:01:04 +00:00
Merge pull request #110 from Kava-4/fix/pro-account-reducer-guard
fix(pro): guard ACTION_SET_ACCOUNT reducer against subscription loss
This commit is contained in:
@@ -22,7 +22,7 @@ This repository patches the Wand Electron app from a .NET Framework WPF desktop
|
|||||||
- The websocket `hello` snapshot must still send cached `installed_apps` and `game_status` even when no trainer snapshot is active yet; do not reintroduce a handshake path that returns early after `trainer_changed`.
|
- The websocket `hello` snapshot must still send cached `installed_apps` and `game_status` even when no trainer snapshot is active yet; do not reintroduce a handshake path that returns early after `trainer_changed`.
|
||||||
- Remote Play/Stop uses the websocket `remote_command` message. The bridge forwards it over `wand-remote-command` / `wand-remote-command-response`, and `installed-apps-sync.js` resolves Wand's trainer API + trainer service to launch a trainer for a `gameId` or end the current trainer.
|
- Remote Play/Stop uses the websocket `remote_command` message. The bridge forwards it over `wand-remote-command` / `wand-remote-command-response`, and `installed-apps-sync.js` resolves Wand's trainer API + trainer service to launch a trainer for a `gameId` or end the current trainer.
|
||||||
- Remote Play must construct Wand's real trainer launch request class (`69482.vO`) before calling `trainerService.launch(...)`. Passing a plain object launches the game process but breaks Wand's `getMetadata(vO)`-based trainer state, causing missing status, disappearing play/close buttons, and stuck loading behavior.
|
- Remote Play must construct Wand's real trainer launch request class (`69482.vO`) before calling `trainerService.launch(...)`. Passing a plain object launches the game process but breaks Wand's `getMetadata(vO)`-based trainer state, causing missing status, disappearing play/close buttons, and stuck loading behavior.
|
||||||
- Pro activation is a C# asar patch (`EPatchType.ActivatePro`, independent of the remote panel / bridge). It rewrites three account-returning service methods to inject `subscription:{period:"yearly",state:"active"}` into the response before it reaches the store: `getUserAccount` and `setAccountWandBrandExperience` (Resolver-style, service field via `<service_name>` placeholder) and `setAccountLanguage` (`BuildSetAccountLanguagePatch` PatchFactory — captures the real param names + the original `post("/v3/account/language",{...})` expr and wraps `.then`). Pro is `am(account) = !!account.subscription` (flags/512 are irrelevant). `setAccountLanguage` is the one the original two patches missed, which is why Pro dropped on language change. If a future Wand build changes these method bodies, re-derive the regexes against the live `app-*.bundle.js` (do NOT trust `.source/new` — it is a different version).
|
- Pro activation is a C# asar patch (`EPatchType.ActivatePro`, independent of the remote panel / bridge). It rewrites three account-returning service methods to inject `subscription:{period:"yearly",state:"active"}` into the response before it reaches the store: `getUserAccount` and `setAccountWandBrandExperience` (Resolver-style, service field via `<service_name>` placeholder) and `setAccountLanguage` (`BuildSetAccountLanguagePatch` PatchFactory — captures the real param names + the original `post("/v3/account/language",{...})` expr and wraps `.then`). A fourth patch (`setAccountReducer`) rewrites the `ACTION_SET_ACCOUNT` store reducer so any account write (periodic `refreshAccount`, push/profile updates, etc.) keeps Pro even when it bypasses those API methods. Pro is `am(account) = !!account.subscription` (flags/512 are irrelevant). `setAccountLanguage` is the one the original two patches missed, which is why Pro dropped on language change. If a future Wand build changes these method bodies, re-derive the regexes against the live `app-*.bundle.js` (do NOT trust `.source/new` — it is a different version).
|
||||||
|
|
||||||
## ASAR Patch Pipeline
|
## ASAR Patch Pipeline
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,17 @@ namespace WandEnhancer.Core
|
|||||||
return $"setAccountLanguage({parameters}){{return ({expr}).then(response=>{{response&&\"object\"==typeof response&&(response.subscription={{period:\"yearly\",state:\"active\"}});return response;}})}}";
|
return $"setAccountLanguage({parameters}){{return ({expr}).then(response=>{{response&&\"object\"==typeof response&&(response.subscription={{period:\"yearly\",state:\"active\"}});return response;}})}}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string BuildSetAccountReducerPatch(Match match)
|
||||||
|
{
|
||||||
|
var decl = RequireGroup(match, "decl", "setAccountReducer");
|
||||||
|
var fn = RequireGroup(match, "fn", "setAccountReducer");
|
||||||
|
var parameters = RequireGroup(match, "params", "setAccountReducer");
|
||||||
|
var state = RequireGroup(match, "state", "setAccountReducer");
|
||||||
|
var account = RequireGroup(match, "account", "setAccountReducer");
|
||||||
|
return
|
||||||
|
$"const {decl}=\"ACTION_SET_ACCOUNT\";function {fn}({parameters}){{const a={account};return a&&\"object\"==typeof a&&(a={{...a,subscription:{{period:\"yearly\",state:\"active\"}}}}),{{...{state},account:a}}}}";
|
||||||
|
}
|
||||||
|
|
||||||
private static string BuildRemoteBridgeResetPatch(Match match)
|
private static string BuildRemoteBridgeResetPatch(Match match)
|
||||||
{
|
{
|
||||||
var source = match.Value;
|
var source = match.Value;
|
||||||
@@ -143,6 +154,19 @@ namespace WandEnhancer.Core
|
|||||||
@"setAccountLanguage\((?<params>[^)]*)\)\{\s*return\s+(?<expr>this\.#\w+\.post\(""/v3/account/language"",\{[^}]*\}\))\s*;?\s*\}",
|
@"setAccountLanguage\((?<params>[^)]*)\)\{\s*return\s+(?<expr>this\.#\w+\.post\(""/v3/account/language"",\{[^}]*\}\))\s*;?\s*\}",
|
||||||
RegexOptions.Singleline),
|
RegexOptions.Singleline),
|
||||||
PatchFactory = BuildSetAccountLanguagePatch
|
PatchFactory = BuildSetAccountLanguagePatch
|
||||||
|
},
|
||||||
|
new PatchEntry
|
||||||
|
{
|
||||||
|
// Last-resort guard: any code path that dispatches ACTION_SET_ACCOUNT
|
||||||
|
// (periodic refreshAccount, push updates, profile edits, etc.) must keep
|
||||||
|
// subscription on the store object even when it bypasses the account API
|
||||||
|
// service methods patched above.
|
||||||
|
Name = "setAccountReducer",
|
||||||
|
SearchHints = new[] { "ACTION_SET_ACCOUNT" },
|
||||||
|
Target = new Regex(
|
||||||
|
@"const (?<decl>\w+)=""ACTION_SET_ACCOUNT"";function (?<fn>\w+)\((?<params>[^)]*)\)\{return\{\.\.\.(?<state>\w+),account:(?<account>\w+)\}\}",
|
||||||
|
RegexOptions.Singleline),
|
||||||
|
PatchFactory = BuildSetAccountReducerPatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user