last commit before bundling nostr-tools ourselves
This commit is contained in:
@@ -264,7 +264,8 @@ class ExtensionBridge {
|
||||
this.checking = false;
|
||||
this.checkInterval = null;
|
||||
this.originalNostr = null;
|
||||
this.foundExtension = null;
|
||||
this.foundExtensions = new Map(); // Store multiple extensions by location
|
||||
this.primaryExtension = null; // The currently selected extension
|
||||
}
|
||||
|
||||
startChecking(nostrLite) {
|
||||
@@ -272,7 +273,7 @@ class ExtensionBridge {
|
||||
this.checking = true;
|
||||
|
||||
const check = () => {
|
||||
this.initExtension(nostrLite);
|
||||
this.detectAllExtensions(nostrLite);
|
||||
};
|
||||
|
||||
// Check immediately
|
||||
@@ -288,50 +289,170 @@ class ExtensionBridge {
|
||||
}, 30000);
|
||||
}
|
||||
|
||||
initExtension(nostrLite, lastTry = false) {
|
||||
const extension = window.nostr;
|
||||
detectAllExtensions(nostrLite) {
|
||||
// Extension locations to check (in priority order)
|
||||
const locations = [
|
||||
{ path: 'window.navigator?.nostr', name: 'navigator.nostr', getter: () => window.navigator?.nostr },
|
||||
{ path: 'window.webln?.nostr', name: 'webln.nostr', getter: () => window.webln?.nostr },
|
||||
{ path: 'window.alby?.nostr', name: 'alby.nostr', getter: () => window.alby?.nostr },
|
||||
{ path: 'window.nos2x', name: 'nos2x', getter: () => window.nos2x },
|
||||
{ path: 'window.flamingo?.nostr', name: 'flamingo.nostr', getter: () => window.flamingo?.nostr },
|
||||
{ path: 'window.mutiny?.nostr', name: 'mutiny.nostr', getter: () => window.mutiny?.nostr },
|
||||
{ path: 'window.nostrich?.nostr', name: 'nostrich.nostr', getter: () => window.nostrich?.nostr },
|
||||
{ path: 'window.getAlby?.nostr', name: 'getAlby.nostr', getter: () => window.getAlby?.nostr }
|
||||
];
|
||||
|
||||
if (extension && !this.foundExtension) {
|
||||
// Check if this is actually a real extension, not our own library
|
||||
const isRealExtension = (
|
||||
extension !== nostrLite && // Not the same object we're about to assign
|
||||
extension !== windowNostr && // Not our windowNostr object
|
||||
typeof extension._hexToUint8Array !== 'function' && // Our library has this internal method
|
||||
extension.constructor.name !== 'Object' // Real extensions usually have proper constructors
|
||||
let foundNew = false;
|
||||
|
||||
// Check each location
|
||||
for (const location of locations) {
|
||||
try {
|
||||
const obj = location.getter();
|
||||
|
||||
if (obj && this.isRealExtension(obj, nostrLite)) {
|
||||
if (!this.foundExtensions.has(location.name)) {
|
||||
this.foundExtensions.set(location.name, {
|
||||
name: location.name,
|
||||
path: location.path,
|
||||
extension: obj,
|
||||
constructor: obj.constructor?.name || 'Unknown'
|
||||
});
|
||||
console.log(`Real Nostr extension detected: ${location.name} (${obj.constructor?.name})`);
|
||||
foundNew = true;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Location doesn't exist or can't be accessed
|
||||
}
|
||||
}
|
||||
|
||||
// Also check window.nostr but be extra careful to avoid our library
|
||||
if (window.nostr && this.isRealExtension(window.nostr, nostrLite)) {
|
||||
// Make sure we haven't already detected this extension via another path
|
||||
const existingExtension = Array.from(this.foundExtensions.values()).find(
|
||||
ext => ext.extension === window.nostr
|
||||
);
|
||||
|
||||
if (isRealExtension) {
|
||||
this.foundExtension = extension;
|
||||
if (!existingExtension && !this.foundExtensions.has('window.nostr')) {
|
||||
this.foundExtensions.set('window.nostr', {
|
||||
name: 'window.nostr',
|
||||
path: 'window.nostr',
|
||||
extension: window.nostr,
|
||||
constructor: window.nostr.constructor?.name || 'Unknown'
|
||||
});
|
||||
console.log(`Real Nostr extension detected at window.nostr: ${window.nostr.constructor?.name}`);
|
||||
foundNew = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the extension and reassign window.nostr to our lite version
|
||||
this.originalNostr = window.nostr;
|
||||
// Set primary extension if we don't have one and found extensions
|
||||
if (!this.primaryExtension && this.foundExtensions.size > 0) {
|
||||
// Prefer navigator.nostr if available, otherwise use first found
|
||||
this.primaryExtension = this.foundExtensions.get('navigator.nostr') ||
|
||||
Array.from(this.foundExtensions.values())[0];
|
||||
|
||||
// Cache the extension and reassign window.nostr to our lite version
|
||||
this.originalNostr = this.primaryExtension.extension;
|
||||
if (window.nostr !== nostrLite) {
|
||||
window.nostr = nostrLite;
|
||||
}
|
||||
|
||||
console.log('Real Nostr extension detected and bridged:', extension.constructor.name);
|
||||
console.log(`Primary extension set: ${this.primaryExtension.name}`);
|
||||
|
||||
// If currently authenticated, reconcile state
|
||||
if (LiteState.auth?.signer?.method === 'extension') {
|
||||
this.reconcileExtension();
|
||||
}
|
||||
} else {
|
||||
console.log('Skipping non-extension object on window.nostr:', extension.constructor.name);
|
||||
// If currently authenticated, reconcile state
|
||||
if (LiteState.auth?.signer?.method === 'extension') {
|
||||
this.reconcileExtension();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isRealExtension(obj, nostrLite) {
|
||||
if (!obj || typeof obj !== 'object') return false;
|
||||
|
||||
// Must have required Nostr methods
|
||||
if (typeof obj.getPublicKey !== 'function' || typeof obj.signEvent !== 'function') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exclude our own library objects
|
||||
if (obj === nostrLite || obj === windowNostr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exclude objects with our library's internal methods
|
||||
if (typeof obj._hexToUint8Array === 'function' || typeof obj._call === 'function') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exclude NostrTools library object
|
||||
if (obj === window.NostrTools) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Real extensions typically have proper constructors (not plain Object)
|
||||
const constructorName = obj.constructor?.name;
|
||||
if (constructorName === 'Object' && !obj._isEnabled && !obj.enabled) {
|
||||
// Plain objects without extension-specific properties are likely our library
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
getAllExtensions() {
|
||||
return Array.from(this.foundExtensions.values());
|
||||
}
|
||||
|
||||
getExtensionCount() {
|
||||
return this.foundExtensions.size;
|
||||
}
|
||||
|
||||
hasExtension() {
|
||||
return !!this.foundExtension;
|
||||
return this.foundExtensions.size > 0;
|
||||
}
|
||||
|
||||
// Legacy compatibility - return primary extension
|
||||
get foundExtension() {
|
||||
return this.primaryExtension?.extension || null;
|
||||
}
|
||||
|
||||
// Method to properly set primary extension
|
||||
setPrimaryExtension(extension, name = 'selected') {
|
||||
// Find the extension in our map or create new entry
|
||||
let extensionInfo = null;
|
||||
|
||||
// Check if this extension is already in our map
|
||||
for (const [key, info] of this.foundExtensions) {
|
||||
if (info.extension === extension) {
|
||||
extensionInfo = info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, create a new entry
|
||||
if (!extensionInfo) {
|
||||
extensionInfo = {
|
||||
name: name,
|
||||
path: name,
|
||||
extension: extension,
|
||||
constructor: extension?.constructor?.name || 'Unknown'
|
||||
};
|
||||
this.foundExtensions.set(name, extensionInfo);
|
||||
}
|
||||
|
||||
this.primaryExtension = extensionInfo;
|
||||
console.log(`Primary extension set to: ${extensionInfo.name}`);
|
||||
}
|
||||
|
||||
async setExtensionReadPubkey(expectedPubkey = null) {
|
||||
if (!this.foundExtension) return false;
|
||||
if (!this.primaryExtension) return false;
|
||||
|
||||
try {
|
||||
// Temporarily set window.nostr to extension
|
||||
const temp = window.nostr;
|
||||
window.nostr = this.foundExtension;
|
||||
window.nostr = this.primaryExtension.extension;
|
||||
|
||||
const pubkey = await this.foundExtension.getPublicKey();
|
||||
const pubkey = await this.primaryExtension.extension.getPublicKey();
|
||||
|
||||
// Restore our lite implementation
|
||||
window.nostr = temp;
|
||||
@@ -360,8 +481,8 @@ class ExtensionBridge {
|
||||
}
|
||||
|
||||
setExtension() {
|
||||
if (!this.foundExtension) return;
|
||||
window.nostr = this.foundExtension;
|
||||
if (!this.primaryExtension) return;
|
||||
window.nostr = this.primaryExtension.extension;
|
||||
this.setExtensionReadPubkey().then(pubkey => {
|
||||
if (pubkey) {
|
||||
LiteState.bus?.emit('extensionSet', { pubkey });
|
||||
@@ -457,7 +578,7 @@ class NostrLite {
|
||||
// Handle extension detection
|
||||
this.bus?.on('extensionDetected', (extension) => {
|
||||
console.log('Extension detected');
|
||||
LiteState.extensionBridge.foundExtension = extension;
|
||||
LiteState.extensionBridge.setPrimaryExtension(extension, 'detected');
|
||||
});
|
||||
|
||||
// Handle auth URL from NIP-46
|
||||
@@ -495,7 +616,7 @@ class NostrLite {
|
||||
case 'extension':
|
||||
if (pubkey && extension) {
|
||||
// Store the extension object in the ExtensionBridge for future use
|
||||
LiteState.extensionBridge.foundExtension = extension;
|
||||
LiteState.extensionBridge.setPrimaryExtension(extension, 'modal-selected');
|
||||
LiteState.extensionBridge.originalNostr = extension;
|
||||
|
||||
// Set up extension authentication
|
||||
|
||||
Reference in New Issue
Block a user