Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -368,4 +368,8 @@ export class VaultController {
getendpoint() {
return this.#endpoint;
}

async clear() {
await this.#store.delete("vault");
}
}
8 changes: 8 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/key.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -212,4 +212,12 @@ export class KeyService {
keyId: rest.join(":"),
};
}

async clear() {
this.#managerCache.clear();
this.#contexts.clear();
await this.#store.delete(CONTEXTS_KEY);
await this.#store.delete(READY_KEY);
this.#ready = false;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -216,4 +216,9 @@ export class SecurityController {
return biometric;
});
}

async clear() {
await this.#store.delete("pin");
await this.#store.delete("biometrics");
}
}
6 changes: 6 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/user.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -143,4 +143,10 @@ export class UserController {
return undefined;
});
}

async clear() {
await this.#store.delete("user");
await this.#store.delete("fake");
await this.#store.delete("doc");
}
}
15 changes: 15 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/state.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,4 +109,19 @@ export class GlobalState {
});
}
}

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);
}
const newGlobalState = await GlobalState.create();
return newGlobalState;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,7 +13,10 @@ import {
} from "@hugeicons/core-free-icons";
import { getContext } from "svelte";

const globalState = getContext<() => GlobalState>("globalState")();
const getGlobalState = getContext<() => GlobalState>("globalState");
const setGlobalState =
getContext<(value: GlobalState) => void>("setGlobalState");
let globalState = getGlobalState();

let isDeleteConfirmationOpen = $state(false);
let isFinalConfirmationOpen = $state(false);
Expand All@@ -33,11 +36,10 @@ function confirmDelete() {
isFinalConfirmationOpen = true;
}

function nukeWallet() {
globalState.userController.user = undefined;
globalState.securityController.clearPin();
globalState.isOnboardingComplete = false;
isFinalConfirmationOpen = false;
async function nukeWallet() {
const newGlobalState = await globalState.reset();
setGlobalState(newGlobalState);
globalState = newGlobalState;
goto("/onboarding");
}

Expand Down
3 changes: 3 additions & 0 deletions infrastructure/eid-wallet/src/routes/+layout.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,9 @@ let globalDeepLinkHandler: ((event: Event) => void) | undefined;
let mainWrapper: HTMLElement | undefined = $state(undefined);

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

Copy link
Copy Markdown
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 contextsecho"=== 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 filesecho"=== 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:

constsetGlobalState=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.


// replace with actual data loading logic
async function loadData() {
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -368,4 +368,8 @@ export class VaultController {
getendpoint() {
return this.#endpoint;
}

async clear() {
await this.#store.delete("vault");
}
}
8 changes: 8 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/key.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -212,4 +212,12 @@ export class KeyService {
keyId: rest.join(":"),
};
}

async clear() {
this.#managerCache.clear();
this.#contexts.clear();
await this.#store.delete(CONTEXTS_KEY);
await this.#store.delete(READY_KEY);
this.#ready = false;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -216,4 +216,9 @@ export class SecurityController {
return biometric;
});
}

async clear() {
await this.#store.delete("pin");
await this.#store.delete("biometrics");
}
}
6 changes: 6 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/user.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -143,4 +143,10 @@ export class UserController {
return undefined;
});
}

async clear() {
await this.#store.delete("user");
await this.#store.delete("fake");
await this.#store.delete("doc");
}
}
15 changes: 15 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/state.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,4 +109,19 @@ export class GlobalState {
});
}
}

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);
}
const newGlobalState = await GlobalState.create();
return newGlobalState;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,7 +13,10 @@ import {
} from "@hugeicons/core-free-icons";
import { getContext } from "svelte";

const globalState = getContext<() => GlobalState>("globalState")();
const getGlobalState = getContext<() => GlobalState>("globalState");
const setGlobalState =
getContext<(value: GlobalState) => void>("setGlobalState");
let globalState = getGlobalState();

let isDeleteConfirmationOpen = $state(false);
let isFinalConfirmationOpen = $state(false);
Expand All@@ -33,11 +36,10 @@ function confirmDelete() {
isFinalConfirmationOpen = true;
}

function nukeWallet() {
globalState.userController.user = undefined;
globalState.securityController.clearPin();
globalState.isOnboardingComplete = false;
isFinalConfirmationOpen = false;
async function nukeWallet() {
const newGlobalState = await globalState.reset();
setGlobalState(newGlobalState);
globalState = newGlobalState;
goto("/onboarding");
}

Expand Down
3 changes: 3 additions & 0 deletions infrastructure/eid-wallet/src/routes/+layout.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,9 @@ let globalDeepLinkHandler: ((event: Event) => void) | undefined;
let mainWrapper: HTMLElement | undefined = $state(undefined);

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

Copy link
Copy Markdown
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 contextsecho"=== 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 filesecho"=== 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:

constsetGlobalState=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.


// replace with actual data loading logic
async function loadData() {
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -368,4 +368,8 @@ export class VaultController {
getendpoint() {
return this.#endpoint;
}

async clear() {
await this.#store.delete("vault");
}
}
8 changes: 8 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/key.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -212,4 +212,12 @@ export class KeyService {
keyId: rest.join(":"),
};
}

async clear() {
this.#managerCache.clear();
this.#contexts.clear();
await this.#store.delete(CONTEXTS_KEY);
await this.#store.delete(READY_KEY);
this.#ready = false;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -216,4 +216,9 @@ export class SecurityController {
return biometric;
});
}

async clear() {
await this.#store.delete("pin");
await this.#store.delete("biometrics");
}
}
6 changes: 6 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/user.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -143,4 +143,10 @@ export class UserController {
return undefined;
});
}

async clear() {
await this.#store.delete("user");
await this.#store.delete("fake");
await this.#store.delete("doc");
}
}
15 changes: 15 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/state.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,4 +109,19 @@ export class GlobalState {
});
}
}

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);
}
const newGlobalState = await GlobalState.create();
return newGlobalState;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,7 +13,10 @@ import {
} from "@hugeicons/core-free-icons";
import { getContext } from "svelte";

const globalState = getContext<() => GlobalState>("globalState")();
const getGlobalState = getContext<() => GlobalState>("globalState");
const setGlobalState =
getContext<(value: GlobalState) => void>("setGlobalState");
let globalState = getGlobalState();

let isDeleteConfirmationOpen = $state(false);
let isFinalConfirmationOpen = $state(false);
Expand All@@ -33,11 +36,10 @@ function confirmDelete() {
isFinalConfirmationOpen = true;
}

function nukeWallet() {
globalState.userController.user = undefined;
globalState.securityController.clearPin();
globalState.isOnboardingComplete = false;
isFinalConfirmationOpen = false;
async function nukeWallet() {
const newGlobalState = await globalState.reset();
setGlobalState(newGlobalState);
globalState = newGlobalState;
goto("/onboarding");
}

Expand Down
3 changes: 3 additions & 0 deletions infrastructure/eid-wallet/src/routes/+layout.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,9 @@ let globalDeepLinkHandler: ((event: Event) => void) | undefined;
let mainWrapper: HTMLElement | undefined = $state(undefined);

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

Copy link
Copy Markdown
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 contextsecho"=== 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 filesecho"=== 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:

constsetGlobalState=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.


// replace with actual data loading logic
async function loadData() {
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -368,4 +368,8 @@ export class VaultController {
getendpoint() {
return this.#endpoint;
}

async clear() {
await this.#store.delete("vault");
}
}
8 changes: 8 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/key.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -212,4 +212,12 @@ export class KeyService {
keyId: rest.join(":"),
};
}

async clear() {
this.#managerCache.clear();
this.#contexts.clear();
await this.#store.delete(CONTEXTS_KEY);
await this.#store.delete(READY_KEY);
this.#ready = false;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -216,4 +216,9 @@ export class SecurityController {
return biometric;
});
}

async clear() {
await this.#store.delete("pin");
await this.#store.delete("biometrics");
}
}
6 changes: 6 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/user.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -143,4 +143,10 @@ export class UserController {
return undefined;
});
}

async clear() {
await this.#store.delete("user");
await this.#store.delete("fake");
await this.#store.delete("doc");
}
}
15 changes: 15 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/state.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,4 +109,19 @@ export class GlobalState {
});
}
}

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);
}
const newGlobalState = await GlobalState.create();
return newGlobalState;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,7 +13,10 @@ import {
} from "@hugeicons/core-free-icons";
import { getContext } from "svelte";

const globalState = getContext<() => GlobalState>("globalState")();
const getGlobalState = getContext<() => GlobalState>("globalState");
const setGlobalState =
getContext<(value: GlobalState) => void>("setGlobalState");
let globalState = getGlobalState();

let isDeleteConfirmationOpen = $state(false);
let isFinalConfirmationOpen = $state(false);
Expand All@@ -33,11 +36,10 @@ function confirmDelete() {
isFinalConfirmationOpen = true;
}

function nukeWallet() {
globalState.userController.user = undefined;
globalState.securityController.clearPin();
globalState.isOnboardingComplete = false;
isFinalConfirmationOpen = false;
async function nukeWallet() {
const newGlobalState = await globalState.reset();
setGlobalState(newGlobalState);
globalState = newGlobalState;
goto("/onboarding");
}

Expand Down
3 changes: 3 additions & 0 deletions infrastructure/eid-wallet/src/routes/+layout.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,9 @@ let globalDeepLinkHandler: ((event: Event) => void) | undefined;
let mainWrapper: HTMLElement | undefined = $state(undefined);

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

Copy link
Copy Markdown
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 contextsecho"=== 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 filesecho"=== 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:

constsetGlobalState=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.


// replace with actual data loading logic
async function loadData() {
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -368,4 +368,8 @@ export class VaultController {
getendpoint() {
return this.#endpoint;
}

async clear() {
await this.#store.delete("vault");
}
}
8 changes: 8 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/key.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -212,4 +212,12 @@ export class KeyService {
keyId: rest.join(":"),
};
}

async clear() {
this.#managerCache.clear();
this.#contexts.clear();
await this.#store.delete(CONTEXTS_KEY);
await this.#store.delete(READY_KEY);
this.#ready = false;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -216,4 +216,9 @@ export class SecurityController {
return biometric;
});
}

async clear() {
await this.#store.delete("pin");
await this.#store.delete("biometrics");
}
}
6 changes: 6 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/user.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -143,4 +143,10 @@ export class UserController {
return undefined;
});
}

async clear() {
await this.#store.delete("user");
await this.#store.delete("fake");
await this.#store.delete("doc");
}
}
15 changes: 15 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/state.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,4 +109,19 @@ export class GlobalState {
});
}
}

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);
}
const newGlobalState = await GlobalState.create();
return newGlobalState;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,7 +13,10 @@ import {
} from "@hugeicons/core-free-icons";
import { getContext } from "svelte";

const globalState = getContext<() => GlobalState>("globalState")();
const getGlobalState = getContext<() => GlobalState>("globalState");
const setGlobalState =
getContext<(value: GlobalState) => void>("setGlobalState");
let globalState = getGlobalState();

let isDeleteConfirmationOpen = $state(false);
let isFinalConfirmationOpen = $state(false);
Expand All@@ -33,11 +36,10 @@ function confirmDelete() {
isFinalConfirmationOpen = true;
}

function nukeWallet() {
globalState.userController.user = undefined;
globalState.securityController.clearPin();
globalState.isOnboardingComplete = false;
isFinalConfirmationOpen = false;
async function nukeWallet() {
const newGlobalState = await globalState.reset();
setGlobalState(newGlobalState);
globalState = newGlobalState;
goto("/onboarding");
}

Expand Down
3 changes: 3 additions & 0 deletions infrastructure/eid-wallet/src/routes/+layout.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,9 @@ let globalDeepLinkHandler: ((event: Event) => void) | undefined;
let mainWrapper: HTMLElement | undefined = $state(undefined);

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

Copy link
Copy Markdown
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 contextsecho"=== 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 filesecho"=== 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:

constsetGlobalState=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.


// replace with actual data loading logic
async function loadData() {
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -368,4 +368,8 @@ export class VaultController {
getendpoint() {
return this.#endpoint;
}

async clear() {
await this.#store.delete("vault");
}
}
8 changes: 8 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/key.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -212,4 +212,12 @@ export class KeyService {
keyId: rest.join(":"),
};
}

async clear() {
this.#managerCache.clear();
this.#contexts.clear();
await this.#store.delete(CONTEXTS_KEY);
await this.#store.delete(READY_KEY);
this.#ready = false;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -216,4 +216,9 @@ export class SecurityController {
return biometric;
});
}

async clear() {
await this.#store.delete("pin");
await this.#store.delete("biometrics");
}
}
6 changes: 6 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/user.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -143,4 +143,10 @@ export class UserController {
return undefined;
});
}

async clear() {
await this.#store.delete("user");
await this.#store.delete("fake");
await this.#store.delete("doc");
}
}
15 changes: 15 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/state.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,4 +109,19 @@ export class GlobalState {
});
}
}

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);
}
const newGlobalState = await GlobalState.create();
return newGlobalState;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,7 +13,10 @@ import {
} from "@hugeicons/core-free-icons";
import { getContext } from "svelte";

const globalState = getContext<() => GlobalState>("globalState")();
const getGlobalState = getContext<() => GlobalState>("globalState");
const setGlobalState =
getContext<(value: GlobalState) => void>("setGlobalState");
let globalState = getGlobalState();

let isDeleteConfirmationOpen = $state(false);
let isFinalConfirmationOpen = $state(false);
Expand All@@ -33,11 +36,10 @@ function confirmDelete() {
isFinalConfirmationOpen = true;
}

function nukeWallet() {
globalState.userController.user = undefined;
globalState.securityController.clearPin();
globalState.isOnboardingComplete = false;
isFinalConfirmationOpen = false;
async function nukeWallet() {
const newGlobalState = await globalState.reset();
setGlobalState(newGlobalState);
globalState = newGlobalState;
goto("/onboarding");
}

Expand Down
3 changes: 3 additions & 0 deletions infrastructure/eid-wallet/src/routes/+layout.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,9 @@ let globalDeepLinkHandler: ((event: Event) => void) | undefined;
let mainWrapper: HTMLElement | undefined = $state(undefined);

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

Copy link
Copy Markdown
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 contextsecho"=== 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 filesecho"=== 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:

constsetGlobalState=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.


// replace with actual data loading logic
async function loadData() {
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -368,4 +368,8 @@ export class VaultController {
getendpoint() {
return this.#endpoint;
}

async clear() {
await this.#store.delete("vault");
}
}
8 changes: 8 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/key.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -212,4 +212,12 @@ export class KeyService {
keyId: rest.join(":"),
};
}

async clear() {
this.#managerCache.clear();
this.#contexts.clear();
await this.#store.delete(CONTEXTS_KEY);
await this.#store.delete(READY_KEY);
this.#ready = false;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -216,4 +216,9 @@ export class SecurityController {
return biometric;
});
}

async clear() {
await this.#store.delete("pin");
await this.#store.delete("biometrics");
}
}
6 changes: 6 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/user.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -143,4 +143,10 @@ export class UserController {
return undefined;
});
}

async clear() {
await this.#store.delete("user");
await this.#store.delete("fake");
await this.#store.delete("doc");
}
}
15 changes: 15 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/state.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,4 +109,19 @@ export class GlobalState {
});
}
}

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);
}
const newGlobalState = await GlobalState.create();
return newGlobalState;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,7 +13,10 @@ import {
} from "@hugeicons/core-free-icons";
import { getContext } from "svelte";

const globalState = getContext<() => GlobalState>("globalState")();
const getGlobalState = getContext<() => GlobalState>("globalState");
const setGlobalState =
getContext<(value: GlobalState) => void>("setGlobalState");
let globalState = getGlobalState();

let isDeleteConfirmationOpen = $state(false);
let isFinalConfirmationOpen = $state(false);
Expand All@@ -33,11 +36,10 @@ function confirmDelete() {
isFinalConfirmationOpen = true;
}

function nukeWallet() {
globalState.userController.user = undefined;
globalState.securityController.clearPin();
globalState.isOnboardingComplete = false;
isFinalConfirmationOpen = false;
async function nukeWallet() {
const newGlobalState = await globalState.reset();
setGlobalState(newGlobalState);
globalState = newGlobalState;
goto("/onboarding");
}

Expand Down
3 changes: 3 additions & 0 deletions infrastructure/eid-wallet/src/routes/+layout.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,9 @@ let globalDeepLinkHandler: ((event: Event) => void) | undefined;
let mainWrapper: HTMLElement | undefined = $state(undefined);

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

Copy link
Copy Markdown
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 contextsecho"=== 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 filesecho"=== 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:

constsetGlobalState=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.


// replace with actual data loading logic
async function loadData() {
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -368,4 +368,8 @@ export class VaultController {
getendpoint() {
return this.#endpoint;
}

async clear() {
await this.#store.delete("vault");
}
}
8 changes: 8 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/key.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -212,4 +212,12 @@ export class KeyService {
keyId: rest.join(":"),
};
}

async clear() {
this.#managerCache.clear();
this.#contexts.clear();
await this.#store.delete(CONTEXTS_KEY);
await this.#store.delete(READY_KEY);
this.#ready = false;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -216,4 +216,9 @@ export class SecurityController {
return biometric;
});
}

async clear() {
await this.#store.delete("pin");
await this.#store.delete("biometrics");
}
}
6 changes: 6 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/controllers/user.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -143,4 +143,10 @@ export class UserController {
return undefined;
});
}

async clear() {
await this.#store.delete("user");
await this.#store.delete("fake");
await this.#store.delete("doc");
}
}
15 changes: 15 additions & 0 deletions infrastructure/eid-wallet/src/lib/global/state.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,4 +109,19 @@ export class GlobalState {
});
}
}

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);
}
const newGlobalState = await GlobalState.create();
return newGlobalState;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,7 +13,10 @@ import {
} from "@hugeicons/core-free-icons";
import { getContext } from "svelte";

const globalState = getContext<() => GlobalState>("globalState")();
const getGlobalState = getContext<() => GlobalState>("globalState");
const setGlobalState =
getContext<(value: GlobalState) => void>("setGlobalState");
let globalState = getGlobalState();

let isDeleteConfirmationOpen = $state(false);
let isFinalConfirmationOpen = $state(false);
Expand All@@ -33,11 +36,10 @@ function confirmDelete() {
isFinalConfirmationOpen = true;
}

function nukeWallet() {
globalState.userController.user = undefined;
globalState.securityController.clearPin();
globalState.isOnboardingComplete = false;
isFinalConfirmationOpen = false;
async function nukeWallet() {
const newGlobalState = await globalState.reset();
setGlobalState(newGlobalState);
globalState = newGlobalState;
goto("/onboarding");
}

Expand Down
3 changes: 3 additions & 0 deletions infrastructure/eid-wallet/src/routes/+layout.svelte
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,9 @@ let globalDeepLinkHandler: ((event: Event) => void) | undefined;
let mainWrapper: HTMLElement | undefined = $state(undefined);

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

Copy link
Copy Markdown
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 contextsecho"=== 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 filesecho"=== 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:

constsetGlobalState=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.


// replace with actual data loading logic
async function loadData() {
Expand Down