Files
bitvid/js/nip07Support.js
T

133 lines
3.1 KiB
JavaScript

// js/nip07Support.js
import { isDevMode } from "./config.js";
export const NIP07_LOGIN_TIMEOUT_MS = 60_000; // 60 seconds
export const NIP07_LOGIN_TIMEOUT_ERROR_MESSAGE =
"Timed out waiting for the NIP-07 extension. Confirm the extension prompt in your browser toolbar and try again.";
const DEFAULT_ENABLE_VARIANT_TIMEOUT_MS = 7000;
export const DEFAULT_NIP07_PERMISSION_METHODS = Object.freeze([
"get_public_key",
"sign_event",
"nip04.encrypt",
"nip04.decrypt",
"read_relays",
"write_relays",
]);
export function getEnableVariantTimeoutMs() {
const overrideValue =
typeof globalThis !== "undefined" &&
globalThis !== null &&
Number.isFinite(globalThis.__BITVID_NIP07_ENABLE_VARIANT_TIMEOUT_MS__)
? Math.floor(globalThis.__BITVID_NIP07_ENABLE_VARIANT_TIMEOUT_MS__)
: null;
if (overrideValue !== null && overrideValue > 0) {
return Math.max(50, overrideValue);
}
return DEFAULT_ENABLE_VARIANT_TIMEOUT_MS;
}
function withNip07Timeout(
operation,
{
timeoutMs = NIP07_LOGIN_TIMEOUT_MS,
message = NIP07_LOGIN_TIMEOUT_ERROR_MESSAGE,
} = {},
) {
const numericTimeout = Number(timeoutMs);
const effectiveTimeout =
Number.isFinite(numericTimeout) && numericTimeout > 0
? numericTimeout
: NIP07_LOGIN_TIMEOUT_MS;
let timeoutId;
const timeoutPromise = new Promise((_, reject) => {
timeoutId = setTimeout(() => {
reject(new Error(message));
}, effectiveTimeout);
});
let operationResult;
try {
operationResult = operation();
} catch (err) {
if (timeoutId) {
clearTimeout(timeoutId);
}
throw err;
}
const operationPromise = Promise.resolve(operationResult);
return Promise.race([operationPromise, timeoutPromise]).finally(() => {
if (timeoutId) {
clearTimeout(timeoutId);
}
});
}
export async function runNip07WithRetry(
operation,
{
label = "NIP-07 operation",
timeoutMs = NIP07_LOGIN_TIMEOUT_MS,
retryMultiplier = 2,
} = {},
) {
let hasStarted = false;
let cachedPromise = null;
const getOrStartOperation = () => {
if (!hasStarted) {
hasStarted = true;
try {
cachedPromise = Promise.resolve(operation());
} catch (error) {
hasStarted = false;
cachedPromise = null;
throw error;
}
}
return cachedPromise;
};
try {
return await withNip07Timeout(getOrStartOperation, {
timeoutMs,
message: NIP07_LOGIN_TIMEOUT_ERROR_MESSAGE,
});
} catch (error) {
const isTimeoutError =
error instanceof Error &&
error.message === NIP07_LOGIN_TIMEOUT_ERROR_MESSAGE;
if (!isTimeoutError || retryMultiplier <= 1) {
throw error;
}
const extendedTimeout = Math.max(
timeoutMs,
Math.round(timeoutMs * retryMultiplier),
);
if (isDevMode) {
console.warn(
`[nostr] ${label} taking longer than ${timeoutMs}ms. Waiting up to ${extendedTimeout}ms for extension response.`,
);
}
return withNip07Timeout(getOrStartOperation, {
timeoutMs: extendedTimeout,
message: NIP07_LOGIN_TIMEOUT_ERROR_MESSAGE,
});
}
}
export const __testExports = { runNip07WithRetry };