diag(nip46): add temporary lifecycle diagnostics for #33

Code-level audit of the NIP-46/Amber login+profile+persistence bug points at a
single shared SignerManager.nip46Client + per-profile restore/switch not being
multi-account-aware. Added TEMP [nip46-diag] userLogger traces (visible on
unstable; devLogger is gated off there) at:
- scheduleStoredRemoteSignerRestore (restore-on-load → "unknown user")
- disconnectRemoteSigner (the shared-client teardown → "logs out everyone")
- SignerManager.logout (scope)
- authService.switchProfile (does the switch resolve the expected pubkey)

These let a single Amber reproduction pinpoint the exact failure before the fix.
Findings + plan recorded under TODO #33. Remove diagnostics with the fix.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Opus 4.8 committed 2026-06-29 20:22:40 -04:00
1 parent adf0488df8
commit 088a5c797d
3 files changed
+76 -1

No files matched your search

+30 -1
View File
@@ -883,6 +883,13 @@ export class SignerManager {
async scheduleStoredRemoteSignerRestore() {
const stored = readStoredNip46Session();
// [nip46-diag] TEMP (todo #33): trace whether a NIP-46 session is restored on
// load — the "unknown user after refresh" symptom. Remove with the fix.
userLogger.info("[nip46-diag] restore: scheduleStoredRemoteSignerRestore", {
hasStored: !!stored,
storedPubkey: stored?.pubkey || stored?.userPubkey || null,
storedKeys: stored ? Object.keys(stored) : [],
});
if (!stored) {
return;
}
@@ -896,8 +903,15 @@ export class SignerManager {
silent: true,
validator: this.buildAccessControlValidator(),
});
userLogger.info("[nip46-diag] restore: succeeded", {
resolvedPubkey: this.pubkey || null,
});
} catch (err) {
devLogger.warn("Failed to restore remote signer", err);
// Surfaced via userLogger so it's visible on unstable (devLogger is gated).
userLogger.warn("[nip46-diag] restore: FAILED", {
message: err?.message || String(err),
code: err?.code || null,
});
}
};
@@ -905,6 +919,14 @@ export class SignerManager {
}
async disconnectRemoteSigner({ keepStored = false } = {}) {
// [nip46-diag] TEMP (todo #33): the single shared nip46Client is torn down here;
// logout/switch calling this is the suspected "logs out everyone" cause.
userLogger.info("[nip46-diag] disconnectRemoteSigner", {
keepStored,
hadClient: !!this.nip46Client,
pubkey: this.pubkey || null,
stack: new Error().stack?.split("\n").slice(2, 5).join(" <- "),
});
// Abort an in-flight nostrconnect:// handshake wait, if any.
if (typeof this.pendingHandshakeCancel === "function") {
try {
@@ -1016,6 +1038,13 @@ export class SignerManager {
logout() {
const previousPubkey = this.pubkey;
// [nip46-diag] TEMP (todo #33): trace logout scope — which pubkey + whether a
// shared remote-signer client is being torn down (affects other NIP-46 profiles).
userLogger.info("[nip46-diag] logout", {
previousPubkey: previousPubkey || null,
hadRemoteClient: !!this.nip46Client,
sessionActorSource: this.sessionActor?.source || null,
});
this.pubkey = null;
logoutSignerFromRegistry(previousPubkey);
const previousSessionActor = this.sessionActor;
+17
View File
@@ -977,6 +977,12 @@ export default class AuthService {
const providerId = normalizeProviderId(normalizedOptions.providerId);
const normalizedActive = this.normalizeHexPubkey(getActiveProfilePubkey());
// [nip46-diag] TEMP (todo #33): trace profile switching — from/to + provider.
userLogger.info("[nip46-diag] switchProfile: begin", {
from: normalizedActive || null,
to: normalizedTarget,
providerId: providerId || null,
});
if (normalizedActive && normalizedActive === normalizedTarget) {
return { switched: false, reason: "already-active" };
}
@@ -993,6 +999,10 @@ export default class AuthService {
try {
requestResult = await this.requestLogin(requestOptions);
} catch (error) {
userLogger.warn("[nip46-diag] switchProfile: requestLogin FAILED", {
to: normalizedTarget,
message: error?.message || String(error),
});
throw error;
}
@@ -1001,6 +1011,13 @@ export default class AuthService {
(typeof requestResult?.pubkey === "string"
? requestResult.pubkey.trim()
: "");
// [nip46-diag] TEMP (todo #33): did the switch resolve the EXPECTED pubkey?
userLogger.info("[nip46-diag] switchProfile: requestLogin returned", {
to: normalizedTarget,
requestedPubkey: requestedPubkey || null,
matchesTarget: requestedPubkey === normalizedTarget,
hasDetail: !!requestResult?.detail,
});
let detail = requestResult?.detail || null;