fix: SessionProvider preset support and address normalization#2401
fix: SessionProvider preset support and address normalization#2401
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2401 +/- ##
==========================================
+ Coverage 19.81% 20.57% +0.76%
==========================================
Files 327 316 -11
Lines 33133 33288 +155
Branches 883 970 +87
==========================================
+ Hits 6564 6849 +285
+ Misses 26557 26425 -132
- Partials 12 14 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
c6e0af8 to
7710141
Compare
…sses SessionProvider lacked preset support, forcing developers to manually duplicate preset policies. When presets were configured but policies were passed separately, the keychain and SDK could compute different session hashes, causing session/not-registered errors. Changes: - Add `preset` option to SessionOptions, resolving policies via loadConfig() to match the keychain's behavior - Normalize addresses with getChecksumAddress in toWasmPolicies to prevent hash divergence from inconsistent address casing - Warn when ControllerProvider receives both preset and policies without shouldOverridePresetPolicies Fixes #2399 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace lazy _resolvePresetPolicies() pattern with eagerly-stored promise. Constructor kicks off loadConfig() immediately; async methods just await the stored promise. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
De-duplicate the preset config → chain policies extraction logic shared between SessionProvider and keychain's getConfigChainPolicies. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When both preset and policies are provided, the SDK uses explicit policies locally. Ensure the keychain URL also sends policies (not preset) to avoid hash mismatch. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When both preset and policies are provided, preset takes precedence (policies are ignored with a warning). This matches ControllerProvider behavior and nudges developers toward using preset as the single source of truth. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Matches ControllerProvider's escape hatch exactly, allowing explicit policies to take precedence over preset when the flag is set. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…wrapper Move the isPoliciesResolved check into the Authentication component so child routes (Session, ConnectRoute) never render until preset policies are fully resolved. This eliminates scattered isPoliciesResolved guards from individual components. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…method Replace _policiesReady + _resolvePresetPolicies with a unified _init() that handles preset resolution, session retrieval, and signer setup in sequence. Public methods await _ready instead of _policiesReady. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
db373b4 to
a343114
Compare
- Add missing SessionPolicies type import - Add definite assignment assertions for async-initialized fields - Remove redundant tryRetrieveFromQueryOrStorage() calls after _init() - Remove redundant _preset = undefined assignment - Update toWasmPolicies docstring to mention address normalization - Align ControllerProvider warning message with SessionProvider Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Did more work after initial review
|
Claude finished @kronosapiens's task —— View job Analyzing controller PR changes and updating documentation
|
Updates documentation to reflect changes made in:
fix: SessionProvider preset support and address normalization
Related controller PR: cartridge-gg/controller#2401
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
…ionFromRedirect Fixes a regression introduced in #2401 where probe() would always return undefined after calling ingestSessionFromRedirect on a deep link redirect (Capacitor, etc). The issue: #2401 moved session restoration into _init(), which runs once during construction. For deep links, the session data arrives *after* construction via ingestSessionFromRedirect, so _init() never sees it. Result: probe() had no path to create the account. Changes: - Separate concerns: _setSigningKeys() (sync) and _resolvePreset() (async) - Restore on-demand retrieval: probe/connect/username call tryRetrieveSessionAccount - Rename tryRetrieveFromQueryOrStorage to tryRetrieveSessionAccount for clarity - Mark tryRetrieveSessionAccount as private since it's internal restoration logic - Add comments explaining the two session entry points (localStorage and URL query) This restores the pre-#2401 behavior of checking storage on every public method call, allowing both web redirects (query param flow) and deep links (explicit call flow) to work correctly. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…ionFromRedirect Fixes a regression introduced in #2401 where probe() would always return undefined after calling ingestSessionFromRedirect on a deep link redirect (Capacitor, etc). The issue: #2401 moved session restoration into _init(), which runs once during construction. For deep links, the session data arrives *after* construction via ingestSessionFromRedirect, so _init() never sees it. Result: probe() had no path to create the account. Changes: - Separate concerns: _setSigningKeys() (sync) and _resolvePreset() (async) - Restore on-demand retrieval: probe/connect/username call tryRetrieveSessionAccount - Rename tryRetrieveFromQueryOrStorage to tryRetrieveSessionAccount for clarity - Mark tryRetrieveSessionAccount as private since it's internal restoration logic - Add comments explaining the two session entry points (localStorage and URL query) This restores the pre-#2401 behavior of checking storage on every public method call, allowing both web redirects (query param flow) and deep links (explicit call flow) to work correctly. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…2409) ## Summary Fixes a regression introduced in #2401 where `SessionProvider.probe()` would always return undefined after calling `ingestSessionFromRedirect()` on a deep link redirect (Capacitor, mobile apps, etc). **Root cause:** #2401 moved session restoration into `_init()`, which runs once during construction. For deep links, the session data arrives *after* construction via `ingestSessionFromRedirect()`, so `_init()` never sees it. Result: `probe()` had no path to create the account. **Solution:** Restore on-demand session retrieval in public methods (`probe()`, `connect()`, `username()`), matching the pre-#2401 behavior. Both web redirects (query param flow) and deep links (explicit call flow) now work correctly. ## Changes - Split initialization: `_setSigningKeys()` (sync) handles signer setup, `_resolvePreset()` (async) handles preset resolution - Restore on-demand account retrieval: `tryRetrieveSessionAccount()` called by public methods when account not set - Rename `tryRetrieveFromQueryOrStorage` → `tryRetrieveSessionAccount` for clarity and mark as private - Add comments explaining the two session entry points (localStorage and URL query params) - Improve variable naming: `_ready` → `_readyPromise` Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>

Summary
Fixes #2399.
Addresses
session/not-registerederrors caused by policy hash divergence between the SDK and keychain.SDK changes (
@cartridge/controller)presetandshouldOverridePresetPoliciestoSessionOptions: Developers can now passpreset: "my-game"instead of manually duplicating policies.Preset policies are resolved via
loadConfig()from@cartridge/presets, matching the keychain's behavior.Policy precedence matches
ControllerProvider: preset wins unlessshouldOverridePresetPolicies: true._init(): Preset resolution, session retrieval from storage, and signer key setup all happen in a single eagerly-started async method.Public methods (
username,probe,connect) simplyawait this._ready.toWasmPolicies: AppliesgetChecksumAddress()to contract targets before hashing, preventing divergence from inconsistent address casing.getPresetSessionPoliciesutility: Shared betweenSessionProviderand the keychain'sgetConfigChainPolicies, replacing ~25 lines of defensive type narrowing with a clean helper.presetandpoliciesare provided without the override flag, aconsole.warnis logged (previously policies were silently ignored inControllerProvider).presetin keychain URL: When preset is used,connect()sends&preset=instead of&policies=, so the keychain resolves the same policies from the same source.Keychain changes
isPoliciesResolvedinAuthentication: TheAuthenticationwrapper now waits for preset policies to fully resolve before rendering child routes.This replaces scattered
isPoliciesResolvedguards that were previously inConnectRouteand eliminates race conditions where components render before async preset policy resolution completes.Root cause
When a developer configured presets and used
SessionProvider, the keychain would resolve policies from the preset while the SDK used the developer's manually-passed policies.If these differed (or if addresses had different casing), the session hash would diverge, producing
session/not-registerederrors.Design note
Preset resolution is async (
loadConfigfetches from the network), but JS constructors can't be async.The
_init()method is eagerly started in the constructor and stores its promise as_ready.A cleaner alternative would be a static factory method (
SessionProvider.create(options)), but that's a breaking API change — worth considering in a future major version.Follow-up
TelegramProviderand Node.jsSessionProviderTest plan
toWasmPoliciestests)tsc --noEmitpasses with zero errors🤖 Generated with Claude Code