mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
feat: show provider metadata in saved profiles
This commit is contained in:
1 parent
3532c212f3
commit
6d84d6be4e
8 files changed
+362
-29
No files matched your search
@@ -2085,6 +2085,20 @@ class Application {
|
||||
return "nip07";
|
||||
})();
|
||||
|
||||
const resolvedProviderId = (() => {
|
||||
const candidates = [detailProviderId, providerId, resolvedAuthType];
|
||||
for (const candidate of candidates) {
|
||||
if (typeof candidate !== "string") {
|
||||
continue;
|
||||
}
|
||||
const trimmed = candidate.trim();
|
||||
if (trimmed) {
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
return resolvedAuthType;
|
||||
})();
|
||||
|
||||
const normalizedPubkey = this.normalizeHexPubkey(pubkey);
|
||||
if (!normalizedPubkey) {
|
||||
throw new Error(
|
||||
@@ -2119,6 +2133,7 @@ class Application {
|
||||
name,
|
||||
picture,
|
||||
authType: resolvedAuthType,
|
||||
providerId: resolvedProviderId,
|
||||
});
|
||||
|
||||
persistSavedProfiles({ persistActive: false });
|
||||
@@ -2955,12 +2970,12 @@ class Application {
|
||||
}
|
||||
}
|
||||
|
||||
async handleProfileSwitchRequest({ pubkey } = {}) {
|
||||
async handleProfileSwitchRequest({ pubkey, providerId } = {}) {
|
||||
if (!pubkey) {
|
||||
throw new Error("Missing pubkey for profile switch request.");
|
||||
}
|
||||
|
||||
const result = await this.authService.switchProfile(pubkey);
|
||||
const result = await this.authService.switchProfile(pubkey, { providerId });
|
||||
|
||||
if (result?.switched) {
|
||||
try {
|
||||
|
||||
@@ -1,14 +1,129 @@
|
||||
import nip07 from "./nip07.js";
|
||||
|
||||
const map = {
|
||||
[(nip07 && typeof nip07.id === "string" && nip07.id.trim()) || "nip07"]: nip07,
|
||||
};
|
||||
function normalizeProviderId(provider, fallbackId) {
|
||||
if (provider && typeof provider.id === "string") {
|
||||
const trimmed = provider.id.trim();
|
||||
if (trimmed) {
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Object.prototype.hasOwnProperty.call(map, "nip07")) {
|
||||
map.nip07 = nip07;
|
||||
if (typeof fallbackId === "string") {
|
||||
const trimmed = fallbackId.trim();
|
||||
if (trimmed) {
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
|
||||
return "provider";
|
||||
}
|
||||
|
||||
export const providers = Object.freeze({ ...map });
|
||||
function normalizeProviderMetadata(provider, fallbackId) {
|
||||
const id = normalizeProviderId(provider, fallbackId);
|
||||
const label =
|
||||
provider && typeof provider.label === "string" && provider.label.trim()
|
||||
? provider.label.trim()
|
||||
: "Saved profile";
|
||||
const description =
|
||||
provider && typeof provider.description === "string" && provider.description.trim()
|
||||
? provider.description.trim()
|
||||
: "";
|
||||
const badgeVariant =
|
||||
provider && typeof provider.badgeVariant === "string" && provider.badgeVariant.trim()
|
||||
? provider.badgeVariant.trim()
|
||||
: "neutral";
|
||||
|
||||
return Object.freeze({ id, label, description, badgeVariant });
|
||||
}
|
||||
|
||||
const providerList = [nip07].filter(Boolean);
|
||||
const providerMap = {};
|
||||
const metadataMap = {};
|
||||
|
||||
providerList.forEach((provider, index) => {
|
||||
const fallbackId = `provider-${index}`;
|
||||
const id = normalizeProviderId(provider, fallbackId);
|
||||
providerMap[id] = provider;
|
||||
metadataMap[id] = normalizeProviderMetadata(provider, id);
|
||||
});
|
||||
|
||||
if (!Object.prototype.hasOwnProperty.call(providerMap, "nip07")) {
|
||||
providerMap.nip07 = nip07;
|
||||
metadataMap.nip07 = normalizeProviderMetadata(nip07, "nip07");
|
||||
} else if (!Object.prototype.hasOwnProperty.call(metadataMap, "nip07")) {
|
||||
metadataMap.nip07 = normalizeProviderMetadata(providerMap.nip07, "nip07");
|
||||
}
|
||||
|
||||
const builtInMetadata = [
|
||||
{
|
||||
id: "nsec",
|
||||
label: "Direct key",
|
||||
description: "Use a saved nsec key stored locally.",
|
||||
badgeVariant: "warning",
|
||||
},
|
||||
];
|
||||
|
||||
builtInMetadata.forEach((entry) => {
|
||||
if (!entry || typeof entry !== "object") {
|
||||
return;
|
||||
}
|
||||
|
||||
const id =
|
||||
typeof entry.id === "string" && entry.id.trim() ? entry.id.trim() : null;
|
||||
if (!id || Object.prototype.hasOwnProperty.call(metadataMap, id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
metadataMap[id] = Object.freeze({
|
||||
id,
|
||||
label:
|
||||
typeof entry.label === "string" && entry.label.trim()
|
||||
? entry.label.trim()
|
||||
: "Saved profile",
|
||||
description:
|
||||
typeof entry.description === "string" && entry.description.trim()
|
||||
? entry.description.trim()
|
||||
: "",
|
||||
badgeVariant:
|
||||
typeof entry.badgeVariant === "string" && entry.badgeVariant.trim()
|
||||
? entry.badgeVariant.trim()
|
||||
: "neutral",
|
||||
});
|
||||
});
|
||||
|
||||
export const providers = Object.freeze({ ...providerMap });
|
||||
export const providerMetadata = Object.freeze({ ...metadataMap });
|
||||
|
||||
const unknownMetadataCache = new Map();
|
||||
|
||||
function getFallbackMetadata(providerId) {
|
||||
const id =
|
||||
typeof providerId === "string" && providerId.trim() ? providerId.trim() : "unknown";
|
||||
if (!unknownMetadataCache.has(id)) {
|
||||
unknownMetadataCache.set(
|
||||
id,
|
||||
Object.freeze({
|
||||
id,
|
||||
label: "Saved profile",
|
||||
description: "",
|
||||
badgeVariant: "neutral",
|
||||
}),
|
||||
);
|
||||
}
|
||||
return unknownMetadataCache.get(id);
|
||||
}
|
||||
|
||||
export function getProviderMetadata(providerId) {
|
||||
if (typeof providerId === "string" && providerId.trim()) {
|
||||
const normalizedId = providerId.trim();
|
||||
if (Object.prototype.hasOwnProperty.call(providerMetadata, normalizedId)) {
|
||||
return providerMetadata[normalizedId];
|
||||
}
|
||||
return getFallbackMetadata(normalizedId);
|
||||
}
|
||||
|
||||
return getFallbackMetadata("saved-profile");
|
||||
}
|
||||
|
||||
export function getProvider(providerId = "nip07") {
|
||||
const id =
|
||||
|
||||
@@ -47,6 +47,7 @@ export default {
|
||||
id: PROVIDER_ID,
|
||||
label: PROVIDER_LABEL,
|
||||
description: PROVIDER_DESCRIPTION,
|
||||
badgeVariant: "info",
|
||||
capabilities: PROVIDER_CAPABILITIES,
|
||||
button: PROVIDER_BUTTON,
|
||||
messages: PROVIDER_MESSAGES,
|
||||
|
||||
@@ -521,6 +521,8 @@ export default class AuthService {
|
||||
providerResult,
|
||||
);
|
||||
|
||||
const entryProviderId = this.normalizeProviderId(providerId) || entryAuthType;
|
||||
|
||||
mutateSavedProfiles((profiles) => {
|
||||
const draft = Array.isArray(profiles) ? profiles.slice() : [];
|
||||
const existingIndex = draft.findIndex((entry) => {
|
||||
@@ -537,6 +539,7 @@ export default class AuthService {
|
||||
name: cachedProfile.name || draft[existingIndex]?.name || "",
|
||||
picture: cachedProfile.picture || draft[existingIndex]?.picture || "",
|
||||
authType: entryAuthType,
|
||||
providerId: entryProviderId,
|
||||
};
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
@@ -545,7 +548,8 @@ export default class AuthService {
|
||||
currentEntry.npub !== nextEntry.npub ||
|
||||
currentEntry.name !== nextEntry.name ||
|
||||
currentEntry.picture !== nextEntry.picture ||
|
||||
currentEntry.authType !== nextEntry.authType;
|
||||
currentEntry.authType !== nextEntry.authType ||
|
||||
currentEntry.providerId !== nextEntry.providerId;
|
||||
if (changed) {
|
||||
draft[existingIndex] = nextEntry;
|
||||
savedProfilesMutated = true;
|
||||
@@ -791,12 +795,16 @@ export default class AuthService {
|
||||
return { removed: changed };
|
||||
}
|
||||
|
||||
async switchProfile(pubkey) {
|
||||
async switchProfile(pubkey, options = {}) {
|
||||
const normalizedTarget = this.normalizeHexPubkey(pubkey);
|
||||
if (!normalizedTarget) {
|
||||
throw new Error("Unable to switch profiles: invalid account.");
|
||||
}
|
||||
|
||||
const normalizedOptions =
|
||||
options && typeof options === "object" ? { ...options } : {};
|
||||
const providerId = this.normalizeProviderId(normalizedOptions.providerId);
|
||||
|
||||
const normalizedActive = this.normalizeHexPubkey(getActiveProfilePubkey());
|
||||
if (normalizedActive && normalizedActive === normalizedTarget) {
|
||||
return { switched: false, reason: "already-active" };
|
||||
@@ -806,6 +814,7 @@ export default class AuthService {
|
||||
allowAccountSelection: true,
|
||||
expectPubkey: normalizedTarget,
|
||||
persistActive: true,
|
||||
...(providerId ? { providerId } : {}),
|
||||
};
|
||||
const autoApply = requestOptions.autoApply !== false;
|
||||
|
||||
@@ -827,7 +836,10 @@ export default class AuthService {
|
||||
if (!detail && !autoApply) {
|
||||
const fallbackTarget =
|
||||
this.normalizeHexPubkey(requestedPubkey) || requestedPubkey || normalizedTarget;
|
||||
detail = await this.login(fallbackTarget, { persistActive: true });
|
||||
detail = await this.login(fallbackTarget, {
|
||||
persistActive: true,
|
||||
providerId,
|
||||
});
|
||||
}
|
||||
|
||||
mutateSavedProfiles((profiles) => {
|
||||
|
||||
@@ -364,6 +364,10 @@ export function persistSavedProfiles({ persistActive = true } = {}) {
|
||||
typeof entry.authType === "string" && entry.authType.trim()
|
||||
? entry.authType.trim()
|
||||
: null,
|
||||
providerId:
|
||||
typeof entry.providerId === "string" && entry.providerId.trim()
|
||||
? entry.providerId.trim()
|
||||
: null,
|
||||
})),
|
||||
activePubkey: activePubkeyToPersist,
|
||||
};
|
||||
@@ -430,6 +434,24 @@ export function loadSavedProfilesFromStorage() {
|
||||
needsRewrite = true;
|
||||
}
|
||||
}
|
||||
const rawProviderId =
|
||||
typeof candidate.providerId === "string" ? candidate.providerId : null;
|
||||
let storedProviderId = null;
|
||||
if (rawProviderId) {
|
||||
const trimmedProviderId = rawProviderId.trim();
|
||||
if (trimmedProviderId) {
|
||||
storedProviderId = trimmedProviderId;
|
||||
if (trimmedProviderId !== rawProviderId) {
|
||||
needsRewrite = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!storedProviderId && storedAuthType) {
|
||||
storedProviderId = storedAuthType;
|
||||
if (rawProviderId !== storedProviderId) {
|
||||
needsRewrite = true;
|
||||
}
|
||||
}
|
||||
const npub =
|
||||
typeof candidate.npub === "string" && candidate.npub.trim()
|
||||
? candidate.npub.trim()
|
||||
@@ -441,6 +463,7 @@ export function loadSavedProfilesFromStorage() {
|
||||
name: typeof candidate.name === "string" ? candidate.name : "",
|
||||
picture: typeof candidate.picture === "string" ? candidate.picture : "",
|
||||
authType: storedAuthType,
|
||||
providerId: storedProviderId,
|
||||
};
|
||||
|
||||
if (
|
||||
|
||||
+115
-18
@@ -11,6 +11,7 @@ import {
|
||||
getTrustedSpamHideThreshold,
|
||||
RUNTIME_FLAGS,
|
||||
} from "../constants.js";
|
||||
import { getProviderMetadata } from "../services/authProviders/index.js";
|
||||
import { devLogger, userLogger } from "../utils/logger.js";
|
||||
|
||||
const noop = () => {};
|
||||
@@ -21,6 +22,30 @@ const DEFAULT_ADMIN_DM_IMAGE_URL =
|
||||
const DEFAULT_BITVID_WEBSITE_URL = "https://bitvid.network/";
|
||||
const NWC_URI_SCHEME = "nostr+walletconnect://";
|
||||
const DEFAULT_MAX_WALLET_DEFAULT_ZAP = 100000000;
|
||||
const DEFAULT_SAVED_PROFILE_LABEL = "Saved profile";
|
||||
|
||||
const PROVIDER_BADGE_BASE_CLASS =
|
||||
"text-3xs font-semibold uppercase tracking-extra-wide";
|
||||
const PROVIDER_BADGE_VARIANT_CLASS_MAP = Object.freeze({
|
||||
info: "text-status-info",
|
||||
success: "text-status-success",
|
||||
warning: "text-status-warning",
|
||||
danger: "text-status-danger",
|
||||
neutral: "text-muted",
|
||||
accent: "text-accent",
|
||||
primary: "text-accent",
|
||||
});
|
||||
|
||||
function resolveProviderBadgeClass(variant) {
|
||||
if (typeof variant === "string" && variant.trim()) {
|
||||
const normalized = variant.trim().toLowerCase();
|
||||
if (Object.prototype.hasOwnProperty.call(PROVIDER_BADGE_VARIANT_CLASS_MAP, normalized)) {
|
||||
return PROVIDER_BADGE_VARIANT_CLASS_MAP[normalized];
|
||||
}
|
||||
}
|
||||
|
||||
return PROVIDER_BADGE_VARIANT_CLASS_MAP.neutral;
|
||||
}
|
||||
|
||||
const DEFAULT_INTERNAL_NWC_SETTINGS = Object.freeze({
|
||||
nwcUri: "",
|
||||
@@ -1419,8 +1444,8 @@ export class ProfileModalController {
|
||||
? (value) => this.formatShortNpub(value)
|
||||
: (value) => (typeof value === "string" ? value : "");
|
||||
const activeNameFallback = activeMeta?.npub
|
||||
? formatNpub(activeMeta.npub) || "Saved profile"
|
||||
: "Saved profile";
|
||||
? formatNpub(activeMeta.npub) || DEFAULT_SAVED_PROFILE_LABEL
|
||||
: DEFAULT_SAVED_PROFILE_LABEL;
|
||||
const activeDisplayName = hasActiveProfile
|
||||
? activeMeta?.name?.trim() || activeNameFallback
|
||||
: "No active profile";
|
||||
@@ -1545,7 +1570,9 @@ export class ProfileModalController {
|
||||
avatarImg.src = meta.picture || FALLBACK_PROFILE_AVATAR;
|
||||
const cardDisplayName =
|
||||
meta.name?.trim() ||
|
||||
(meta.npub ? formatNpub(meta.npub) || "Saved profile" : "Saved profile");
|
||||
(meta.npub
|
||||
? formatNpub(meta.npub) || DEFAULT_SAVED_PROFILE_LABEL
|
||||
: DEFAULT_SAVED_PROFILE_LABEL);
|
||||
avatarImg.alt = `${cardDisplayName} avatar`;
|
||||
avatarSpan.appendChild(avatarImg);
|
||||
|
||||
@@ -1555,11 +1582,24 @@ export class ProfileModalController {
|
||||
const topLine = document.createElement("div");
|
||||
topLine.className = "flex flex-wrap items-center gap-3";
|
||||
|
||||
const providerId = this.getEntryProviderId(entry);
|
||||
const providerInfo = this.resolveEntryProviderMetadata(entry);
|
||||
const providerLabel =
|
||||
(providerInfo && providerInfo.label) || DEFAULT_SAVED_PROFILE_LABEL;
|
||||
const badgeVariant = resolveProviderBadgeClass(
|
||||
providerInfo && providerInfo.badgeVariant,
|
||||
);
|
||||
|
||||
const label = document.createElement("span");
|
||||
label.className =
|
||||
"text-3xs font-semibold uppercase tracking-extra-wide text-status-info";
|
||||
label.textContent =
|
||||
normalizedAuthType === "nsec" ? "Direct key" : "Saved profile";
|
||||
label.className = `${PROVIDER_BADGE_BASE_CLASS} ${badgeVariant}`;
|
||||
label.textContent = providerLabel;
|
||||
label.dataset.providerVariant =
|
||||
(providerInfo && providerInfo.badgeVariant) || "neutral";
|
||||
if (providerId) {
|
||||
label.dataset.providerId = providerId;
|
||||
} else if (providerInfo && providerInfo.id) {
|
||||
label.dataset.providerId = providerInfo.id;
|
||||
}
|
||||
|
||||
const action = document.createElement("span");
|
||||
action.className = "text-xs font-medium text-muted";
|
||||
@@ -1589,6 +1629,15 @@ export class ProfileModalController {
|
||||
: `Switch to ${cardDisplayName}`;
|
||||
button.setAttribute("aria-label", ariaLabel);
|
||||
|
||||
const datasetProviderId =
|
||||
providerId || (providerInfo && providerInfo.id) || "";
|
||||
|
||||
if (datasetProviderId) {
|
||||
button.dataset.providerId = datasetProviderId;
|
||||
} else {
|
||||
delete button.dataset.providerId;
|
||||
}
|
||||
|
||||
const activateProfile = async (event) => {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
@@ -1602,13 +1651,22 @@ export class ProfileModalController {
|
||||
button.dataset.loading = "true";
|
||||
button.setAttribute("aria-busy", "true");
|
||||
|
||||
try {
|
||||
await this.switchProfile(entry.pubkey, { entry });
|
||||
} catch (error) {
|
||||
userLogger.error("Failed to switch profile:", error);
|
||||
} finally {
|
||||
button.dataset.loading = "false";
|
||||
button.setAttribute("aria-busy", "false");
|
||||
const logProviderId =
|
||||
providerId || (providerInfo && providerInfo.id) || normalizedAuthType || "unknown";
|
||||
|
||||
try {
|
||||
await this.switchProfile(entry.pubkey, {
|
||||
entry,
|
||||
providerId: providerId || null,
|
||||
});
|
||||
} catch (error) {
|
||||
userLogger.error(
|
||||
`[ProfileModalController] Failed to switch profile for provider ${logProviderId}:`,
|
||||
error,
|
||||
);
|
||||
} finally {
|
||||
button.dataset.loading = "false";
|
||||
button.setAttribute("aria-busy", "false");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4708,16 +4766,20 @@ export class ProfileModalController {
|
||||
);
|
||||
}
|
||||
|
||||
async requestSwitchProfile({ pubkey, entry } = {}) {
|
||||
async requestSwitchProfile({ pubkey, entry, providerId } = {}) {
|
||||
const callback = this.callbacks.onRequestSwitchProfile;
|
||||
if (callback && callback !== noop) {
|
||||
return callback({ controller: this, pubkey, entry });
|
||||
return callback({ controller: this, pubkey, entry, providerId });
|
||||
}
|
||||
|
||||
if (!pubkey) {
|
||||
throw new Error("Missing target pubkey for switch request.");
|
||||
}
|
||||
|
||||
if (providerId) {
|
||||
return this.services.switchProfile(pubkey, { providerId });
|
||||
}
|
||||
|
||||
return this.services.switchProfile(pubkey);
|
||||
}
|
||||
|
||||
@@ -5618,14 +5680,14 @@ export class ProfileModalController {
|
||||
}
|
||||
}
|
||||
|
||||
async switchProfile(pubkey, { entry } = {}) {
|
||||
async switchProfile(pubkey, { entry, providerId } = {}) {
|
||||
if (!pubkey) {
|
||||
return { switched: false, reason: "missing-pubkey" };
|
||||
}
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = await this.requestSwitchProfile({ pubkey, entry });
|
||||
result = await this.requestSwitchProfile({ pubkey, entry, providerId });
|
||||
} catch (error) {
|
||||
const message =
|
||||
error && typeof error.message === "string" && error.message.trim()
|
||||
@@ -5661,6 +5723,41 @@ export class ProfileModalController {
|
||||
return this.state.setSavedProfiles(...args);
|
||||
}
|
||||
|
||||
normalizeProviderId(providerId) {
|
||||
if (typeof providerId !== "string") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const trimmed = providerId.trim();
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
getEntryProviderId(entry) {
|
||||
if (!entry || typeof entry !== "object") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const explicit = this.normalizeProviderId(entry.providerId);
|
||||
if (explicit) {
|
||||
return explicit;
|
||||
}
|
||||
|
||||
return this.normalizeProviderId(entry.authType);
|
||||
}
|
||||
|
||||
resolveEntryProviderMetadata(entry) {
|
||||
const providerId = this.getEntryProviderId(entry);
|
||||
if (providerId) {
|
||||
return getProviderMetadata(providerId);
|
||||
}
|
||||
|
||||
return getProviderMetadata();
|
||||
}
|
||||
|
||||
persistSavedProfiles(...args) {
|
||||
if (typeof this.services.persistSavedProfiles === "function") {
|
||||
try {
|
||||
|
||||
@@ -440,12 +440,16 @@ for (const _ of [0]) {
|
||||
npub: 'npub1abcdefghijkmnopqrstuvwxyz1234567890example',
|
||||
name: '',
|
||||
picture: '',
|
||||
providerId: 'nip07',
|
||||
authType: 'nip07',
|
||||
},
|
||||
{
|
||||
pubkey: 'b'.repeat(64),
|
||||
npub: 'npub1zyxwvutsrqponmlkjihgfedcba1234567890sample',
|
||||
name: '',
|
||||
picture: '',
|
||||
providerId: 'nsec',
|
||||
authType: 'nsec',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -470,6 +474,62 @@ for (const _ of [0]) {
|
||||
const expectedSwitcher = formatShortNpub(sampleProfiles[1].npub);
|
||||
assert.equal(switcherNpubEl.textContent, expectedSwitcher);
|
||||
});
|
||||
|
||||
test('renderSavedProfiles applies provider metadata', async () => {
|
||||
const sampleProfiles = [
|
||||
{
|
||||
pubkey: defaultActorHex,
|
||||
npub: 'npub1abcdefghijkmnopqrstuvwxyz1234567890example',
|
||||
name: 'Primary Account',
|
||||
picture: '',
|
||||
providerId: 'nip07',
|
||||
authType: 'nip07',
|
||||
},
|
||||
{
|
||||
pubkey: 'b'.repeat(64),
|
||||
npub: 'npub1zyxwvutsrqponmlkjihgfedcba1234567890sample',
|
||||
name: 'Backup',
|
||||
picture: '',
|
||||
providerId: 'nsec',
|
||||
authType: 'nsec',
|
||||
},
|
||||
];
|
||||
|
||||
const controller = createController({
|
||||
services: {
|
||||
formatShortNpub,
|
||||
},
|
||||
});
|
||||
|
||||
await controller.load();
|
||||
|
||||
controller.state.setSavedProfiles(sampleProfiles);
|
||||
controller.state.setActivePubkey(null);
|
||||
|
||||
controller.renderSavedProfiles();
|
||||
|
||||
const buttons = Array.from(
|
||||
controller.switcherList.querySelectorAll('button[data-provider-id]'),
|
||||
);
|
||||
|
||||
assert.equal(buttons.length, 2, 'expected two provider entries in the switcher');
|
||||
|
||||
const [extensionButton, directKeyButton] = buttons;
|
||||
|
||||
assert.equal(extensionButton.dataset.providerId, 'nip07');
|
||||
const extensionLabel = extensionButton.querySelector('[data-provider-variant]');
|
||||
assert.ok(extensionLabel, 'extension entry should include a provider badge');
|
||||
assert.equal(extensionLabel.textContent, 'Login with Extension');
|
||||
assert.equal(extensionLabel.dataset.providerVariant, 'info');
|
||||
assert.equal(extensionButton.getAttribute('aria-pressed'), 'false');
|
||||
|
||||
assert.equal(directKeyButton.dataset.providerId, 'nsec');
|
||||
const directKeyLabel = directKeyButton.querySelector('[data-provider-variant]');
|
||||
assert.ok(directKeyLabel, 'direct key entry should include a provider badge');
|
||||
assert.equal(directKeyLabel.textContent, 'Direct key');
|
||||
assert.equal(directKeyLabel.dataset.providerVariant, 'warning');
|
||||
assert.equal(directKeyButton.getAttribute('aria-pressed'), 'false');
|
||||
});
|
||||
}
|
||||
|
||||
test('load() injects markup and caches expected elements', async () => {
|
||||
|
||||
@@ -42,6 +42,7 @@ test("persistSavedProfiles preserves custom authType strings", () => {
|
||||
name: "",
|
||||
picture: "",
|
||||
authType: "custom-wallet",
|
||||
providerId: "custom-wallet",
|
||||
},
|
||||
],
|
||||
{ persist: false, persistActive: false },
|
||||
@@ -55,6 +56,7 @@ test("persistSavedProfiles preserves custom authType strings", () => {
|
||||
const stored = JSON.parse(storedRaw);
|
||||
assert.equal(stored.entries.length, 1);
|
||||
assert.equal(stored.entries[0].authType, "custom-wallet");
|
||||
assert.equal(stored.entries[0].providerId, "custom-wallet");
|
||||
});
|
||||
|
||||
test("loadSavedProfilesFromStorage retains custom provider authType", () => {
|
||||
@@ -71,6 +73,7 @@ test("loadSavedProfilesFromStorage retains custom provider authType", () => {
|
||||
name: "",
|
||||
picture: "",
|
||||
authType: "nostr-wallet-connect",
|
||||
providerId: "nostr-wallet-connect",
|
||||
},
|
||||
],
|
||||
activePubkey: null,
|
||||
@@ -80,9 +83,11 @@ test("loadSavedProfilesFromStorage retains custom provider authType", () => {
|
||||
const { profiles } = loadSavedProfilesFromStorage();
|
||||
assert.equal(profiles.length, 1);
|
||||
assert.equal(profiles[0].authType, "nostr-wallet-connect");
|
||||
assert.equal(profiles[0].providerId, "nostr-wallet-connect");
|
||||
|
||||
const stored = JSON.parse(localStorage.getItem(STORAGE_KEY));
|
||||
assert.equal(stored.entries[0].authType, "nostr-wallet-connect");
|
||||
assert.equal(stored.entries[0].providerId, "nostr-wallet-connect");
|
||||
});
|
||||
|
||||
test("loadSavedProfilesFromStorage migrates missing authType to nip07", () => {
|
||||
@@ -107,9 +112,11 @@ test("loadSavedProfilesFromStorage migrates missing authType to nip07", () => {
|
||||
const { profiles } = loadSavedProfilesFromStorage();
|
||||
assert.equal(profiles.length, 1);
|
||||
assert.equal(profiles[0].authType, "nip07");
|
||||
assert.equal(profiles[0].providerId, "nip07");
|
||||
|
||||
const stored = JSON.parse(localStorage.getItem(STORAGE_KEY));
|
||||
assert.equal(stored.entries[0].authType, "nip07");
|
||||
assert.equal(stored.entries[0].providerId, "nip07");
|
||||
});
|
||||
|
||||
test("loadSavedProfilesFromStorage trims stored authType values", () => {
|
||||
@@ -126,6 +133,7 @@ test("loadSavedProfilesFromStorage trims stored authType values", () => {
|
||||
name: "",
|
||||
picture: "",
|
||||
authType: " extension-provider ",
|
||||
providerId: " extension-provider ",
|
||||
},
|
||||
],
|
||||
activePubkey: null,
|
||||
@@ -135,7 +143,9 @@ test("loadSavedProfilesFromStorage trims stored authType values", () => {
|
||||
const { profiles } = loadSavedProfilesFromStorage();
|
||||
assert.equal(profiles.length, 1);
|
||||
assert.equal(profiles[0].authType, "extension-provider");
|
||||
assert.equal(profiles[0].providerId, "extension-provider");
|
||||
|
||||
const stored = JSON.parse(localStorage.getItem(STORAGE_KEY));
|
||||
assert.equal(stored.entries[0].authType, "extension-provider");
|
||||
assert.equal(stored.entries[0].providerId, "extension-provider");
|
||||
});
|
||||
Reference in new issue
Block a user