Files
bitvid/scripts/check-direct-pool-access.mjs
T
thePR0M3TH3ANandClaude Opus 4.8 1fb6b86b7f feat(relay): add SubscriptionManager (L1) + direct-pool-access lint guard
P1 foundation of the data-flow refactor (docs/architecture-refactor.md):

- js/nostr/subscriptionManager.js: the single chokepoint for relay reads.
  Builds on relaySubscriptionService (dedup by key) and adds: health-gated
  default relays, deduped one-shot list() with timeout, and a reconnect
  registry that re-issues active subs centrally (instead of every subsystem
  re-subscribing on reconnect — the storm amplifier). Callers pass batched
  filters (one REQ for many ids), never per-item.
- Export RelaySubscriptionService class for test isolation.
- scripts/check-direct-pool-access.mjs + lint:pool-access: fail on NEW direct
  pool.sub/list usage; 12 grandfathered files listed as migration targets
  (allowlist may only shrink).

Nothing rewired yet — additive. Pilot (video feed) and per-subsystem
migration follow. Cheat-resistant tests included.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-14 10:11:43 -04:00

99 lines
3.5 KiB
JavaScript

#!/usr/bin/env node
/**
* Lint: enforce the SubscriptionManager (L1) chokepoint.
*
* Per docs/architecture-refactor.md, relay reads must go through
* js/nostr/subscriptionManager.js — nothing else should call pool.sub /
* pool.list / legacySub / legacyList / subscribeMap directly.
*
* Files that still do are GRANDFATHERED below; the allowlist must only SHRINK as
* phases migrate subsystems. A new file using direct pool access fails the lint;
* an allowlisted file is reported as a remaining migration target.
*
* Usage:
* node scripts/check-direct-pool-access.mjs # enforce (exit 1)
* node scripts/check-direct-pool-access.mjs --report # report only (exit 0)
*/
import { readFileSync, readdirSync, statSync } from "node:fs";
import { join, relative } from "node:path";
const ROOT = new URL("..", import.meta.url).pathname.replace(/\/$/, "");
const SOURCE_DIR = join(ROOT, "js");
// Patterns that indicate a direct relay-read outside L1.
const PATTERNS = [/\.pool\.sub\(/, /\.pool\.list\(/, /\blegacySub\(/, /\blegacyList\(/, /\bsubscribeMap\(/];
// The only modules allowed to touch the pool directly.
const L1_FILES = new Set([
"js/nostr/subscriptionManager.js",
"js/services/relaySubscriptionService.js",
"js/nostr/toolkit.js", // vendored pool shim (defines legacySub/legacyList)
"js/nostr/managers/ConnectionManager.js", // owns the pool lifecycle / health probe
]);
// Grandfathered: not yet migrated. SHRINK this list as phases land; do not grow.
const GRANDFATHERED = new Set([
"js/adminListStore.js",
"js/app.js",
"js/channelProfile.js",
"js/feedEngine/watchHistoryFeed.js",
"js/nostr/client.js",
"js/reactionCounter.js",
"js/relayManager.js",
"js/searchView.js",
"js/services/authService.js",
"js/services/dmNostrService.js",
"js/services/moderationService.js",
"js/services/nostrService.js",
]);
function collectJsFiles(dir) {
const out = [];
for (const entry of readdirSync(dir, { withFileTypes: true })) {
const full = join(dir, entry.name);
if (entry.isDirectory()) out.push(...collectJsFiles(full));
else if (entry.isFile() && entry.name.endsWith(".js")) out.push(full);
}
return out;
}
const reportOnly = process.argv.includes("--report");
const violations = [];
const remaining = [];
for (const filePath of collectJsFiles(SOURCE_DIR)) {
const rel = relative(ROOT, filePath);
if (rel.endsWith(".min.js") || L1_FILES.has(rel)) continue;
const content = readFileSync(filePath, "utf8");
if (!PATTERNS.some((re) => re.test(content))) continue;
if (GRANDFATHERED.has(rel)) remaining.push(rel);
else violations.push(rel);
}
// Allowlist entries that no longer need to be there (already migrated) — nudge.
const stale = [...GRANDFATHERED].filter(
(rel) => !remaining.includes(rel),
);
if (remaining.length) {
console.log(`\n${remaining.length} file(s) still using direct pool access (migration targets):`);
for (const r of remaining.sort()) console.log(` • ${r}`);
}
if (stale.length) {
console.log(`\n${stale.length} allowlist entr(y/ies) can be REMOVED (already migrated):`);
for (const r of stale.sort()) console.log(` ✓ ${r}`);
}
if (violations.length) {
console.error(`\n${violations.length} NEW direct pool access violation(s):`);
for (const v of violations.sort()) console.error(` ✗ ${v}`);
console.error(
"\nRoute relay reads through js/nostr/subscriptionManager.js (subscribe/list).",
);
if (!reportOnly) process.exit(1);
} else {
console.log("\nNo new direct pool access. (Allowlist must only shrink.)");
}