Skip to content

Conversation

@sosweetham
Copy link
Member

@sosweetham sosweetham commented Nov 14, 2025

Description of change

Fixes delete account logic to properly reset application state to help start new onboarding properly

Issue Number

Type of change

  • Fix (a change which fixes an issue)

How the change has been tested

Manually

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features
    • Added a single-step wallet reset in Settings that fully clears user data, security settings (PIN/biometrics), keys, and encrypted vault contents, then restarts onboarding.
    • The reset is now performed asynchronously to ensure all stored state is reliably cleared before navigation.

@sosweetham sosweetham requested a review from coodos as a code owner November 14, 2025 09:42
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 14, 2025

Walkthrough

Adds public async clear() methods to VaultController, KeyService, SecurityController, and UserController; introduces GlobalState.reset() to call those clears and remove init/onboarding flags; updates settings UI to asynchronously call reset and added a context setter to expose setGlobalState in layout.

Changes

Cohort / File(s) Change Summary
Controller clear methods
infrastructure/eid-wallet/src/lib/global/controllers/evault.ts, infrastructure/eid-wallet/src/lib/global/controllers/key.ts, infrastructure/eid-wallet/src/lib/global/controllers/security.ts, infrastructure/eid-wallet/src/lib/global/controllers/user.ts
Added public async clear() to each controller/service to delete their respective stored entries and reset internal caches/flags.
GlobalState orchestration
infrastructure/eid-wallet/src/lib/global/state.ts
Added public async reset() that calls controller clear() methods, deletes initialized and isOnboardingComplete from the store, handles errors, and re-instantiates GlobalState.
Settings UI integration
infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte
Converted nukeWallet() to async, now awaits globalState.reset(), updates global state via setGlobalState, and navigates to /onboarding. Also changed how global state is retrieved (use getGlobalState and setGlobalState contexts).
Layout context setter
infrastructure/eid-wallet/src/routes/+layout.svelte
Added `setContext("setGlobalState", (value: GlobalState

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Settings as Settings Page
    participant Layout as App Layout
    participant GlobalState
    participant Controllers as Controllers
    participant Store as Internal Store

    User->>Settings: click "nuke wallet"
    Settings->>GlobalState: call nukeWallet() → await reset()
    GlobalState->>Controllers: call clear() on Vault, Key, Security, User
    Controllers->>Store: delete respective keys / clear caches
    Store-->>Controllers: deletions acknowledged
    Controllers-->>GlobalState: clear() complete
    GlobalState->>Store: delete initialized / onboarding flags
    Store-->>GlobalState: deletions acknowledged
    GlobalState-->>Layout: return new GlobalState instance
    Layout->>Settings: setGlobalState(newState)
    Settings->>Settings: navigate to /onboarding
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Attention areas:
    • key.ts — cache invalidation and flags (ensure all keys cleared).
    • state.ts — sequence, error handling, and re-instantiation correctness.
    • +page.svelte / +layout.svelte — context getter/setter usage and navigation flow.

Suggested reviewers

  • coodos

Poem

🐇 I hop and clear each treasured chest,

Pins and keys now take a rest,
A gentle reset, a brand new start,
Off to onboarding with a happy heart,
Thump-thump, the wallet's fresh and blessed.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main purpose of the PR: fixing wallet deletion logic by properly resetting application state to prevent synchronization issues.
Description check ✅ Passed The PR description follows the template with all required sections completed, including issue context, type of change (Fix), testing method (Manual), and a fully checked change checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/nuke-wallet-logic

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
infrastructure/eid-wallet/src/lib/global/controllers/key.ts (1)

54-60: Code duplication: reset() and clear() methods are nearly identical.

Both reset() (lines 54-60) and the newly added clear() (lines 216-222) perform the same operations. This duplication increases maintenance burden. Consider whether both methods are needed, or if one should delegate to the other.

If both methods are intended to remain, consider this pattern:

 async reset(): Promise<void> {
+    await this.clear();
+ }
+
+ async clear() {
     this.#managerCache.clear();
     this.#contexts.clear();
     await this.#store.delete(CONTEXTS_KEY);
     await this.#store.delete(READY_KEY);
     this.#ready = false;
 }
-
- async clear() {
-     this.#managerCache.clear();
-     this.#contexts.clear();
-     this.#store.delete(CONTEXTS_KEY);
-     this.#store.delete(READY_KEY);
-     this.#ready = false;
- }

Also applies to: 216-222

🧹 Nitpick comments (1)
infrastructure/eid-wallet/src/lib/global/controllers/evault.ts (1)

372-374: Consider resetting internal state fields.

The clear() method only deletes the store entry but doesn't reset the internal state fields #client, #endpoint, and #profileCreationStatus. If the VaultController instance is reused after clearing (which happens in the reset flow), these stale values could cause unexpected behavior.

Apply this diff to reset internal state:

 async clear() {
+    this.#client = null;
+    this.#endpoint = null;
+    this.#profileCreationStatus = "idle";
     await this.#store.delete("vault");
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 490ae34 and e94a527.

📒 Files selected for processing (6)
  • infrastructure/eid-wallet/src/lib/global/controllers/evault.ts (1 hunks)
  • infrastructure/eid-wallet/src/lib/global/controllers/key.ts (1 hunks)
  • infrastructure/eid-wallet/src/lib/global/controllers/security.ts (1 hunks)
  • infrastructure/eid-wallet/src/lib/global/controllers/user.ts (1 hunks)
  • infrastructure/eid-wallet/src/lib/global/state.ts (1 hunks)
  • infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-04-24T05:54:12.858Z
Learnt from: sosweetham
Repo: MetaState-Prototype-Project/prototype PR: 97
File: infrastructure/eid-wallet/src/routes/+page.svelte:31-35
Timestamp: 2025-04-24T05:54:12.858Z
Learning: The "Clear PIN" button on the root page of the eID wallet application is intended for debugging purposes only, not for production use, so it doesn't require confirmation dialogs or detailed user guidance.

Applied to files:

  • infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte
🔇 Additional comments (2)
infrastructure/eid-wallet/src/lib/global/controllers/security.ts (1)

220-223: LGTM!

The clear() method correctly deletes both security-related store entries with proper async/await handling.

infrastructure/eid-wallet/src/lib/global/controllers/user.ts (1)

147-151: LGTM!

The clear() method correctly deletes all user-related store entries with proper async/await handling for each operation.

Comment on lines 113 to 120
async reset() {
await this.securityController.clear();
await this.userController.clear();
await this.vaultController.clear();
await this.keyService.clear();
await this.#store.delete("initialized");
await this.#store.delete("isOnboardingComplete");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Consider adding error handling to prevent partial reset state.

The reset() method correctly orchestrates clearing all controllers sequentially. However, if any clear() operation fails midway, the application could be left in an inconsistent state with some data cleared and others not. Consider wrapping the operations in a try-catch block or implementing a rollback mechanism.

Example with error handling:

 async reset() {
+    try {
         await this.securityController.clear();
         await this.userController.clear();
         await this.vaultController.clear();
         await this.keyService.clear();
         await this.#store.delete("initialized");
         await this.#store.delete("isOnboardingComplete");
+    } catch (error) {
+        console.error("Failed to reset global state:", error);
+        throw new Error("Incomplete reset - application may be in inconsistent state");
+    }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async reset() {
await this.securityController.clear();
await this.userController.clear();
await this.vaultController.clear();
await this.keyService.clear();
await this.#store.delete("initialized");
await this.#store.delete("isOnboardingComplete");
}
async reset() {
try {
await this.securityController.clear();
await this.userController.clear();
await this.vaultController.clear();
await this.keyService.clear();
await this.#store.delete("initialized");
await this.#store.delete("isOnboardingComplete");
} catch (error) {
console.error("Failed to reset global state:", error);
throw new Error("Incomplete reset - application may be in inconsistent state");
}
}
🤖 Prompt for AI Agents
In infrastructure/eid-wallet/src/lib/global/state.ts around lines 113-120, the
reset() sequence can leave the app in a partially-reset state if any clear()
fails; wrap the sequence in a try/catch, take a lightweight snapshot/backup of
each controller/store state before performing clears, perform the clears
sequentially inside the try, and if any operation fails run a rollback that
restores controllers/stores from the snapshot, log the original error and
rethrow or return a structured failure; ensure snapshot cleanup on success and
make the function return/throw a clear error so callers can act.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
infrastructure/eid-wallet/src/lib/global/controllers/key.ts (1)

216-222: Consider removing duplicate logic between clear() and reset() methods.

The clear() method (lines 216-222) is identical to the existing reset() method (lines 54-60). Both perform the same operations in the same order. This duplication creates maintenance overhead and API confusion.

Consider one of these approaches:

  • If clear() is the new standard API across controllers, deprecate or remove reset() and migrate callers to clear()
  • If both methods serve different purposes, add documentation explaining when to use each
  • If reset() should remain for backward compatibility, have clear() delegate to reset() (or vice versa)

Additionally, add an explicit return type to clear() for consistency:

-async clear() {
+async clear(): Promise<void> {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e94a527 and 4748d0d.

📒 Files selected for processing (3)
  • infrastructure/eid-wallet/src/lib/global/controllers/key.ts (1 hunks)
  • infrastructure/eid-wallet/src/lib/global/state.ts (1 hunks)
  • infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • infrastructure/eid-wallet/src/lib/global/state.ts
  • infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build

@coodos coodos changed the title Fix/nuke wallet logic Fix/wallet restoration not syncing to graphql Nov 14, 2025
@coodos coodos changed the title Fix/wallet restoration not syncing to graphql Fix/wallet restoration not syncing to graphql due to messy state Nov 14, 2025
@coodos coodos merged commit 328bc79 into main Nov 14, 2025
3 of 4 checks passed
@coodos coodos deleted the fix/nuke-wallet-logic branch November 14, 2025 10:20
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4748d0d and 27bd672.

📒 Files selected for processing (3)
  • infrastructure/eid-wallet/src/lib/global/state.ts (1 hunks)
  • infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte (2 hunks)
  • infrastructure/eid-wallet/src/routes/+layout.svelte (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • infrastructure/eid-wallet/src/lib/global/state.ts
  • infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build

Comment on lines +23 to +25
setContext("setGlobalState", (value: GlobalState | undefined) => {
globalState = value;
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Request verification: Potential race conditions during state reset.

Exposing a setter that allows external components to directly mutate globalState could lead to race conditions if components access globalState while it's being reset to undefined or a new instance. Consider these scenarios:

  1. Component A reads globalState via the getter context
  2. Component B calls setGlobalState(undefined) or setGlobalState(newState)
  3. Component A attempts to access properties on what it thought was a valid GlobalState object

To verify this is safe, run the following script to check how globalState and setGlobalState are used together:

Consider these improvements:

  1. Add guards: Check if operations are in progress before allowing mutation
  2. Clarify intent: Rename to setContext("resetGlobalState", ...) to signal this is for reset operations only
  3. Alternative pattern: Expose a resetGlobalState() method that encapsulates the full reset logic rather than a generic setter:
-setContext("setGlobalState", (value: GlobalState | undefined) => {
-    globalState = value;
-});
+setContext("resetGlobalState", async () => {
+    if (globalState) {
+        await globalState.reset();
+    }
+    globalState = await GlobalState.create();
+});

This would provide better encapsulation and prevent misuse while still supporting the wallet reset flow.


🏁 Script executed:

#!/bin/bash
# Check usage patterns of getGlobalState and setGlobalState contexts

echo "=== Finding setGlobalState usage ==="
rg -n --type=ts --type=svelte -C 5 'getContext.*setGlobalState'

echo -e "\n=== Finding globalState getter usage ==="
rg -n --type=ts --type=svelte -C 5 'getContext.*globalState.*\(\)'

echo -e "\n=== Finding reset() calls ==="
rg -n --type=ts --type=svelte -C 5 '\.reset\(\)'

Length of output: 202


🏁 Script executed:

#!/bin/bash
# Check usage patterns - corrected for .svelte files

echo "=== Finding setGlobalState usage (no type filter) ==="
rg -n -C 5 'setGlobalState' --type-add 'svelte:*.svelte' --type svelte --type ts

echo -e "\n=== Finding globalState context getter usage ==="
rg -n -C 5 "getContext.*['\"]globalState" --type-add 'svelte:*.svelte' --type svelte --type ts

echo -e "\n=== Finding reset\(\) method calls ==="
rg -n -C 5 '\.reset\s*\(' --type-add 'svelte:*.svelte' --type svelte --type ts

echo -e "\n=== Finding setContext calls in layout ==="
rg -n -C 5 'setContext' infrastructure/eid-wallet/src/routes/+layout.svelte

Length of output: 26473


Fix type mismatch in setGlobalState context setter.

The setter's type signature doesn't match its usage. The layout exports (value: GlobalState | undefined), but settings/+page.svelte expects (value: GlobalState). Update the type in settings/+page.svelte line 18 to accept undefined:

const setGlobalState = getContext<(value: GlobalState | undefined) => void>("setGlobalState");

Regarding the race condition concern: the single-threaded nature of JavaScript and immediate navigation after reset (line 43) significantly reduce practical risk. Components holding stale references won't run after the navigation occurs. However, for clarity and future maintainability, consider renaming this to resetGlobalState() to signal its specific purpose rather than a generic state setter.

🤖 Prompt for AI Agents
in infrastructure/eid-wallet/src/routes/+layout.svelte lines 23-25 and
settings/+page.svelte line 18, the setGlobalState context setter is declared to
accept GlobalState | undefined but settings/+page.svelte types it as (value:
GlobalState) — update the getContext call in settings/+page.svelte to use
(value: GlobalState | undefined) => void so the types match; optionally consider
renaming the setter to resetGlobalState if its intent is to clear state for
clarity.

@coderabbitai coderabbitai bot mentioned this pull request Nov 14, 2025
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants