mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
loadVideos awaited ensureAccessControlReady -> waitForReady -> _performRefresh
-> loadAdminState, which awaits a remote admin-list fetch. On a cold load that
waits for relays to connect (~5s) plus the fetch, stalling the feed ~10s before
any video renders. The cached admin state IS hydrated synchronously at
construction, but with markLoaded:false, so waitForReady blocked on a full
remote refresh even when a usable cache existed ("refresh fixes it").
ensureAccessControlReady now blocks only on a first-ever cold load WITH whitelist
mode (where showing non-whitelisted content before the whitelist arrives would be
wrong). In every other case — admin state hydrated from the localStorage cache,
already loaded, or blacklist-only mode — it kicks the refresh off in the
background (ensureReady) and renders immediately; the reactive
onWhitelist/onBlacklistChange handlers re-filter the grid once fresh lists land.
Adds accessControl.isHydrated() and a branching test
(nostr-service-access-control-ready.test.mjs).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
71 lines
2.5 KiB
JavaScript
71 lines
2.5 KiB
JavaScript
// Verifies ensureAccessControlReady no longer blocks the feed on the remote
|
|
// admin-list fetch except on a first-ever cold load in whitelist mode.
|
|
//
|
|
// Scenario (SCN-access-control-non-blocking-feed):
|
|
// - admin state hydrated (cache or loaded) => background refresh (ensureReady)
|
|
// - cold + whitelist mode => block (waitForReady)
|
|
// - cold + blacklist-only mode => background refresh (ensureReady)
|
|
|
|
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import "./test-helpers/setup-localstorage.mjs";
|
|
import moderationService from "../js/services/moderationService.js";
|
|
import { NostrService } from "../js/services/nostrService.js";
|
|
|
|
// Stub background timers the service may schedule.
|
|
if (moderationService) {
|
|
moderationService.scheduleTrustedMuteSubscriptionRefresh = () => {};
|
|
moderationService.refreshTrustedMuteSubscriptions = async () => {};
|
|
}
|
|
if (typeof globalThis.window === "undefined") globalThis.window = {};
|
|
|
|
function makeAccessControl({ hydrated, whitelist }) {
|
|
const calls = { ensureReady: 0, waitForReady: 0 };
|
|
return {
|
|
calls,
|
|
isHydrated: () => hydrated,
|
|
whitelistMode: () => whitelist,
|
|
ensureReady: async () => {
|
|
calls.ensureReady += 1;
|
|
},
|
|
waitForReady: async () => {
|
|
calls.waitForReady += 1;
|
|
},
|
|
};
|
|
}
|
|
|
|
test("hydrated => background refresh, never blocks on waitForReady", async () => {
|
|
const service = new NostrService();
|
|
const ac = makeAccessControl({ hydrated: true, whitelist: true });
|
|
service.accessControl = ac;
|
|
await service.ensureAccessControlReady();
|
|
assert.equal(ac.calls.ensureReady, 1);
|
|
assert.equal(ac.calls.waitForReady, 0);
|
|
});
|
|
|
|
test("cold + whitelist mode => blocks on waitForReady (correctness)", async () => {
|
|
const service = new NostrService();
|
|
const ac = makeAccessControl({ hydrated: false, whitelist: true });
|
|
service.accessControl = ac;
|
|
await service.ensureAccessControlReady();
|
|
assert.equal(ac.calls.waitForReady, 1);
|
|
assert.equal(ac.calls.ensureReady, 0);
|
|
});
|
|
|
|
test("cold + blacklist-only mode => background refresh (no block)", async () => {
|
|
const service = new NostrService();
|
|
const ac = makeAccessControl({ hydrated: false, whitelist: false });
|
|
service.accessControl = ac;
|
|
await service.ensureAccessControlReady();
|
|
assert.equal(ac.calls.ensureReady, 1);
|
|
assert.equal(ac.calls.waitForReady, 0);
|
|
});
|
|
|
|
test("missing access control is a no-op", async () => {
|
|
const service = new NostrService();
|
|
service.accessControl = null;
|
|
await service.ensureAccessControlReady(); // must not throw
|
|
assert.ok(true);
|
|
});
|