mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-06 12:52:26 +00:00
Merge branch 'unstable' into agent/automated-pr-review-fixes-3637557005884121646
This commit is contained in:
36 files changed
+1208
-990
No files matched your search
@@ -1674,153 +1674,6 @@ class Application {
|
||||
});
|
||||
}
|
||||
|
||||
async handleAddProfile(payload = {}) {
|
||||
const loginResult =
|
||||
payload && typeof payload === "object" ? payload.loginResult : null;
|
||||
|
||||
if (!loginResult) {
|
||||
devLogger.warn(
|
||||
"[profileModal] Ignoring add profile callback without an authentication result.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { pubkey, authType: loginAuthType, providerId } =
|
||||
typeof loginResult === "object" && loginResult
|
||||
? loginResult
|
||||
: { pubkey: loginResult };
|
||||
|
||||
const detailAuthType =
|
||||
typeof loginResult?.detail?.authType === "string"
|
||||
? loginResult.detail.authType
|
||||
: null;
|
||||
const detailProviderId =
|
||||
typeof loginResult?.detail?.providerId === "string"
|
||||
? loginResult.detail.providerId
|
||||
: null;
|
||||
|
||||
const resolvedAuthType = (() => {
|
||||
const candidates = [
|
||||
detailAuthType,
|
||||
loginAuthType,
|
||||
detailProviderId,
|
||||
providerId,
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
if (typeof candidate !== "string") {
|
||||
continue;
|
||||
}
|
||||
const trimmed = candidate.trim();
|
||||
if (trimmed) {
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
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(
|
||||
"Received an invalid public key from the authentication provider.",
|
||||
);
|
||||
}
|
||||
|
||||
const alreadySaved = this.savedProfiles.some(
|
||||
(entry) => this.normalizeHexPubkey(entry.pubkey) === normalizedPubkey,
|
||||
);
|
||||
if (alreadySaved) {
|
||||
this.showSuccess("That profile is already saved on this device.");
|
||||
return;
|
||||
}
|
||||
|
||||
const npub = this.safeEncodeNpub(normalizedPubkey) || "";
|
||||
let profileMeta = this.getProfileCacheEntry(normalizedPubkey)?.profile;
|
||||
|
||||
if (!profileMeta) {
|
||||
await this.authService.loadOwnProfile(normalizedPubkey);
|
||||
profileMeta = this.getProfileCacheEntry(normalizedPubkey)?.profile;
|
||||
}
|
||||
|
||||
const name = profileMeta?.name || "";
|
||||
const picture =
|
||||
profileMeta?.picture || "assets/svg/default-profile.svg";
|
||||
|
||||
this.savedProfiles.push({
|
||||
pubkey: normalizedPubkey,
|
||||
npub,
|
||||
name,
|
||||
picture,
|
||||
authType: resolvedAuthType,
|
||||
providerId: resolvedProviderId,
|
||||
});
|
||||
|
||||
persistSavedProfiles({ persistActive: false });
|
||||
this.renderSavedProfiles();
|
||||
|
||||
this.showSuccess("Profile added. Select it when you're ready to switch.");
|
||||
} catch (error) {
|
||||
const cancellationCodes = new Set([
|
||||
"login-cancelled",
|
||||
"user-cancelled",
|
||||
"modal-dismissed",
|
||||
]);
|
||||
if (
|
||||
error &&
|
||||
typeof error === "object" &&
|
||||
typeof error.code === "string" &&
|
||||
cancellationCodes.has(error.code)
|
||||
) {
|
||||
devLogger.log("[profileModal] Add profile flow cancelled.", error);
|
||||
return;
|
||||
}
|
||||
|
||||
devLogger.error(
|
||||
"[profileModal] Failed to add profile via authentication provider:",
|
||||
error,
|
||||
);
|
||||
|
||||
const message = this.describeLoginError(
|
||||
error,
|
||||
"Couldn't add that profile. Please try again.",
|
||||
);
|
||||
|
||||
const rejectionError =
|
||||
error instanceof Error
|
||||
? error
|
||||
: new Error(message || "Couldn't add that profile. Please try again.");
|
||||
|
||||
if (message && rejectionError.message !== message) {
|
||||
rejectionError.message = message;
|
||||
}
|
||||
|
||||
if (
|
||||
error &&
|
||||
typeof error === "object" &&
|
||||
error.code &&
|
||||
!rejectionError.code
|
||||
) {
|
||||
rejectionError.code = error.code;
|
||||
}
|
||||
|
||||
throw rejectionError;
|
||||
}
|
||||
}
|
||||
|
||||
describeLoginError(error, fallbackMessage = "Failed to login. Please try again.") {
|
||||
const code =
|
||||
error && typeof error.code === "string" && error.code.trim()
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
import { bytesToHex } from "../../vendor/crypto-helpers.bundle.min.js";
|
||||
import { signEventWithPrivateKey } from "../nostr/publishHelpers.js";
|
||||
import { ensureNostrTools, getCachedNostrTools } from "../nostr/toolkit.js";
|
||||
import { normalizeActorKey } from "../nostr/watchHistory.js";
|
||||
import { buildHttpAuthEvent } from "../nostrEventSchemas.js";
|
||||
import { runNip07WithRetry } from "../nostr/nip07Permissions.js";
|
||||
|
||||
const DEFAULT_TEST_PUBKEY = "f".repeat(64);
|
||||
const DEFAULT_DEV_DISPLAY_NAME = "Ephemeral dev signer";
|
||||
const DEFAULT_TEST_DISPLAY_NAME = "Test signer";
|
||||
|
||||
function normalizePubkey(value) {
|
||||
const normalized = typeof value === "string" ? normalizeActorKey(value) : "";
|
||||
return normalized || "";
|
||||
}
|
||||
|
||||
function getSigningTimestamp() {
|
||||
return Math.floor(Date.now() / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} SigningAdapter
|
||||
* @property {() => Promise<string>} getPubkey
|
||||
* @property {() => Promise<string>} getDisplayName
|
||||
* @property {(unsignedEvent: object) => Promise<object>} signEvent
|
||||
* @property {(message: string) => Promise<string>} signMessage
|
||||
*/
|
||||
|
||||
export function createNip07SigningAdapter({ extension } = {}) {
|
||||
const resolvedExtension =
|
||||
extension ||
|
||||
(typeof window !== "undefined" && window?.nostr ? window.nostr : null);
|
||||
|
||||
const getPubkey = async () => {
|
||||
if (
|
||||
!resolvedExtension ||
|
||||
typeof resolvedExtension.getPublicKey !== "function"
|
||||
) {
|
||||
throw new Error("NIP-07 extension is unavailable.");
|
||||
}
|
||||
return normalizePubkey(
|
||||
await runNip07WithRetry(() => resolvedExtension.getPublicKey(), {
|
||||
label: "extension.getPublicKey",
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const getDisplayName = async () => {
|
||||
if (
|
||||
!resolvedExtension ||
|
||||
typeof resolvedExtension.getMetadata !== "function"
|
||||
) {
|
||||
return "";
|
||||
}
|
||||
const metadata = await runNip07WithRetry(
|
||||
() => resolvedExtension.getMetadata(),
|
||||
{ label: "extension.getMetadata" },
|
||||
);
|
||||
if (!metadata || typeof metadata !== "object") {
|
||||
return "";
|
||||
}
|
||||
const displayName =
|
||||
typeof metadata.display_name === "string"
|
||||
? metadata.display_name.trim()
|
||||
: "";
|
||||
if (displayName) {
|
||||
return displayName;
|
||||
}
|
||||
return typeof metadata.name === "string" ? metadata.name.trim() : "";
|
||||
};
|
||||
|
||||
const signEvent = async (event) => {
|
||||
if (
|
||||
!resolvedExtension ||
|
||||
typeof resolvedExtension.signEvent !== "function"
|
||||
) {
|
||||
throw new Error("NIP-07 extension is missing signEvent.");
|
||||
}
|
||||
return runNip07WithRetry(() => resolvedExtension.signEvent(event), {
|
||||
label: "extension.signEvent",
|
||||
});
|
||||
};
|
||||
|
||||
const signMessage = async (message) => {
|
||||
if (
|
||||
!resolvedExtension ||
|
||||
typeof resolvedExtension.signMessage !== "function"
|
||||
) {
|
||||
throw new Error("NIP-07 extension does not support signMessage.");
|
||||
}
|
||||
return runNip07WithRetry(() => resolvedExtension.signMessage(message), {
|
||||
label: "extension.signMessage",
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
type: "nip07",
|
||||
getPubkey,
|
||||
getDisplayName,
|
||||
signEvent,
|
||||
signMessage,
|
||||
};
|
||||
}
|
||||
|
||||
export function createEphemeralDevSigningAdapter({
|
||||
displayName = DEFAULT_DEV_DISPLAY_NAME,
|
||||
privateKey,
|
||||
} = {}) {
|
||||
let cachedPrivateKey = typeof privateKey === "string" ? privateKey.trim() : "";
|
||||
let cachedPubkey = "";
|
||||
|
||||
const ensurePrivateKey = () => {
|
||||
if (cachedPrivateKey) {
|
||||
return cachedPrivateKey;
|
||||
}
|
||||
const random = new Uint8Array(32);
|
||||
if (typeof window !== "undefined" && window.crypto?.getRandomValues) {
|
||||
window.crypto.getRandomValues(random);
|
||||
} else if (typeof globalThis?.crypto?.getRandomValues === "function") {
|
||||
globalThis.crypto.getRandomValues(random);
|
||||
} else {
|
||||
for (let i = 0; i < random.length; i += 1) {
|
||||
random[i] = Math.floor(Math.random() * 256);
|
||||
}
|
||||
}
|
||||
cachedPrivateKey = bytesToHex(random);
|
||||
return cachedPrivateKey;
|
||||
};
|
||||
|
||||
const ensurePubkey = async () => {
|
||||
if (cachedPubkey) {
|
||||
return cachedPubkey;
|
||||
}
|
||||
const tools = (await ensureNostrTools()) || getCachedNostrTools();
|
||||
if (!tools || typeof tools.getPublicKey !== "function") {
|
||||
throw new Error("Nostr tools are required to derive the dev pubkey.");
|
||||
}
|
||||
cachedPubkey = normalizePubkey(tools.getPublicKey(ensurePrivateKey()));
|
||||
if (!cachedPubkey) {
|
||||
throw new Error("Failed to derive dev pubkey.");
|
||||
}
|
||||
return cachedPubkey;
|
||||
};
|
||||
|
||||
const signEvent = async (event) =>
|
||||
signEventWithPrivateKey({ ...event, pubkey: await ensurePubkey() }, ensurePrivateKey());
|
||||
|
||||
const signMessage = async (message) => {
|
||||
const pubkey = await ensurePubkey();
|
||||
const event = buildHttpAuthEvent({
|
||||
pubkey,
|
||||
created_at: getSigningTimestamp(),
|
||||
url: "bitvid:signing-adapter",
|
||||
content: typeof message === "string" ? message : String(message ?? ""),
|
||||
});
|
||||
|
||||
const signed = signEventWithPrivateKey(event, ensurePrivateKey());
|
||||
if (!signed || typeof signed.sig !== "string") {
|
||||
throw new Error("Failed to sign message.");
|
||||
}
|
||||
return signed.sig;
|
||||
};
|
||||
|
||||
return {
|
||||
type: "dev",
|
||||
getPubkey: ensurePubkey,
|
||||
getDisplayName: async () => displayName,
|
||||
signEvent,
|
||||
signMessage,
|
||||
};
|
||||
}
|
||||
|
||||
export function createTestSigningAdapter({
|
||||
pubkey = DEFAULT_TEST_PUBKEY,
|
||||
displayName = DEFAULT_TEST_DISPLAY_NAME,
|
||||
signEvent,
|
||||
signMessage,
|
||||
} = {}) {
|
||||
const normalizedPubkey = normalizePubkey(pubkey) || DEFAULT_TEST_PUBKEY;
|
||||
|
||||
const signEventImpl =
|
||||
typeof signEvent === "function"
|
||||
? signEvent
|
||||
: async (event) => ({
|
||||
...event,
|
||||
pubkey: normalizedPubkey || event.pubkey,
|
||||
id: "test-event-id",
|
||||
sig: "test-event-sig",
|
||||
});
|
||||
|
||||
const signMessageImpl =
|
||||
typeof signMessage === "function"
|
||||
? signMessage
|
||||
: async (message) => `signed:${message}`;
|
||||
|
||||
return {
|
||||
type: "test",
|
||||
getPubkey: async () => normalizedPubkey,
|
||||
getDisplayName: async () => displayName,
|
||||
signEvent: signEventImpl,
|
||||
signMessage: signMessageImpl,
|
||||
};
|
||||
}
|
||||
@@ -908,24 +908,16 @@ class HashtagPreferencesService {
|
||||
DEFAULT_NIP07_ENCRYPTION_METHODS,
|
||||
);
|
||||
if (!permissionResult?.ok) {
|
||||
const error =
|
||||
permissionResult?.error instanceof Error
|
||||
? permissionResult.error
|
||||
: new Error(
|
||||
"Extension encryption permissions are required to read hashtag preferences.",
|
||||
);
|
||||
error.code = "hashtag-preferences-permission-required";
|
||||
return { ok: false, error };
|
||||
userLogger.warn(
|
||||
`${LOG_PREFIX} Extension permission request failed/denied, but attempting operation via fallback.`,
|
||||
permissionResult?.error,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
userLogger.warn(
|
||||
`${LOG_PREFIX} Extension permissions request failed while loading preferences`,
|
||||
`${LOG_PREFIX} Extension permissions request threw, attempting fallback.`,
|
||||
error,
|
||||
);
|
||||
const wrapped =
|
||||
error instanceof Error ? error : new Error(String(error));
|
||||
wrapped.code = "hashtag-preferences-permission-required";
|
||||
return { ok: false, error: wrapped };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -969,11 +961,12 @@ class HashtagPreferencesService {
|
||||
);
|
||||
}
|
||||
|
||||
const nostrApi = allowPermissionPrompt
|
||||
? typeof window !== "undefined"
|
||||
? window?.nostr
|
||||
: null
|
||||
: null;
|
||||
const nostrApi =
|
||||
typeof window !== "undefined" && window?.nostr
|
||||
? window.nostr
|
||||
: typeof globalThis !== "undefined" && globalThis?.nostr
|
||||
? globalThis.nostr
|
||||
: null;
|
||||
if (nostrApi) {
|
||||
if (typeof nostrApi.nip04?.decrypt === "function") {
|
||||
registerDecryptor(
|
||||
|
||||
+4
-4
@@ -859,10 +859,10 @@ class SubscriptionsManager {
|
||||
|
||||
let signer = getActiveSigner();
|
||||
if (
|
||||
!signer ||
|
||||
(!signerHasRequiredDecryptors(signer) &&
|
||||
typeof nostrClient?.ensureActiveSignerForPubkey === "function" &&
|
||||
allowPermissionPrompt)
|
||||
allowPermissionPrompt &&
|
||||
(!signer ||
|
||||
(!signerHasRequiredDecryptors(signer) &&
|
||||
typeof nostrClient?.ensureActiveSignerForPubkey === "function"))
|
||||
) {
|
||||
signer = await nostrClient.ensureActiveSignerForPubkey(userPubkey);
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import { WSS_TRACKERS as DEFAULT_WSS_TRACKERS } from "./constants.js";
|
||||
|
||||
export const TRACKER_TIMEOUT_MS = 6000;
|
||||
const TRACKER_PER_MAGNET = 10;
|
||||
export const HEALTH_TTL_MS = 2 * 60 * 1000;
|
||||
export const CONCURRENCY = 6;
|
||||
export const TRACKER_ERROR_COOLDOWN_MS = 60 * 1000;
|
||||
|
||||
export function resolveTrackerList({ magnetTrackers } = {}) {
|
||||
const combined = [];
|
||||
const seen = new Set();
|
||||
|
||||
const pushUnique = (url) => {
|
||||
if (typeof url !== "string") {
|
||||
return;
|
||||
}
|
||||
const trimmed = url.trim();
|
||||
if (!trimmed) {
|
||||
return;
|
||||
}
|
||||
if (!/^wss:\/\//i.test(trimmed)) {
|
||||
return;
|
||||
}
|
||||
const normalized = trimmed.toLowerCase();
|
||||
if (seen.has(normalized)) {
|
||||
return;
|
||||
}
|
||||
seen.add(normalized);
|
||||
combined.push(trimmed);
|
||||
};
|
||||
|
||||
if (Array.isArray(magnetTrackers)) {
|
||||
magnetTrackers.forEach(pushUnique);
|
||||
}
|
||||
|
||||
DEFAULT_WSS_TRACKERS.forEach(pushUnique);
|
||||
|
||||
return combined.slice(0, TRACKER_PER_MAGNET);
|
||||
}
|
||||
@@ -571,7 +571,6 @@ export default class ApplicationBootstrap {
|
||||
onClose: () => app.handleProfileModalClosed(),
|
||||
onLogout: async () => app.requestLogout(),
|
||||
onChannelLink: (element) => app.handleProfileChannelLink(element),
|
||||
onAddAccount: (payload) => app.handleAddProfile(payload),
|
||||
onRequestLogoutProfile: (payload) =>
|
||||
app.handleProfileLogoutRequest(payload),
|
||||
onRequestSwitchProfile: (payload) =>
|
||||
|
||||
@@ -6176,25 +6176,159 @@ export class ProfileModalController {
|
||||
}
|
||||
}
|
||||
|
||||
async invokeAddAccountCallback(loginResult) {
|
||||
if (typeof this.callbacks.onAddAccount !== "function") {
|
||||
async handleAddProfile(payload = {}) {
|
||||
const loginResult =
|
||||
payload && typeof payload === "object" ? payload.loginResult : null;
|
||||
|
||||
if (!loginResult) {
|
||||
devLogger.warn(
|
||||
"[ProfileModalController] Ignoring add profile callback without an authentication result.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.callbacks.onAddAccount({
|
||||
controller: this,
|
||||
loginResult,
|
||||
const { pubkey, authType: loginAuthType, providerId } =
|
||||
typeof loginResult === "object" && loginResult
|
||||
? loginResult
|
||||
: { pubkey: loginResult };
|
||||
|
||||
const detailAuthType =
|
||||
typeof loginResult?.detail?.authType === "string"
|
||||
? loginResult.detail.authType
|
||||
: null;
|
||||
const detailProviderId =
|
||||
typeof loginResult?.detail?.providerId === "string"
|
||||
? loginResult.detail.providerId
|
||||
: null;
|
||||
|
||||
const resolvedAuthType = (() => {
|
||||
const candidates = [
|
||||
detailAuthType,
|
||||
loginAuthType,
|
||||
detailProviderId,
|
||||
providerId,
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
if (typeof candidate !== "string") {
|
||||
continue;
|
||||
}
|
||||
const trimmed = candidate.trim();
|
||||
if (trimmed) {
|
||||
return trimmed;
|
||||
}
|
||||
}
|
||||
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(
|
||||
"Received an invalid public key from the authentication provider.",
|
||||
);
|
||||
}
|
||||
|
||||
const savedProfiles = this.getSavedProfiles();
|
||||
const alreadySaved = savedProfiles.some(
|
||||
(entry) => this.normalizeHexPubkey(entry.pubkey) === normalizedPubkey,
|
||||
);
|
||||
if (alreadySaved) {
|
||||
this.showSuccess("That profile is already saved on this device.");
|
||||
return;
|
||||
}
|
||||
|
||||
const npub = this.safeEncodeNpub(normalizedPubkey) || "";
|
||||
let profileMeta = this.services.getProfileCacheEntry(normalizedPubkey)?.profile;
|
||||
|
||||
if (!profileMeta) {
|
||||
await this.services.authService.loadOwnProfile(normalizedPubkey);
|
||||
profileMeta = this.services.getProfileCacheEntry(normalizedPubkey)?.profile;
|
||||
}
|
||||
|
||||
const name = profileMeta?.name || "";
|
||||
const picture =
|
||||
profileMeta?.picture || "assets/svg/default-profile.svg";
|
||||
|
||||
savedProfiles.push({
|
||||
pubkey: normalizedPubkey,
|
||||
npub,
|
||||
name,
|
||||
picture,
|
||||
authType: resolvedAuthType,
|
||||
providerId: resolvedProviderId,
|
||||
});
|
||||
|
||||
this.setSavedProfiles(savedProfiles, { persist: false, persistActive: false });
|
||||
this.persistSavedProfiles({ persistActive: false });
|
||||
this.renderSavedProfiles();
|
||||
|
||||
this.showSuccess("Profile added. Select it when you're ready to switch.");
|
||||
} catch (error) {
|
||||
devLogger.warn(
|
||||
"[ProfileModalController] onAddAccount callback threw:",
|
||||
const cancellationCodes = new Set([
|
||||
"login-cancelled",
|
||||
"user-cancelled",
|
||||
"modal-dismissed",
|
||||
]);
|
||||
if (
|
||||
error &&
|
||||
typeof error === "object" &&
|
||||
typeof error.code === "string" &&
|
||||
cancellationCodes.has(error.code)
|
||||
) {
|
||||
this.log("[ProfileModalController] Add profile flow cancelled.", error);
|
||||
return;
|
||||
}
|
||||
|
||||
devLogger.error(
|
||||
"[ProfileModalController] Failed to add profile via authentication provider:",
|
||||
error,
|
||||
);
|
||||
throw error;
|
||||
|
||||
const message = this.describeLoginErrorService(
|
||||
error,
|
||||
"Couldn't add that profile. Please try again.",
|
||||
);
|
||||
|
||||
const rejectionError =
|
||||
error instanceof Error
|
||||
? error
|
||||
: new Error(message || "Couldn't add that profile. Please try again.");
|
||||
|
||||
if (message && rejectionError.message !== message) {
|
||||
rejectionError.message = message;
|
||||
}
|
||||
|
||||
if (
|
||||
error &&
|
||||
typeof error === "object" &&
|
||||
error.code &&
|
||||
!rejectionError.code
|
||||
) {
|
||||
rejectionError.code = error.code;
|
||||
}
|
||||
|
||||
throw rejectionError;
|
||||
}
|
||||
}
|
||||
|
||||
async invokeAddAccountCallback(loginResult) {
|
||||
return this.handleAddProfile({ loginResult });
|
||||
}
|
||||
|
||||
renderSavedProfiles() {
|
||||
const normalizedActive = this.normalizeHexPubkey(this.getActivePubkey());
|
||||
const entriesNeedingFetch = new Set();
|
||||
|
||||
+4
-3
@@ -959,9 +959,10 @@ class UserBlockListManager {
|
||||
};
|
||||
|
||||
if (
|
||||
!signer ||
|
||||
(!signerHasRequiredDecryptors(signer) &&
|
||||
typeof nostrClient?.ensureActiveSignerForPubkey === "function")
|
||||
allowPermissionPrompt &&
|
||||
(!signer ||
|
||||
(!signerHasRequiredDecryptors(signer) &&
|
||||
typeof nostrClient?.ensureActiveSignerForPubkey === "function"))
|
||||
) {
|
||||
signer = await nostrClient.ensureActiveSignerForPubkey(normalized);
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ function getSessionActorKey() {
|
||||
return normalizeActorKey(nostrClient?.sessionActor?.pubkey);
|
||||
}
|
||||
|
||||
async function ensureWatchHistoryExtensionPermissions(actorKey) {
|
||||
async function ensureWatchHistoryExtensionPermissions(actorKey, options = {}) {
|
||||
const normalizedActor = normalizeActorKey(actorKey);
|
||||
if (!normalizedActor) {
|
||||
return { ok: true };
|
||||
@@ -85,8 +85,13 @@ async function ensureWatchHistoryExtensionPermissions(actorKey) {
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
const allowPermissionPrompt = options?.allowPermissionPrompt !== false;
|
||||
|
||||
let signer = getActiveSigner();
|
||||
if (!signer && typeof nostrClient?.ensureActiveSignerForPubkey === "function") {
|
||||
if (
|
||||
allowPermissionPrompt &&
|
||||
(!signer && typeof nostrClient?.ensureActiveSignerForPubkey === "function")
|
||||
) {
|
||||
signer = await nostrClient.ensureActiveSignerForPubkey(normalizedActor);
|
||||
}
|
||||
|
||||
@@ -97,6 +102,10 @@ async function ensureWatchHistoryExtensionPermissions(actorKey) {
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
if (!allowPermissionPrompt) {
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
const permissionResult = await requestDefaultExtensionPermissions();
|
||||
if (permissionResult.ok) {
|
||||
return { ok: true };
|
||||
@@ -984,7 +993,7 @@ async function snapshot(items, options = {}) {
|
||||
return run;
|
||||
}
|
||||
|
||||
function scheduleWatchHistoryRefresh(actorKey, cacheEntry = {}) {
|
||||
function scheduleWatchHistoryRefresh(actorKey, cacheEntry = {}, options = {}) {
|
||||
if (!actorKey) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
@@ -996,6 +1005,7 @@ function scheduleWatchHistoryRefresh(actorKey, cacheEntry = {}) {
|
||||
const promise = (async () => {
|
||||
const permissionResult = await ensureWatchHistoryExtensionPermissions(
|
||||
actorKey,
|
||||
options
|
||||
);
|
||||
if (!permissionResult.ok) {
|
||||
throw permissionResult.error;
|
||||
@@ -1264,11 +1274,19 @@ async function loadLatest(actorInput, options = {}) {
|
||||
}
|
||||
|
||||
if (!allowStale || !hasCachedItems) {
|
||||
const resolved = await scheduleWatchHistoryRefresh(actorKey, cacheEntry);
|
||||
const resolved = await scheduleWatchHistoryRefresh(
|
||||
actorKey,
|
||||
cacheEntry,
|
||||
normalizedOptions
|
||||
);
|
||||
return mergeQueuedItemsIfNeeded(actorKey, resolved);
|
||||
}
|
||||
|
||||
const refreshPromise = scheduleWatchHistoryRefresh(actorKey, cacheEntry);
|
||||
const refreshPromise = scheduleWatchHistoryRefresh(
|
||||
actorKey,
|
||||
cacheEntry,
|
||||
normalizedOptions
|
||||
);
|
||||
refreshPromise.catch(() => {});
|
||||
|
||||
devLogger.info(
|
||||
|
||||
Reference in new issue
Block a user