Merge branch 'unstable' into fix-moderation-fixture-click-timeout-6604549089296585406

This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2026-02-05 18:13:34 -05:00
commit 36fe983e0d
5 files changed
+109 -14

No files matched your search

+66
View File
@@ -0,0 +1,66 @@
import { profileCache } from "../js/state/profileCache.js";
// Polyfill localStorage
const store = new Map();
global.localStorage = {
getItem: (key) => store.get(key) || null,
setItem: (key, value) => store.set(key, value),
removeItem: (key) => store.delete(key),
clear: () => store.clear(),
};
// Polyfill requestIdleCallback
global.requestIdleCallback = (cb) => setTimeout(() => {
cb({
timeRemaining: () => 50,
didTimeout: false
});
}, 0);
// Polyfill window (might be needed by logger or others)
if (typeof window === 'undefined') {
global.window = global;
}
function generateLargeData() {
const data = [];
// Generate roughly 2MB of JSON data
for (let i = 0; i < 20000; i++) {
data.push({ id: i, content: "x".repeat(100) });
}
return data;
}
async function runBenchmark() {
const pubkey = "0".repeat(64);
const section = "watchHistory";
const data = generateLargeData();
// Set active profile to ensure logic runs
profileCache.setActiveProfile(pubkey);
console.log("Benchmarking setProfileData with large payload...");
// Warmup
profileCache.setProfileData(pubkey, section, [{id: 1}]);
const start = performance.now();
// We call it multiple times to amplify the effect, but a single call with 2MB is enough to show blocking
profileCache.setProfileData(pubkey, section, data);
const end = performance.now();
console.log(`Execution time (Synchronous part): ${(end - start).toFixed(4)} ms`);
// Wait for idle callback
await new Promise(resolve => setTimeout(resolve, 50));
// Verify data is "stored"
const stored = localStorage.getItem(profileCache.getStorageKey(pubkey, section));
if (stored) {
console.log("Data successfully stored in localStorage (length: " + stored.length + ")");
} else {
console.log("Data NOT found in localStorage");
}
}
runBenchmark();
+20 -9
View File
@@ -16,6 +16,15 @@ const SECTION_TO_NOTE_TYPE = {
"profile": NOTE_TYPES.PROFILE_METADATA,
};
// Helper to defer non-critical work to idle periods
function runIdle(callback) {
if (typeof requestIdleCallback !== "undefined") {
requestIdleCallback(callback);
} else {
setTimeout(callback, 1);
}
}
function sanitizeProfileString(value) {
if (typeof value !== "string") {
return "";
@@ -316,17 +325,19 @@ class ProfileCache {
const storageKey = this.getStorageKey(pubkey, section);
const tier = this.getStorageTier(section);
// Save to storage
// Save to storage (Optimized: defer blocking I/O)
if (tier === STORAGE_TIERS.LOCAL_STORAGE && typeof localStorage !== "undefined") {
try {
if (data === null || data === undefined) {
localStorage.removeItem(storageKey);
} else {
localStorage.setItem(storageKey, JSON.stringify(data));
runIdle(() => {
try {
if (data === null || data === undefined) {
localStorage.removeItem(storageKey);
} else {
localStorage.setItem(storageKey, JSON.stringify(data));
}
} catch (error) {
userLogger.warn(`[ProfileCache] Failed to save ${section} for ${pubkey}`, error);
}
} catch (error) {
userLogger.warn(`[ProfileCache] Failed to save ${section} for ${pubkey}`, error);
}
});
}
// Update memory cache
+3 -3
View File
@@ -1856,9 +1856,9 @@ export class VideoCard {
target.hidden = false;
target.removeAttribute("hidden");
target.removeAttribute("aria-hidden");
// If target is summary container, ensure it's displayed as block
// If target is summary container, ensure it's displayed as flex (to match bv-stack)
if (target !== slot) {
target.style.setProperty("display", "block", "important");
target.style.setProperty("display", "flex", "important");
} else {
target.style.removeProperty("display");
}
@@ -2009,7 +2009,7 @@ export class VideoCard {
if (!this.hiddenSummaryEl) {
this.hiddenSummaryEl = this.createElement("div", {
classNames: ["p-md", "bv-stack", "bv-stack--tight"],
classNames: ["p-md", "bv-stack", "bv-stack--tight", "items-start"],
});
this.hiddenSummaryEl.dataset.moderationHiddenContainer = "true";
this.hiddenSummaryEl.setAttribute("role", "group");
+10 -2
View File
@@ -79,7 +79,7 @@ test("ProfileCache: resolveAddressKey", (t) => {
assert.equal(keyUnknown, `bitvid:profile:${pubkey}:unknownSection:v1`);
});
test("ProfileCache: set and get (memory and persistence)", (t) => {
test("ProfileCache: set and get (memory and persistence)", async (t) => {
const pubkey = "c".repeat(64);
profileCache.setActiveProfile(pubkey);
@@ -98,6 +98,10 @@ test("ProfileCache: set and get (memory and persistence)", (t) => {
// Check persistence
const storageKey = profileCache.getStorageKey(pubkey, section);
// Wait for async write (runIdle/setTimeout)
await new Promise((resolve) => setTimeout(resolve, 20));
const storedRaw = localStorage.getItem(storageKey);
assert.ok(storedRaw);
assert.deepEqual(JSON.parse(storedRaw), data);
@@ -110,7 +114,7 @@ test("ProfileCache: set and get (memory and persistence)", (t) => {
assert.deepEqual(reloaded, data);
});
test("ProfileCache: setProfile normalization and storage", (t) => {
test("ProfileCache: setProfile normalization and storage", async (t) => {
const pubkey = "d".repeat(64);
const profileInput = {
name: " Test User ",
@@ -131,6 +135,10 @@ test("ProfileCache: setProfile normalization and storage", (t) => {
// Verify persistence
const storageKey = profileCache.getStorageKey(pubkey, "profile");
// Wait for async write (runIdle/setTimeout)
await new Promise((resolve) => setTimeout(resolve, 20));
const stored = JSON.parse(localStorage.getItem(storageKey));
assert.deepEqual(stored.profile, entry.profile);
});
+10
View File
@@ -44,6 +44,16 @@ if (typeof globalThis.window.localStorage === "undefined") {
globalThis.window.localStorage = globalThis.localStorage;
}
// Polyfill requestIdleCallback for synchronous testing if undefined
if (typeof globalThis.requestIdleCallback === "undefined") {
globalThis.requestIdleCallback = (cb) => cb();
globalThis.cancelIdleCallback = () => {};
if (globalThis.window) {
globalThis.window.requestIdleCallback = globalThis.requestIdleCallback;
globalThis.window.cancelIdleCallback = globalThis.cancelIdleCallback;
}
}
if (typeof globalThis.window.crypto === "undefined" && typeof globalThis.crypto !== "undefined") {
globalThis.window.crypto = globalThis.crypto;
}