mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Merge pull request #2263 from PR0M3TH3AN/refactor-client-incremental-fetch-10947149003245285900
refactor: Integrate RelayBatchFetcher into NostrClient
This commit is contained in:
6 files changed
+150
-16
No files matched your search
+68
-2
@@ -214,7 +214,13 @@ import { queueSignEvent } from "./signRequestQueue.js";
|
||||
import { EventsMap } from "./eventsMap.js";
|
||||
import { PersistenceManager } from "./managers/PersistenceManager.js";
|
||||
import { ConnectionManager } from "./managers/ConnectionManager.js";
|
||||
import { SignerManager } from "./managers/SignerManager.js";
|
||||
import {
|
||||
SignerManager,
|
||||
resolveSignerCapabilities,
|
||||
hydrateExtensionSignerCapabilities,
|
||||
attachNipMethodAliases,
|
||||
} from "./managers/SignerManager.js";
|
||||
import { RelayBatchFetcher } from "./relayBatchFetcher.js";
|
||||
|
||||
function normalizeProfileFromEvent(event) {
|
||||
if (!event || !event.content) return null;
|
||||
@@ -230,10 +236,31 @@ function normalizeProfileFromEvent(event) {
|
||||
// We keep them as pass-throughs to the registry or utility logic where appropriate.
|
||||
|
||||
function resolveActiveSigner(pubkey) {
|
||||
return resolveActiveSignerFromRegistry(pubkey);
|
||||
const signer = resolveActiveSignerFromRegistry(pubkey);
|
||||
if (signer) {
|
||||
hydrateExtensionSignerCapabilities(signer);
|
||||
attachNipMethodAliases(signer);
|
||||
if (!signer.capabilities && resolveSignerCapabilities) {
|
||||
const capsDescriptor = Object.getOwnPropertyDescriptor(signer, "capabilities");
|
||||
if (!capsDescriptor || typeof capsDescriptor.get !== "function") {
|
||||
signer.capabilities = resolveSignerCapabilities(signer);
|
||||
}
|
||||
}
|
||||
}
|
||||
return signer;
|
||||
}
|
||||
|
||||
function setActiveSigner(signer) {
|
||||
if (signer) {
|
||||
hydrateExtensionSignerCapabilities(signer);
|
||||
attachNipMethodAliases(signer);
|
||||
if (!signer.capabilities && resolveSignerCapabilities) {
|
||||
const capsDescriptor = Object.getOwnPropertyDescriptor(signer, "capabilities");
|
||||
if (!capsDescriptor || typeof capsDescriptor.get !== "function") {
|
||||
signer.capabilities = resolveSignerCapabilities(signer);
|
||||
}
|
||||
}
|
||||
}
|
||||
setActiveSignerInRegistry(signer);
|
||||
}
|
||||
|
||||
@@ -580,6 +607,7 @@ export class NostrClient {
|
||||
constructor() {
|
||||
this.connectionManager = new ConnectionManager(this);
|
||||
this.signerManager = new SignerManager(this);
|
||||
this.relayBatchFetcher = new RelayBatchFetcher(this);
|
||||
|
||||
/**
|
||||
* @type {Map<string, object>}
|
||||
@@ -752,6 +780,8 @@ export class NostrClient {
|
||||
get sessionActorCipherClosuresPrivateKey() { return this.signerManager.sessionActorCipherClosuresPrivateKey; }
|
||||
set sessionActorCipherClosuresPrivateKey(val) { this.signerManager.sessionActorCipherClosuresPrivateKey = val; }
|
||||
|
||||
get extensionPermissionCache() { return this.signerManager.extensionPermissionCache; }
|
||||
|
||||
get pool() { return this.connectionManager.pool; }
|
||||
set pool(val) { this.connectionManager.pool = val; }
|
||||
|
||||
@@ -892,6 +922,23 @@ export class NostrClient {
|
||||
}
|
||||
}
|
||||
|
||||
resolveEventDTag(event, fallbackEvent = null) {
|
||||
if (!event || typeof event !== "object") {
|
||||
if (fallbackEvent) {
|
||||
return this.resolveEventDTag(fallbackEvent);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
const val = getDTagValueFromTags(event.tags);
|
||||
if (val) {
|
||||
return val;
|
||||
}
|
||||
if (fallbackEvent) {
|
||||
return this.resolveEventDTag(fallbackEvent);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
getActiveKey(video) {
|
||||
return getActiveKey(video);
|
||||
}
|
||||
@@ -2911,6 +2958,21 @@ export class NostrClient {
|
||||
return this.signerManager.ensureActiveSignerForPubkey(pubkey);
|
||||
}
|
||||
|
||||
async registerPrivateKeySigner({ privateKey, pubkey }) {
|
||||
if (!privateKey) {
|
||||
throw new Error("Private key is required.");
|
||||
}
|
||||
const adapter = await createNsecAdapter({ privateKey, pubkey });
|
||||
this.signerManager.setActiveSigner(adapter);
|
||||
this.sessionActor = {
|
||||
pubkey: adapter.pubkey,
|
||||
privateKey: privateKey,
|
||||
source: "nsec",
|
||||
createdAt: Date.now(),
|
||||
};
|
||||
return adapter;
|
||||
}
|
||||
|
||||
async loginWithExtension(options) {
|
||||
return this.signerManager.loginWithExtension(options);
|
||||
}
|
||||
@@ -2919,6 +2981,10 @@ export class NostrClient {
|
||||
return this.signerManager.connectRemoteSigner(params);
|
||||
}
|
||||
|
||||
installNip46Client(client) {
|
||||
this.signerManager.installNip46Client(client);
|
||||
}
|
||||
|
||||
async useStoredRemoteSigner(options) {
|
||||
return this.signerManager.useStoredRemoteSigner(options);
|
||||
}
|
||||
|
||||
@@ -47,13 +47,14 @@ import {
|
||||
summarizeUrlForLog,
|
||||
} from "../nip46LoggingUtils.js";
|
||||
|
||||
import { bytesToHex } from "../../../vendor/crypto-helpers.bundle.min.js";
|
||||
import { devLogger, userLogger } from "../../utils/logger.js";
|
||||
import { createPrivateKeyCipherClosures } from "../signerHelpers.js";
|
||||
import { queueSignEvent } from "../signRequestQueue.js";
|
||||
import { signEventWithPrivateKey } from "../publishHelpers.js";
|
||||
import { ensureNostrTools, getCachedNostrTools } from "../toolkit.js";
|
||||
|
||||
function resolveSignerCapabilities(signer) {
|
||||
export function resolveSignerCapabilities(signer) {
|
||||
const fallback = {
|
||||
sign: false,
|
||||
nip44: false,
|
||||
@@ -84,7 +85,7 @@ function resolveSignerCapabilities(signer) {
|
||||
};
|
||||
}
|
||||
|
||||
function hydrateExtensionSignerCapabilities(signer) {
|
||||
export function hydrateExtensionSignerCapabilities(signer) {
|
||||
if (!signer || typeof signer !== "object") {
|
||||
return;
|
||||
}
|
||||
@@ -115,7 +116,7 @@ function hydrateExtensionSignerCapabilities(signer) {
|
||||
}
|
||||
}
|
||||
|
||||
function attachNipMethodAliases(signer) {
|
||||
export function attachNipMethodAliases(signer) {
|
||||
if (!signer || typeof signer !== "object") {
|
||||
return;
|
||||
}
|
||||
@@ -263,6 +264,10 @@ export class SignerManager {
|
||||
this.extensionReady = false;
|
||||
this.extensionPermissionsGranted = false;
|
||||
this.extensionPermissionCache = new Map();
|
||||
const storedPermissions = readStoredNip07Permissions();
|
||||
for (const method of storedPermissions) {
|
||||
this.extensionPermissionCache.set(method, true);
|
||||
}
|
||||
this.sessionActorCipherClosures = null;
|
||||
this.sessionActorCipherClosuresPrivateKey = null;
|
||||
this.remoteSignerListeners = new Set();
|
||||
@@ -311,21 +316,45 @@ export class SignerManager {
|
||||
|
||||
async ensureSessionActor() {
|
||||
if (this.sessionActor) {
|
||||
return this.sessionActor;
|
||||
return this.sessionActor.pubkey;
|
||||
}
|
||||
|
||||
if (this.lockedSessionActor) {
|
||||
return this.lockedSessionActor;
|
||||
return this.lockedSessionActor.pubkey;
|
||||
}
|
||||
|
||||
const storedEntry = readStoredSessionActorEntry();
|
||||
if (storedEntry) {
|
||||
this.lockedSessionActor = storedEntry;
|
||||
this.sessionActor = storedEntry;
|
||||
return storedEntry;
|
||||
return storedEntry.pubkey;
|
||||
}
|
||||
|
||||
return null;
|
||||
const tools = await ensureNostrTools();
|
||||
let privateKey = "";
|
||||
if (tools && typeof tools.generateSecretKey === "function") {
|
||||
const secret = tools.generateSecretKey();
|
||||
privateKey = bytesToHex(secret);
|
||||
} else if (tools && typeof tools.generatePrivateKey === "function") {
|
||||
privateKey = tools.generatePrivateKey();
|
||||
} else {
|
||||
throw new Error("Failed to generate session actor: nostr-tools missing key generation.");
|
||||
}
|
||||
|
||||
let pubkey = "";
|
||||
if (tools && typeof tools.getPublicKey === "function") {
|
||||
pubkey = tools.getPublicKey(privateKey);
|
||||
}
|
||||
|
||||
const newActor = {
|
||||
pubkey,
|
||||
privateKey,
|
||||
source: "generated",
|
||||
createdAt: Date.now(),
|
||||
};
|
||||
|
||||
this.sessionActor = newActor;
|
||||
return pubkey;
|
||||
}
|
||||
|
||||
clearStoredSessionActor() {
|
||||
@@ -423,6 +452,9 @@ export class SignerManager {
|
||||
if (missing.length === 0) {
|
||||
this.extensionPermissionsGranted = true;
|
||||
this.extensionPermissionCache.set(cacheKey, true);
|
||||
for (const method of methods) {
|
||||
this.extensionPermissionCache.set(method, true);
|
||||
}
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
@@ -435,11 +467,14 @@ export class SignerManager {
|
||||
const message = resolvePermissionStatusMessage(missing, context);
|
||||
|
||||
try {
|
||||
const response = await requestEnablePermissions(missing);
|
||||
if (response?.enabled) {
|
||||
const response = await requestEnablePermissions(window.nostr, missing);
|
||||
if (response?.ok) {
|
||||
writeStoredNip07Permissions(missing);
|
||||
this.extensionPermissionsGranted = true;
|
||||
this.extensionPermissionCache.set(cacheKey, true);
|
||||
for (const method of missing) {
|
||||
this.extensionPermissionCache.set(method, true);
|
||||
}
|
||||
return { ok: true };
|
||||
}
|
||||
return { ok: false, error: "permission-denied" };
|
||||
@@ -547,6 +582,16 @@ export class SignerManager {
|
||||
return { pubkey: normalized, signer: adapter };
|
||||
}
|
||||
|
||||
installNip46Client(client) {
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
this.nip46Client = client;
|
||||
this.pubkey = client.userPubkey || client.remotePubkey; // Fallback
|
||||
this.setActiveSigner(client.getActiveSigner());
|
||||
this.emitRemoteSignerChange();
|
||||
}
|
||||
|
||||
async connectRemoteSigner({
|
||||
connectionString,
|
||||
remember = true,
|
||||
@@ -893,6 +938,10 @@ export class SignerManager {
|
||||
};
|
||||
}
|
||||
|
||||
signEventWithPrivateKey(event, privateKey) {
|
||||
return signEventWithPrivateKey(event, privateKey);
|
||||
}
|
||||
|
||||
logout() {
|
||||
const previousPubkey = this.pubkey;
|
||||
this.pubkey = null;
|
||||
|
||||
@@ -5,6 +5,9 @@ import { normalizeNostrPubkey, sanitizeRelayList } from "./nip46Client.js";
|
||||
import { DEFAULT_RELAY_URLS, RELAY_URLS } from "./toolkit.js";
|
||||
|
||||
export class RelayBatchFetcher {
|
||||
/**
|
||||
* @param {import("./client.js").NostrClient} client
|
||||
*/
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@@ -484,7 +484,17 @@ export function clearStoredSessionActor() {
|
||||
|
||||
export function isSessionActor(nostrClient) {
|
||||
const sa = nostrClient?.sessionActor;
|
||||
return !!sa && sa.source !== "nsec";
|
||||
if (!sa) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
nostrClient?.pubkey &&
|
||||
sa.pubkey &&
|
||||
nostrClient.pubkey !== sa.pubkey
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return sa.source !== "nsec";
|
||||
}
|
||||
|
||||
function _closeSessionActorDb() {
|
||||
|
||||
@@ -55,6 +55,7 @@ function setupLoginEnvironment({ enableImpl, getPublicKey = HEX_PUBKEY } = {}) {
|
||||
return Promise.resolve();
|
||||
},
|
||||
getPublicKey: () => Promise.resolve(getPublicKey),
|
||||
signEvent: () => Promise.resolve({}),
|
||||
};
|
||||
|
||||
windowRef.nostr = nostrStub;
|
||||
@@ -456,10 +457,11 @@ describe("NIP-07 Login Permissions", () => {
|
||||
it("NIP-07 login does not wait for deferred permission grants", async () => {
|
||||
clearStoredPermissions();
|
||||
const env = setupLoginEnvironment();
|
||||
const originalEnsurePermissions = nostrClient.ensureExtensionPermissions;
|
||||
const target = nostrClient.signerManager || nostrClient;
|
||||
const originalEnsurePermissions = target.ensureExtensionPermissions;
|
||||
let completionPromise;
|
||||
|
||||
nostrClient.ensureExtensionPermissions = async () => {
|
||||
target.ensureExtensionPermissions = async () => {
|
||||
completionPromise = new Promise((_, reject) => {
|
||||
setTimeout(() => reject(new Error("permission denied")), 300);
|
||||
});
|
||||
@@ -482,7 +484,7 @@ describe("NIP-07 Login Permissions", () => {
|
||||
"deferred permission grants should still reject",
|
||||
);
|
||||
} finally {
|
||||
nostrClient.ensureExtensionPermissions = originalEnsurePermissions;
|
||||
target.ensureExtensionPermissions = originalEnsurePermissions;
|
||||
env.restore();
|
||||
nostrClient.logout();
|
||||
clearStoredPermissions();
|
||||
|
||||
@@ -15,7 +15,11 @@ test("ensureActiveSignerForPubkey prefers concurrent login over late extension i
|
||||
const client = new NostrClient();
|
||||
client.pubkey = HEX_PUBKEY;
|
||||
// Pre-condition: Cache permissions to trigger the waitForNip07Extension logic
|
||||
client.extensionPermissionCache.add("sign_event");
|
||||
if (typeof client.extensionPermissionCache.add === 'function') {
|
||||
client.extensionPermissionCache.add("sign_event");
|
||||
} else if (typeof client.extensionPermissionCache.set === 'function') {
|
||||
client.extensionPermissionCache.set("sign_event", true);
|
||||
}
|
||||
|
||||
// Mock a NIP-46 signer that might be set during the race
|
||||
const mockNip46Signer = {
|
||||
|
||||
Reference in new issue
Block a user