@nostr-wot/graph 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/storage.ts","../../src/graph.ts","../../src/crawl.ts","../../src/scoring.ts","../../src/wot-source.ts","../../src/wot-graph.ts","../../src/react/context.tsx"],"names":["_a","DEFAULT_MAX_HOPS","useWebSocketImplementation","RelayPool","SimplePool","createContext","useState","useMemo","useEffect","jsx","useContext","useRef","useCallback"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * IndexedDB storage for the local WoT graph.\n *\n * Ported from the extension (`lib/storage.ts`), generalized from per-account\n * databases to a `namespace` key and wrapped in a class so multiple graphs can\n * coexist. Preserves the two performance-critical techniques:\n *\n * - **Interning**: pubkeys (64-hex) are mapped to small integer ids, so the\n * graph is stored/traversed as numbers instead of strings.\n * - **Delta encoding**: each node's sorted follow-id list is stored as a\n * `Uint32Array` of deltas, which compresses well and keeps memory bounded for\n * the 100k+ nodes a 2-hop crawl can yield.\n *\n * When `indexedDB` is unavailable (Node without a polyfill) the store operates\n * in memory-only mode: crawl/query still work, nothing is persisted.\n */\n\nimport type { GraphMeta, StorageStats } from './types';\n\nconst DB_PREFIX = 'nostr-wot-graph';\nconst DB_VERSION = 1;\nconst STORE_PUBKEYS = 'pubkeys';\nconst STORE_FOLLOWS = 'follows';\nconst STORE_META = 'meta';\n\n// Encode follow ids for storage (sort + delta encode into a Uint32Array).\nexport function encodeFollows(followIds: ArrayLike<number>): ArrayBuffer {\n if (followIds.length === 0) return new ArrayBuffer(0);\n\n const sorted = Array.from(followIds).sort((a, b) => a - b);\n\n const deltas = new Uint32Array(sorted.length);\n deltas[0] = sorted[0];\n for (let i = 1; i < sorted.length; i++) {\n deltas[i] = sorted[i] - sorted[i - 1];\n }\n\n return deltas.buffer;\n}\n\n// Decode follow ids from storage (delta decode back to absolute values).\nexport function decodeFollows(buffer: ArrayBuffer | null | undefined): Uint32Array {\n if (!buffer || buffer.byteLength === 0) return new Uint32Array(0);\n\n const deltas = new Uint32Array(buffer);\n const result = new Uint32Array(deltas.length);\n\n result[0] = deltas[0];\n for (let i = 1; i < deltas.length; i++) {\n result[i] = result[i - 1] + deltas[i];\n }\n\n return result;\n}\n\nfunction hasIndexedDB(): boolean {\n return typeof indexedDB !== 'undefined' && indexedDB !== null;\n}\n\nexport class GraphStorage {\n readonly namespace: string;\n private db: IDBDatabase | null = null;\n private memoryOnly = false;\n private opened = false;\n\n // In-memory caches (source of truth for reads/BFS).\n private pubkeyToId = new Map<string, number>();\n private idToPubkey = new Map<number, string>();\n private nextId = 1;\n private graphCache = new Map<number, Uint32Array>();\n private metaCache = new Map<string, unknown>();\n\n // Pending persistence buffers (drained by flush()).\n private dirtyFollows = new Map<number, number[]>();\n private dirtyPubkeys: Array<{ id: number; pubkey: string }> = [];\n\n constructor(namespace: string) {\n if (!namespace) throw new Error('GraphStorage requires a namespace');\n this.namespace = namespace;\n }\n\n private dbName(): string {\n return `${DB_PREFIX}:${this.namespace}`;\n }\n\n /** Open (or create) the namespace DB and hydrate in-memory caches. */\n async open(): Promise<void> {\n if (this.opened) return;\n\n if (!hasIndexedDB()) {\n this.memoryOnly = true;\n this.opened = true;\n return;\n }\n\n await new Promise<void>((resolve, reject) => {\n const request = indexedDB.open(this.dbName(), DB_VERSION);\n request.onerror = () => reject(request.error);\n request.onupgradeneeded = (event) => {\n const database = (event.target as IDBOpenDBRequest).result;\n if (!database.objectStoreNames.contains(STORE_PUBKEYS)) {\n const store = database.createObjectStore(STORE_PUBKEYS, { keyPath: 'id' });\n store.createIndex('pubkey', 'pubkey', { unique: true });\n }\n if (!database.objectStoreNames.contains(STORE_FOLLOWS)) {\n database.createObjectStore(STORE_FOLLOWS, { keyPath: 'id' });\n }\n if (!database.objectStoreNames.contains(STORE_META)) {\n database.createObjectStore(STORE_META, { keyPath: 'key' });\n }\n };\n request.onsuccess = () => {\n this.db = request.result;\n resolve();\n };\n });\n\n this.opened = true;\n await this.loadAll();\n }\n\n /** Hydrate the in-memory interning + follow maps + meta from the DB. */\n async loadAll(): Promise<void> {\n this.pubkeyToId.clear();\n this.idToPubkey.clear();\n this.graphCache.clear();\n this.metaCache.clear();\n this.nextId = 1;\n\n if (this.memoryOnly || !this.db) return;\n const db = this.db;\n\n const pubkeys = await this.getAll<{ id: number; pubkey: string }>(db, STORE_PUBKEYS);\n for (const record of pubkeys) {\n this.pubkeyToId.set(record.pubkey, record.id);\n this.idToPubkey.set(record.id, record.pubkey);\n if (record.id >= this.nextId) this.nextId = record.id + 1;\n }\n\n const follows = await this.getAll<{ id: number; follows: ArrayBuffer }>(db, STORE_FOLLOWS);\n for (const record of follows) {\n this.graphCache.set(record.id, decodeFollows(record.follows));\n }\n\n const meta = await this.getAll<{ key: string; value: unknown }>(db, STORE_META);\n for (const record of meta) {\n this.metaCache.set(record.key, record.value);\n }\n }\n\n private getAll<T>(db: IDBDatabase, store: string): Promise<T[]> {\n return new Promise((resolve, reject) => {\n const tx = db.transaction(store, 'readonly');\n const request = tx.objectStore(store).getAll();\n request.onsuccess = () => resolve(request.result as T[]);\n request.onerror = () => reject(request.error);\n });\n }\n\n // ── Interning ──\n\n /** Numeric id for a pubkey, or null if never seen. */\n getId(pubkey: string): number | null {\n return this.pubkeyToId.get(pubkey) ?? null;\n }\n\n /** Numeric id for a pubkey, minting and buffering a new one if needed. */\n getOrCreateId(pubkey: string): number {\n const existing = this.pubkeyToId.get(pubkey);\n if (existing !== undefined) return existing;\n\n const id = this.nextId++;\n this.pubkeyToId.set(pubkey, id);\n this.idToPubkey.set(id, pubkey);\n this.dirtyPubkeys.push({ id, pubkey });\n return id;\n }\n\n /** Batch variant of {@link getOrCreateId}. */\n getOrCreateIds(pubkeys: string[]): number[] {\n const ids = new Array<number>(pubkeys.length);\n for (let i = 0; i < pubkeys.length; i++) {\n ids[i] = this.getOrCreateId(pubkeys[i]);\n }\n return ids;\n }\n\n /** Pubkey for a numeric id, or null. */\n getHex(id: number): string | null {\n return this.idToPubkey.get(id) ?? null;\n }\n\n /** Highest assigned id (for typed-array sizing). */\n getMaxId(): number {\n return this.nextId - 1;\n }\n\n // ── Follows ──\n\n /** Store `pubkey`'s follow list. Interns everything and updates the cache. */\n saveFollows(pubkey: string, follows: string[]): void {\n const id = this.getOrCreateId(pubkey);\n const followIds = this.getOrCreateIds(follows);\n this.graphCache.set(id, new Uint32Array(followIds));\n this.dirtyFollows.set(id, followIds);\n }\n\n /** Follow ids for a node id — sync, from the in-memory cache. */\n getFollowIdsSync(id: number): Uint32Array {\n return this.graphCache.get(id) ?? new Uint32Array(0);\n }\n\n /** Follow ids for a pubkey (interned). Empty if unknown. */\n getFollowIds(pubkey: string): Uint32Array {\n const id = this.getId(pubkey);\n if (id === null) return new Uint32Array(0);\n return this.getFollowIdsSync(id);\n }\n\n /** Follow list of `pubkey` as hex strings. */\n getFollows(pubkey: string): string[] {\n const ids = this.getFollowIds(pubkey);\n const out: string[] = [];\n for (let i = 0; i < ids.length; i++) {\n const hex = this.getHex(ids[i]);\n if (hex) out.push(hex);\n }\n return out;\n }\n\n // ── Meta ──\n\n async setMeta(key: string, value: unknown): Promise<void> {\n this.metaCache.set(key, value);\n if (this.memoryOnly || !this.db) return;\n const db = this.db;\n await new Promise<void>((resolve, reject) => {\n const tx = db.transaction(STORE_META, 'readwrite');\n tx.objectStore(STORE_META).put({ key, value });\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n }\n\n getMeta<T = unknown>(key: string): T | undefined {\n return this.metaCache.get(key) as T | undefined;\n }\n\n /** Read the structured graph meta record. */\n getGraphMeta(): GraphMeta {\n return {\n root: (this.getMeta<string>('root') ?? null) as string | null,\n lastCrawl: (this.getMeta<number>('lastCrawl') ?? null) as number | null,\n maxDepth: (this.getMeta<number>('maxDepth') ?? null) as number | null,\n version: this.getMeta<number>('version') ?? DB_VERSION,\n };\n }\n\n // ── Persistence ──\n\n /** Flush buffered pubkey + follow writes to IndexedDB. No-op in memory mode. */\n async flush(): Promise<void> {\n if (this.memoryOnly || !this.db) {\n this.dirtyPubkeys.length = 0;\n this.dirtyFollows.clear();\n return;\n }\n const db = this.db;\n\n const pubkeys = this.dirtyPubkeys.splice(0, this.dirtyPubkeys.length);\n const follows = Array.from(this.dirtyFollows.entries());\n this.dirtyFollows.clear();\n\n if (pubkeys.length === 0 && follows.length === 0) return;\n\n await new Promise<void>((resolve, reject) => {\n const stores: string[] = [];\n if (pubkeys.length) stores.push(STORE_PUBKEYS);\n if (follows.length) stores.push(STORE_FOLLOWS);\n const tx = db.transaction(stores, 'readwrite');\n\n if (pubkeys.length) {\n const store = tx.objectStore(STORE_PUBKEYS);\n for (const row of pubkeys) store.put(row);\n }\n if (follows.length) {\n const store = tx.objectStore(STORE_FOLLOWS);\n for (const [id, followIds] of follows) {\n store.put({ id, follows: encodeFollows(followIds), updated_at: Date.now() });\n }\n }\n\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n }\n\n // ── Stats / clear ──\n\n stats(): StorageStats {\n let edges = 0;\n for (const follows of this.graphCache.values()) edges += follows.length;\n return {\n nodes: this.graphCache.size,\n edges,\n uniquePubkeys: this.pubkeyToId.size,\n };\n }\n\n /** Wipe this namespace: memory caches + persisted stores. */\n async clear(): Promise<void> {\n this.pubkeyToId.clear();\n this.idToPubkey.clear();\n this.graphCache.clear();\n this.metaCache.clear();\n this.dirtyFollows.clear();\n this.dirtyPubkeys.length = 0;\n this.nextId = 1;\n\n if (this.memoryOnly || !this.db) return;\n const db = this.db;\n await new Promise<void>((resolve, reject) => {\n const tx = db.transaction([STORE_FOLLOWS, STORE_PUBKEYS, STORE_META], 'readwrite');\n tx.objectStore(STORE_FOLLOWS).clear();\n tx.objectStore(STORE_PUBKEYS).clear();\n tx.objectStore(STORE_META).clear();\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /** Close the underlying DB connection. */\n close(): void {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n this.opened = false;\n }\n}\n","/**\n * In-memory BFS over the hydrated follow graph.\n *\n * Ported from the extension (`lib/graph.ts`, `LocalGraph`). Given the interned\n * follow map (from {@link GraphStorage}) and a root pubkey, a single BFS pass\n * fills two typed arrays indexed by node id:\n *\n * - `hops` (`Uint8Array`) — distance from root, stored as `hop + 1` so `0`\n * means \"not reached\" (255 max).\n * - `paths` (`Uint32Array`) — count of shortest paths to each node.\n *\n * The cache is keyed by root and invalidated on crawl / root change / clear.\n */\n\nimport type { GraphStorage } from './storage';\nimport type { DistanceInfo } from './types';\n\ninterface BfsCache {\n rootId: number;\n hops: Uint8Array;\n paths: Uint32Array;\n maxId: number;\n}\n\nconst DEFAULT_MAX_HOPS = 6;\n\nexport class LocalGraph {\n private storage: GraphStorage;\n private cache: BfsCache | null = null;\n private cachedRoot: string | null = null;\n\n constructor(storage: GraphStorage) {\n this.storage = storage;\n }\n\n /** Invalidate the precomputed cache (called on crawl / root change / clear). */\n invalidateCache(): void {\n this.cache = null;\n this.cachedRoot = null;\n }\n\n /**\n * Precompute hops and paths from a root pubkey using a single BFS pass.\n * Results stored in typed arrays indexed by node id for O(1) lookup.\n */\n private buildCache(rootPubkey: string, maxHops: number = DEFAULT_MAX_HOPS): void {\n const rootId = this.storage.getId(rootPubkey);\n if (rootId === null) {\n this.cache = null;\n this.cachedRoot = null;\n return;\n }\n\n const maxId = this.storage.getMaxId();\n // Uint8Array: 0 = unreachable, 1-255 = hop distance. Store hop+1 so 0 means \"not reached\".\n const hops = new Uint8Array(maxId + 1);\n const paths = new Uint32Array(maxId + 1);\n\n // Root: distance 0, 1 path\n hops[rootId] = 1; // stored as hop+1\n paths[rootId] = 1;\n\n let frontier: number[] = [rootId];\n let hop = 0;\n\n while (frontier.length > 0 && hop < maxHops) {\n hop++;\n const hopStored = hop + 1;\n const nextFrontier: number[] = [];\n\n for (let f = 0; f < frontier.length; f++) {\n const nodeId = frontier[f];\n const nodePaths = paths[nodeId];\n const followIds = this.storage.getFollowIdsSync(nodeId);\n\n for (let i = 0; i < followIds.length; i++) {\n const fid = followIds[i];\n if (fid > maxId) continue; // safety guard\n\n if (hops[fid] === 0) {\n // First discovery\n hops[fid] = hopStored;\n paths[fid] = nodePaths;\n nextFrontier.push(fid);\n } else if (hops[fid] === hopStored) {\n // Same-level rediscovery -- accumulate paths\n paths[fid] += nodePaths;\n }\n // If hops[fid] < hopStored, it was found at a closer level -- ignore\n }\n }\n\n frontier = nextFrontier;\n }\n\n this.cache = { rootId, hops, paths, maxId };\n this.cachedRoot = rootPubkey;\n }\n\n /** Ensure the cache is built for `root`. */\n private ensureCache(root: string, maxHops: number): void {\n if (this.cachedRoot !== root || !this.cache) {\n this.buildCache(root, maxHops);\n }\n }\n\n /**\n * Distance info from `root` to `pubkey`. Returns `{ hops, paths }`, or `null`\n * when unreached / unknown. Self → `{ hops: 0, paths: 1 }`.\n */\n getDistance(root: string, pubkey: string, maxHops: number = DEFAULT_MAX_HOPS): DistanceInfo | null {\n if (root === pubkey) return { hops: 0, paths: 1 };\n\n this.ensureCache(root, maxHops);\n if (!this.cache || this.cachedRoot !== root) return null;\n\n const toId = this.storage.getId(pubkey);\n if (toId === null || toId > this.cache.maxId) return null;\n\n const h = this.cache.hops[toId];\n if (h === 0) return null; // unreachable\n\n return { hops: h - 1, paths: this.cache.paths[toId] };\n }\n\n /** Follow list of `pubkey` as hex strings. */\n getFollows(pubkey: string): string[] {\n return this.storage.getFollows(pubkey);\n }\n}\n","/**\n * BFS crawler for kind:3 contact lists.\n *\n * Ported from the extension (`lib/sync.ts`, `GraphSync`) but with the raw\n * `WebSocket` transport replaced by `@nostr-wot/relay`'s pool. The pool handles\n * connection/reconnect across relays; this class keeps the proven crawl logic:\n *\n * - BFS by depth: fetch the root's kind:3, enqueue its follows for the next\n * depth, and so on up to `maxDepth`.\n * - Newest-per-author: for each pubkey, take the kind:3 event with the highest\n * `created_at` seen across relays.\n * - Rate limiting: a base delay between dispatches and a max-concurrent cap.\n * - Tolerates unreachable relays; throws `CrawlError` only when zero relays are\n * configured to connect.\n * - Abortable via `signal` or `stop()`; a stopped crawl leaves partial data\n * usable and reports `stoppedEarly: true`.\n */\n\nimport type { GraphStorage } from './storage';\nimport type { CrawlOptions, CrawlResult } from './types';\n\n// Minimal relay-pool surface the crawler needs. `@nostr-wot/relay`'s `RelayPool`\n// (its `subscribe(filter, { onEvent, onEose })`) is structurally assignable.\nexport interface CrawlSubCloser {\n close(): void;\n}\nexport interface CrawlEvent {\n created_at: number;\n tags: string[][];\n [key: string]: unknown;\n}\nexport interface CrawlPool {\n subscribe(\n filter: { kinds?: number[]; authors?: string[]; limit?: number; [key: string]: unknown },\n handlers: {\n onEvent: (e: CrawlEvent) => void;\n onEose?: () => void;\n onStatus?: (s: string) => void;\n },\n ): CrawlSubCloser;\n getConnectedCount?(): number;\n}\n\nexport interface GraphCrawlerOptions {\n pool: CrawlPool;\n storage: GraphStorage;\n relays: string[];\n /** Base delay (ms) between fetch dispatches. Default 50. */\n baseDelayMs?: number;\n /** Max concurrent in-flight fetches. Default 5. */\n maxConcurrent?: number;\n /** Per-pubkey response timeout (ms). Default 10000. */\n requestTimeoutMs?: number;\n}\n\nexport class CrawlError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'CrawlError';\n }\n}\n\nconst DEFAULT_MAX_DEPTH = 2;\n\nexport class GraphCrawler {\n private pool: CrawlPool;\n private storage: GraphStorage;\n private relays: string[];\n private baseDelayMs: number;\n private maxConcurrent: number;\n private requestTimeoutMs: number;\n private aborted = false;\n\n constructor(options: GraphCrawlerOptions) {\n this.pool = options.pool;\n this.storage = options.storage;\n this.relays = options.relays;\n this.baseDelayMs = options.baseDelayMs ?? 50;\n this.maxConcurrent = options.maxConcurrent ?? 5;\n this.requestTimeoutMs = options.requestTimeoutMs ?? 10000;\n }\n\n /** Abort an in-flight crawl. */\n stop(): void {\n this.aborted = true;\n }\n\n async crawl(rootPubkey: string, opts: CrawlOptions = {}): Promise<CrawlResult> {\n if (this.relays.length === 0) {\n throw new CrawlError('no relays connected');\n }\n\n const maxDepth = opts.maxDepth ?? DEFAULT_MAX_DEPTH;\n const start = Date.now();\n this.aborted = false;\n\n const signal = opts.signal;\n const onAbort = () => this.stop();\n if (signal) {\n if (signal.aborted) this.aborted = true;\n else signal.addEventListener('abort', onAbort);\n }\n\n const fetched = new Set<string>();\n const failed = new Set<string>();\n const seen = new Set<string>([rootPubkey]);\n let currentLevel: string[] = [rootPubkey];\n let reachedDepth = 0;\n let stoppedEarly = false;\n\n try {\n for (let depth = 0; depth <= maxDepth; depth++) {\n if (currentLevel.length === 0) break;\n if (this.aborted) {\n stoppedEarly = true;\n break;\n }\n\n const nextSet = new Set<string>();\n\n await this.mapLimited(currentLevel, async (pubkey) => {\n if (this.aborted) return;\n const follows = await this.fetchNewest(pubkey);\n if (this.aborted) return;\n\n if (follows === null) {\n failed.add(pubkey);\n } else {\n fetched.add(pubkey);\n reachedDepth = Math.max(reachedDepth, depth);\n this.storage.saveFollows(pubkey, follows);\n if (depth < maxDepth) {\n for (const f of follows) {\n if (!seen.has(f)) {\n seen.add(f);\n nextSet.add(f);\n }\n }\n }\n }\n\n opts.onProgress?.({ depth, fetched: fetched.size, queued: nextSet.size });\n });\n\n if (this.aborted) {\n stoppedEarly = true;\n break;\n }\n\n currentLevel = Array.from(nextSet);\n }\n } finally {\n if (signal) signal.removeEventListener('abort', onAbort);\n await this.storage.flush();\n }\n\n const stats = this.storage.stats();\n return {\n fetched: fetched.size,\n nodes: stats.nodes,\n edges: stats.edges,\n depth: reachedDepth,\n durationMs: Date.now() - start,\n stoppedEarly,\n };\n }\n\n /**\n * Fetch a single pubkey's newest kind:3 follow list across relays.\n * Resolves to the follow pubkeys, or `null` if no event arrived.\n */\n private fetchNewest(pubkey: string): Promise<string[] | null> {\n return new Promise((resolve) => {\n let newestAt = 0;\n let follows: string[] | null = null;\n let settled = false;\n let sub: CrawlSubCloser | null = null;\n\n const finish = () => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n try {\n sub?.close();\n } catch {\n /* ignore */\n }\n resolve(follows);\n };\n\n const timer = setTimeout(finish, this.requestTimeoutMs);\n\n sub = this.pool.subscribe(\n { kinds: [3], authors: [pubkey], limit: 1 },\n {\n onEvent: (ev: CrawlEvent) => {\n if (ev && ev.created_at > newestAt) {\n newestAt = ev.created_at;\n follows = (ev.tags || [])\n .filter((tag) => tag[0] === 'p' && tag[1])\n .map((tag) => tag[1]);\n }\n },\n onEose: finish,\n },\n );\n\n // Guard: a synchronous mock that resolved before assigning `sub` above.\n if (settled) {\n try {\n sub?.close();\n } catch {\n /* ignore */\n }\n }\n });\n }\n\n /**\n * Run `worker` over `items` with a max-concurrency cap and a base delay\n * before each dispatch (preserving the crawler's per-relay rate limiting\n * intent, now applied at the pool boundary).\n */\n private async mapLimited<T>(items: T[], worker: (item: T) => Promise<void>): Promise<void> {\n let index = 0;\n const runNext = async (): Promise<void> => {\n while (index < items.length) {\n if (this.aborted) return;\n const item = items[index++];\n if (this.baseDelayMs > 0) {\n await new Promise((r) => setTimeout(r, this.baseDelayMs));\n }\n if (this.aborted) return;\n await worker(item);\n }\n };\n\n const lanes = Math.min(this.maxConcurrent, Math.max(1, items.length));\n await Promise.all(Array.from({ length: lanes }, () => runNext()));\n }\n}\n","/**\n * Centralized trust score calculation.\n *\n * Formula: score = base + pathBonus (capped at maxPathBonus)\n *\n * Where:\n * - base: base score per hop distance (1 hop = 100%, 2 hops = 50%, etc.)\n * - pathBonus: bonus based on number of shortest paths, capped at maxPathBonus\n *\n * Ported verbatim from the extension (`lib/scoring.ts`).\n */\n\nimport type { ScoringConfig } from './types';\n\nexport const DEFAULT_SCORING: ScoringConfig = {\n distanceWeights: { 1: 1.0, 2: 0.5, 3: 0.25, 4: 0.1 },\n pathBonus: { 2: 0.15, 3: 0.1, 4: 0.05 },\n maxPathBonus: 0.5,\n};\n\n/**\n * Calculate trust score from hops and path count.\n *\n * @param hops - Number of hops (0 = self, 1 = direct follow, etc.)\n * @param paths - Number of shortest paths (null if unknown)\n * @param scoring - Scoring configuration\n * @returns Score between 0 and 1\n */\nexport function calculateScore(\n hops: number | null | undefined,\n paths: number | null,\n scoring: ScoringConfig = DEFAULT_SCORING,\n): number {\n // Self = maximum trust\n if (hops === 0) return 1.0;\n\n // Not connected\n if (hops === null || hops === undefined) return 0;\n\n const { distanceWeights, pathBonus, maxPathBonus } = scoring;\n\n // Get base score for this hop distance (use hop 4 for anything beyond)\n const hopKey = Math.min(hops, 4);\n const base = distanceWeights?.[hopKey] ?? DEFAULT_SCORING.distanceWeights[hopKey] ?? 0.1;\n\n // Calculate path bonus (only for hops > 1 with multiple paths)\n let bonus = 0;\n if (paths !== null && paths > 1 && hops > 1) {\n // Get path bonus for this hop level\n let pathBonusValue: number;\n if (typeof pathBonus === 'object') {\n pathBonusValue = pathBonus[hopKey] ?? DEFAULT_SCORING.pathBonus[hopKey] ?? 0.05;\n } else {\n // Legacy single value\n pathBonusValue = (pathBonus as unknown as number) ?? 0.1;\n }\n // Bonus = pathBonusValue * (paths - 1), capped at maxPathBonus\n bonus = Math.min(pathBonusValue * (paths - 1), maxPathBonus ?? 0.5);\n }\n\n // Final score: base + pathBonus (capped)\n const score = base + bonus;\n\n // Clamp to [0, 1]\n return Math.min(Math.max(score, 0), 1);\n}\n","/**\n * Adapter turning a {@link WotGraph} into the small `WoTLocalSource` shape that\n * `@nostr-wot/wot`'s `WoT` class can consume as a local query source instead of\n * the remote Oracle.\n */\n\nimport type { FilterByWoTOptions, WoTLocalSource } from './types';\n\n/** Minimal surface {@link createWoTSource} needs from a graph. */\nexport interface WoTSourceGraph {\n getDistance(pubkey: string): { hops: number; paths: number } | null;\n isInWoT(pubkey: string, maxHops?: number): boolean;\n filterByWoT(pubkeys: string[], opts?: FilterByWoTOptions): string[];\n}\n\nexport function createWoTSource(graph: WoTSourceGraph): WoTLocalSource {\n return {\n getDistance(target: string): number | null {\n const info = graph.getDistance(target);\n return info ? info.hops : null;\n },\n isInMyWoT(target: string, maxHops?: number): boolean {\n return graph.isInWoT(target, maxHops);\n },\n filterByWoT(pubkeys: string[], opts?: FilterByWoTOptions): string[] {\n return graph.filterByWoT(pubkeys, opts);\n },\n };\n}\n","/**\n * `WotGraph` — the primary public entry point.\n *\n * Ties the four internal layers together: a namespaced {@link GraphStorage},\n * a BFS {@link LocalGraph}, a {@link GraphCrawler}, and the pure scoring\n * function. Consumers create one per origin/app, `load()` to rehydrate any\n * cached graph, `crawl()` to build/refresh it, then run O(1)/O(n) queries.\n */\n\nimport { RelayPool } from '@nostr-wot/relay';\nimport { SimplePool } from 'nostr-tools';\nimport { useWebSocketImplementation } from 'nostr-tools/pool';\n\nimport { GraphStorage } from './storage';\nimport { LocalGraph } from './graph';\nimport { GraphCrawler, CrawlError, type CrawlPool } from './crawl';\nimport { calculateScore, DEFAULT_SCORING } from './scoring';\nimport { createWoTSource } from './wot-source';\nimport type {\n CrawlOptions,\n CrawlResult,\n DistanceInfo,\n FilterByWoTOptions,\n ScoringConfig,\n WebSocketLike,\n WoTLocalSource,\n} from './types';\n\nexport interface WotGraphOptions {\n /** IndexedDB partition key (e.g. the app name). */\n namespace: string;\n /** Relay URLs to crawl. */\n relays: string[];\n /** Optional shared pool; if omitted one is created from `relays`. */\n pool?: CrawlPool;\n /** Scoring overrides merged onto {@link DEFAULT_SCORING}. */\n scoring?: Partial<ScoringConfig>;\n /** WebSocket implementation forwarded to the created pool. */\n websocketImplementation?: WebSocketLike;\n}\n\nexport interface WotGraphStats {\n nodes: number;\n edges: number;\n root: string | null;\n lastCrawl: number | null;\n maxDepth: number | null;\n}\n\nconst DEFAULT_MAX_HOPS = 2;\nconst STORAGE_VERSION = 1;\n\nexport class WotGraph {\n readonly namespace: string;\n private relays: string[];\n private scoring: ScoringConfig;\n private websocketImplementation?: WebSocketLike;\n\n private storage: GraphStorage;\n private graph: LocalGraph;\n\n private pool: CrawlPool | null;\n private ownPool: RelayPool | null = null;\n private crawler: GraphCrawler | null = null;\n\n private root: string | null = null;\n private inFlight: Promise<CrawlResult> | null = null;\n private controller: AbortController | null = null;\n private listeners = new Set<() => void>();\n\n constructor(options: WotGraphOptions) {\n this.namespace = options.namespace;\n this.relays = [...options.relays];\n this.scoring = mergeScoring(options.scoring);\n this.websocketImplementation = options.websocketImplementation;\n this.pool = options.pool ?? null;\n\n this.storage = new GraphStorage(this.namespace);\n this.graph = new LocalGraph(this.storage);\n }\n\n /** Hydrate any cached graph from IndexedDB (fast path). */\n async load(): Promise<void> {\n await this.storage.open();\n this.root = this.storage.getGraphMeta().root;\n this.graph.invalidateCache();\n this.notify();\n }\n\n /**\n * Build/refresh the graph by crawling kind:3 from `rootPubkey`.\n * Concurrent calls return the same in-flight promise (idempotent).\n */\n crawl(rootPubkey: string, opts: CrawlOptions = {}): Promise<CrawlResult> {\n // Synchronous single-flight guard: a second crawl() while one is in flight\n // returns the same promise (idempotent — React strict-mode safe).\n if (this.inFlight) return this.inFlight;\n\n this.controller = new AbortController();\n if (opts.signal) {\n if (opts.signal.aborted) this.controller.abort();\n else opts.signal.addEventListener('abort', () => this.controller?.abort(), { once: true });\n }\n this.root = rootPubkey;\n\n const run = (async (): Promise<CrawlResult> => {\n try {\n await this.storage.open();\n const pool = this.resolvePool();\n this.crawler = new GraphCrawler({ pool, storage: this.storage, relays: this.relays });\n const result = await this.crawler.crawl(rootPubkey, {\n maxDepth: opts.maxDepth,\n onProgress: opts.onProgress,\n signal: this.controller!.signal,\n });\n await this.storage.setMeta('root', rootPubkey);\n await this.storage.setMeta('lastCrawl', Date.now());\n await this.storage.setMeta('maxDepth', opts.maxDepth ?? DEFAULT_MAX_HOPS);\n await this.storage.setMeta('version', STORAGE_VERSION);\n this.graph.invalidateCache();\n this.notify();\n return result;\n } finally {\n this.inFlight = null;\n this.crawler = null;\n this.controller = null;\n }\n })();\n\n this.inFlight = run;\n return run;\n }\n\n /** Distance info from the crawled root, or `null` if unreached/unknown. */\n getDistance(pubkey: string): DistanceInfo | null {\n if (!this.root) return null;\n return this.graph.getDistance(this.root, pubkey);\n }\n\n /** Trust score 0..1 via {@link calculateScore}. */\n getScore(pubkey: string): number {\n const info = this.getDistance(pubkey);\n return calculateScore(info ? info.hops : null, info ? info.paths : null, this.scoring);\n }\n\n /** Whether `pubkey` is within `maxHops` of the root. */\n isInWoT(pubkey: string, maxHops: number = DEFAULT_MAX_HOPS): boolean {\n const info = this.getDistance(pubkey);\n return info !== null && info.hops <= maxHops;\n }\n\n /** Trusted subset of `pubkeys`, sorted by score descending. */\n filterByWoT(pubkeys: string[], opts?: FilterByWoTOptions): string[] {\n const maxHops = opts?.maxHops ?? DEFAULT_MAX_HOPS;\n const scored: Array<{ pubkey: string; score: number }> = [];\n for (const pubkey of pubkeys) {\n const info = this.getDistance(pubkey);\n if (info !== null && info.hops <= maxHops) {\n scored.push({ pubkey, score: calculateScore(info.hops, info.paths, this.scoring) });\n }\n }\n scored.sort((a, b) => b.score - a.score);\n return scored.map((s) => s.pubkey);\n }\n\n /** Follow list of `pubkey` as hex strings. */\n getFollows(pubkey: string): string[] {\n return this.graph.getFollows(pubkey);\n }\n\n /** Aggregate stats + crawl meta. */\n stats(): WotGraphStats {\n const s = this.storage.stats();\n const meta = this.storage.getGraphMeta();\n return {\n nodes: s.nodes,\n edges: s.edges,\n root: meta.root,\n lastCrawl: meta.lastCrawl,\n maxDepth: meta.maxDepth,\n };\n }\n\n /** True if the last crawl is older than `ttlMs` (or never happened). */\n isStale(ttlMs: number): boolean {\n const last = this.storage.getGraphMeta().lastCrawl;\n if (last === null) return true;\n return Date.now() - last > ttlMs;\n }\n\n /** Wipe this namespace. */\n async clear(): Promise<void> {\n await this.storage.clear();\n this.root = null;\n this.graph.invalidateCache();\n this.notify();\n }\n\n /** Abort an in-flight crawl. Partial data stays usable. */\n stop(): void {\n this.controller?.abort();\n this.crawler?.stop();\n }\n\n /** Adapter for `@nostr-wot/wot`'s `WoT` class. */\n asWoTSource(): WoTLocalSource {\n return createWoTSource(this);\n }\n\n /** The root pubkey the graph is currently answering queries from. */\n getRoot(): string | null {\n return this.root;\n }\n\n /** Subscribe to graph changes (crawl / load / clear). Returns an unsubscribe. */\n onChange(cb: () => void): () => void {\n this.listeners.add(cb);\n return () => this.listeners.delete(cb);\n }\n\n /** Release the pool/storage this instance owns. */\n destroy(): void {\n this.storage.close();\n if (this.ownPool) {\n this.ownPool.destroy();\n this.ownPool = null;\n }\n }\n\n private notify(): void {\n for (const cb of this.listeners) cb();\n }\n\n private resolvePool(): CrawlPool {\n if (this.pool) return this.pool;\n if (this.relays.length === 0) throw new CrawlError('no relays connected');\n if (this.websocketImplementation) {\n useWebSocketImplementation(this.websocketImplementation);\n }\n const rp = new RelayPool({ urls: this.relays });\n rp.ensurePool(() => new SimplePool());\n this.ownPool = rp;\n // RelayPool.subscribe(filter, { onEvent, onEose }) is structurally compatible.\n this.pool = rp as unknown as CrawlPool;\n return this.pool;\n }\n}\n\nfunction mergeScoring(overrides?: Partial<ScoringConfig>): ScoringConfig {\n if (!overrides) return { ...DEFAULT_SCORING };\n return {\n distanceWeights: { ...DEFAULT_SCORING.distanceWeights, ...overrides.distanceWeights },\n pathBonus: { ...DEFAULT_SCORING.pathBonus, ...overrides.pathBonus },\n maxPathBonus: overrides.maxPathBonus ?? DEFAULT_SCORING.maxPathBonus,\n };\n}\n","import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport { WotGraph, type WotGraphOptions } from '../wot-graph';\nimport type { CrawlOptions, CrawlProgress, CrawlResult, DistanceInfo } from '../types';\n\nexport interface WotGraphProviderProps extends WotGraphOptions {\n children: ReactNode;\n}\n\nexport interface WotGraphContextValue {\n graph: WotGraph;\n ready: boolean;\n crawling: boolean;\n setCrawling: (v: boolean) => void;\n /** Bumps whenever the graph changes (crawl / load / clear). */\n version: number;\n}\n\nconst WotGraphContext = createContext<WotGraphContextValue | null>(null);\n\n/**\n * Constructs and holds a {@link WotGraph}, calling `load()` on mount.\n *\n * @example\n * ```tsx\n * <WotGraphProvider namespace=\"myapp\" relays={[\"wss://relay.damus.io\"]}>\n * <App />\n * </WotGraphProvider>\n * ```\n */\nexport function WotGraphProvider({ children, ...options }: WotGraphProviderProps) {\n const [ready, setReady] = useState(false);\n const [crawling, setCrawling] = useState(false);\n const [version, setVersion] = useState(0);\n\n // Instance is stable for the provider lifetime.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const graph = useMemo(() => new WotGraph(options), []);\n\n useEffect(() => {\n let mounted = true;\n const unsub = graph.onChange(() => {\n if (mounted) setVersion((v) => v + 1);\n });\n graph\n .load()\n .catch(() => {\n /* keep ready=true so queries can still run on an empty graph */\n })\n .finally(() => {\n if (mounted) setReady(true);\n });\n return () => {\n mounted = false;\n unsub();\n graph.stop();\n graph.destroy();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const value = useMemo<WotGraphContextValue>(\n () => ({ graph, ready, crawling, setCrawling, version }),\n [graph, ready, crawling, version],\n );\n\n return <WotGraphContext.Provider value={value}>{children}</WotGraphContext.Provider>;\n}\n\nfunction useWotGraphContext(): WotGraphContextValue {\n const ctx = useContext(WotGraphContext);\n if (!ctx) throw new Error('useWotGraph must be used within a WotGraphProvider');\n return ctx;\n}\n\n/** The {@link WotGraph} instance plus `{ ready, crawling }` state. */\nexport function useWotGraph(): {\n graph: WotGraph;\n ready: boolean;\n crawling: boolean;\n} {\n const { graph, ready, crawling } = useWotGraphContext();\n return { graph, ready, crawling };\n}\n\n/** `{ hops, paths } | null` for a pubkey; recomputes when the graph changes. */\nexport function useDistance(pubkey: string | null | undefined): DistanceInfo | null {\n const { graph, version } = useWotGraphContext();\n return useMemo(\n () => (pubkey ? graph.getDistance(pubkey) : null),\n // version participates so queries refresh after a crawl.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [graph, pubkey, version],\n );\n}\n\n/** `{ crawl, stop, progress, crawling, error }` for driving a crawl from UI. */\nexport function useCrawl(): {\n crawl: (rootPubkey: string, opts?: CrawlOptions) => Promise<CrawlResult | null>;\n stop: () => void;\n progress: CrawlProgress | null;\n crawling: boolean;\n error: Error | null;\n} {\n const { graph, crawling, setCrawling } = useWotGraphContext();\n const [progress, setProgress] = useState<CrawlProgress | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const mounted = useRef(true);\n\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n\n const crawl = useCallback(\n async (rootPubkey: string, opts?: CrawlOptions): Promise<CrawlResult | null> => {\n setError(null);\n setCrawling(true);\n try {\n const result = await graph.crawl(rootPubkey, {\n ...opts,\n onProgress: (p) => {\n if (mounted.current) setProgress(p);\n opts?.onProgress?.(p);\n },\n });\n return result;\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n if (mounted.current) setError(e);\n return null;\n } finally {\n if (mounted.current) setCrawling(false);\n }\n },\n [graph, setCrawling],\n );\n\n const stop = useCallback(() => graph.stop(), [graph]);\n\n return { crawl, stop, progress, crawling, error };\n}\n"]}
@@ -0,0 +1,247 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ /**
5
+ * Trust-score configuration. Ported verbatim from the extension.
6
+ */
7
+ interface ScoringConfig {
8
+ /** Base score per hop distance, e.g. `{ 1: 1.0, 2: 0.5, 3: 0.25, 4: 0.1 }`. */
9
+ distanceWeights: Record<number, number>;
10
+ /** Bonus per extra shortest path, keyed by hop level, e.g. `{ 2: 0.15, 3: 0.1, 4: 0.05 }`. */
11
+ pathBonus: Record<number, number>;
12
+ /** Maximum path bonus that can be added on top of the base score. */
13
+ maxPathBonus: number;
14
+ }
15
+ /**
16
+ * Result of a distance query: hops from root + count of shortest paths.
17
+ */
18
+ interface DistanceInfo {
19
+ /** Number of hops from the root (0 = self). */
20
+ hops: number;
21
+ /** Count of shortest paths from the root (1 for self). */
22
+ paths: number;
23
+ }
24
+ /**
25
+ * Progress emitted while crawling.
26
+ */
27
+ interface CrawlProgress {
28
+ /** Current BFS depth being fetched. */
29
+ depth: number;
30
+ /** Number of pubkeys fetched so far. */
31
+ fetched: number;
32
+ /** Number of pubkeys queued for the next depth. */
33
+ queued: number;
34
+ }
35
+ /**
36
+ * Options for {@link GraphCrawler.crawl} / {@link WotGraph.crawl}.
37
+ */
38
+ interface CrawlOptions {
39
+ /** Max BFS depth. Default 2. */
40
+ maxDepth?: number;
41
+ /** Progress callback. */
42
+ onProgress?: (p: CrawlProgress) => void;
43
+ /** Abort signal to cancel the crawl. */
44
+ signal?: AbortSignal;
45
+ }
46
+ /**
47
+ * Result of a crawl.
48
+ */
49
+ interface CrawlResult {
50
+ /** Pubkeys whose kind:3 was successfully fetched. */
51
+ fetched: number;
52
+ /** Nodes with a stored follow list after the crawl. */
53
+ nodes: number;
54
+ /** Total follow edges after the crawl. */
55
+ edges: number;
56
+ /** Deepest BFS depth actually reached. */
57
+ depth: number;
58
+ /** Wall-clock duration in ms. */
59
+ durationMs: number;
60
+ /** True if the crawl was aborted/stopped before finishing. */
61
+ stoppedEarly: boolean;
62
+ }
63
+ /**
64
+ * Options for {@link WotGraph.filterByWoT}.
65
+ */
66
+ interface FilterByWoTOptions {
67
+ /** Only keep pubkeys within this many hops. Default 2. */
68
+ maxHops?: number;
69
+ }
70
+ /**
71
+ * A pluggable WebSocket constructor forwarded to the underlying pool
72
+ * (e.g. a proxy-safe implementation).
73
+ */
74
+ type WebSocketLike = typeof WebSocket;
75
+ /**
76
+ * Local query source consumed by `@nostr-wot/wot`'s `WoT` class.
77
+ * Structurally shared: `@nostr-wot/wot` declares an identical interface.
78
+ */
79
+ interface WoTLocalSource {
80
+ /** Distance in hops from the root, or `null` if unreached/unknown. */
81
+ getDistance(target: string): number | null;
82
+ /** Whether `target` is within `maxHops` of the root. */
83
+ isInMyWoT(target: string, maxHops?: number): boolean;
84
+ /** Trusted subset of `pubkeys`, sorted by score descending. */
85
+ filterByWoT(pubkeys: string[], opts?: FilterByWoTOptions): string[];
86
+ }
87
+
88
+ /**
89
+ * BFS crawler for kind:3 contact lists.
90
+ *
91
+ * Ported from the extension (`lib/sync.ts`, `GraphSync`) but with the raw
92
+ * `WebSocket` transport replaced by `@nostr-wot/relay`'s pool. The pool handles
93
+ * connection/reconnect across relays; this class keeps the proven crawl logic:
94
+ *
95
+ * - BFS by depth: fetch the root's kind:3, enqueue its follows for the next
96
+ * depth, and so on up to `maxDepth`.
97
+ * - Newest-per-author: for each pubkey, take the kind:3 event with the highest
98
+ * `created_at` seen across relays.
99
+ * - Rate limiting: a base delay between dispatches and a max-concurrent cap.
100
+ * - Tolerates unreachable relays; throws `CrawlError` only when zero relays are
101
+ * configured to connect.
102
+ * - Abortable via `signal` or `stop()`; a stopped crawl leaves partial data
103
+ * usable and reports `stoppedEarly: true`.
104
+ */
105
+
106
+ interface CrawlSubCloser {
107
+ close(): void;
108
+ }
109
+ interface CrawlEvent {
110
+ created_at: number;
111
+ tags: string[][];
112
+ [key: string]: unknown;
113
+ }
114
+ interface CrawlPool {
115
+ subscribe(filter: {
116
+ kinds?: number[];
117
+ authors?: string[];
118
+ limit?: number;
119
+ [key: string]: unknown;
120
+ }, handlers: {
121
+ onEvent: (e: CrawlEvent) => void;
122
+ onEose?: () => void;
123
+ onStatus?: (s: string) => void;
124
+ }): CrawlSubCloser;
125
+ getConnectedCount?(): number;
126
+ }
127
+
128
+ /**
129
+ * `WotGraph` — the primary public entry point.
130
+ *
131
+ * Ties the four internal layers together: a namespaced {@link GraphStorage},
132
+ * a BFS {@link LocalGraph}, a {@link GraphCrawler}, and the pure scoring
133
+ * function. Consumers create one per origin/app, `load()` to rehydrate any
134
+ * cached graph, `crawl()` to build/refresh it, then run O(1)/O(n) queries.
135
+ */
136
+
137
+ interface WotGraphOptions {
138
+ /** IndexedDB partition key (e.g. the app name). */
139
+ namespace: string;
140
+ /** Relay URLs to crawl. */
141
+ relays: string[];
142
+ /** Optional shared pool; if omitted one is created from `relays`. */
143
+ pool?: CrawlPool;
144
+ /** Scoring overrides merged onto {@link DEFAULT_SCORING}. */
145
+ scoring?: Partial<ScoringConfig>;
146
+ /** WebSocket implementation forwarded to the created pool. */
147
+ websocketImplementation?: WebSocketLike;
148
+ }
149
+ interface WotGraphStats {
150
+ nodes: number;
151
+ edges: number;
152
+ root: string | null;
153
+ lastCrawl: number | null;
154
+ maxDepth: number | null;
155
+ }
156
+ declare class WotGraph {
157
+ readonly namespace: string;
158
+ private relays;
159
+ private scoring;
160
+ private websocketImplementation?;
161
+ private storage;
162
+ private graph;
163
+ private pool;
164
+ private ownPool;
165
+ private crawler;
166
+ private root;
167
+ private inFlight;
168
+ private controller;
169
+ private listeners;
170
+ constructor(options: WotGraphOptions);
171
+ /** Hydrate any cached graph from IndexedDB (fast path). */
172
+ load(): Promise<void>;
173
+ /**
174
+ * Build/refresh the graph by crawling kind:3 from `rootPubkey`.
175
+ * Concurrent calls return the same in-flight promise (idempotent).
176
+ */
177
+ crawl(rootPubkey: string, opts?: CrawlOptions): Promise<CrawlResult>;
178
+ /** Distance info from the crawled root, or `null` if unreached/unknown. */
179
+ getDistance(pubkey: string): DistanceInfo | null;
180
+ /** Trust score 0..1 via {@link calculateScore}. */
181
+ getScore(pubkey: string): number;
182
+ /** Whether `pubkey` is within `maxHops` of the root. */
183
+ isInWoT(pubkey: string, maxHops?: number): boolean;
184
+ /** Trusted subset of `pubkeys`, sorted by score descending. */
185
+ filterByWoT(pubkeys: string[], opts?: FilterByWoTOptions): string[];
186
+ /** Follow list of `pubkey` as hex strings. */
187
+ getFollows(pubkey: string): string[];
188
+ /** Aggregate stats + crawl meta. */
189
+ stats(): WotGraphStats;
190
+ /** True if the last crawl is older than `ttlMs` (or never happened). */
191
+ isStale(ttlMs: number): boolean;
192
+ /** Wipe this namespace. */
193
+ clear(): Promise<void>;
194
+ /** Abort an in-flight crawl. Partial data stays usable. */
195
+ stop(): void;
196
+ /** Adapter for `@nostr-wot/wot`'s `WoT` class. */
197
+ asWoTSource(): WoTLocalSource;
198
+ /** The root pubkey the graph is currently answering queries from. */
199
+ getRoot(): string | null;
200
+ /** Subscribe to graph changes (crawl / load / clear). Returns an unsubscribe. */
201
+ onChange(cb: () => void): () => void;
202
+ /** Release the pool/storage this instance owns. */
203
+ destroy(): void;
204
+ private notify;
205
+ private resolvePool;
206
+ }
207
+
208
+ interface WotGraphProviderProps extends WotGraphOptions {
209
+ children: ReactNode;
210
+ }
211
+ interface WotGraphContextValue {
212
+ graph: WotGraph;
213
+ ready: boolean;
214
+ crawling: boolean;
215
+ setCrawling: (v: boolean) => void;
216
+ /** Bumps whenever the graph changes (crawl / load / clear). */
217
+ version: number;
218
+ }
219
+ /**
220
+ * Constructs and holds a {@link WotGraph}, calling `load()` on mount.
221
+ *
222
+ * @example
223
+ * ```tsx
224
+ * <WotGraphProvider namespace="myapp" relays={["wss://relay.damus.io"]}>
225
+ * <App />
226
+ * </WotGraphProvider>
227
+ * ```
228
+ */
229
+ declare function WotGraphProvider({ children, ...options }: WotGraphProviderProps): react_jsx_runtime.JSX.Element;
230
+ /** The {@link WotGraph} instance plus `{ ready, crawling }` state. */
231
+ declare function useWotGraph(): {
232
+ graph: WotGraph;
233
+ ready: boolean;
234
+ crawling: boolean;
235
+ };
236
+ /** `{ hops, paths } | null` for a pubkey; recomputes when the graph changes. */
237
+ declare function useDistance(pubkey: string | null | undefined): DistanceInfo | null;
238
+ /** `{ crawl, stop, progress, crawling, error }` for driving a crawl from UI. */
239
+ declare function useCrawl(): {
240
+ crawl: (rootPubkey: string, opts?: CrawlOptions) => Promise<CrawlResult | null>;
241
+ stop: () => void;
242
+ progress: CrawlProgress | null;
243
+ crawling: boolean;
244
+ error: Error | null;
245
+ };
246
+
247
+ export { type CrawlOptions, type CrawlProgress, type CrawlResult, type DistanceInfo, type FilterByWoTOptions, type ScoringConfig, type WoTLocalSource, WotGraph, type WotGraphContextValue, type WotGraphOptions, WotGraphProvider, type WotGraphProviderProps, type WotGraphStats, useCrawl, useDistance, useWotGraph };
@@ -0,0 +1,247 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ /**
5
+ * Trust-score configuration. Ported verbatim from the extension.
6
+ */
7
+ interface ScoringConfig {
8
+ /** Base score per hop distance, e.g. `{ 1: 1.0, 2: 0.5, 3: 0.25, 4: 0.1 }`. */
9
+ distanceWeights: Record<number, number>;
10
+ /** Bonus per extra shortest path, keyed by hop level, e.g. `{ 2: 0.15, 3: 0.1, 4: 0.05 }`. */
11
+ pathBonus: Record<number, number>;
12
+ /** Maximum path bonus that can be added on top of the base score. */
13
+ maxPathBonus: number;
14
+ }
15
+ /**
16
+ * Result of a distance query: hops from root + count of shortest paths.
17
+ */
18
+ interface DistanceInfo {
19
+ /** Number of hops from the root (0 = self). */
20
+ hops: number;
21
+ /** Count of shortest paths from the root (1 for self). */
22
+ paths: number;
23
+ }
24
+ /**
25
+ * Progress emitted while crawling.
26
+ */
27
+ interface CrawlProgress {
28
+ /** Current BFS depth being fetched. */
29
+ depth: number;
30
+ /** Number of pubkeys fetched so far. */
31
+ fetched: number;
32
+ /** Number of pubkeys queued for the next depth. */
33
+ queued: number;
34
+ }
35
+ /**
36
+ * Options for {@link GraphCrawler.crawl} / {@link WotGraph.crawl}.
37
+ */
38
+ interface CrawlOptions {
39
+ /** Max BFS depth. Default 2. */
40
+ maxDepth?: number;
41
+ /** Progress callback. */
42
+ onProgress?: (p: CrawlProgress) => void;
43
+ /** Abort signal to cancel the crawl. */
44
+ signal?: AbortSignal;
45
+ }
46
+ /**
47
+ * Result of a crawl.
48
+ */
49
+ interface CrawlResult {
50
+ /** Pubkeys whose kind:3 was successfully fetched. */
51
+ fetched: number;
52
+ /** Nodes with a stored follow list after the crawl. */
53
+ nodes: number;
54
+ /** Total follow edges after the crawl. */
55
+ edges: number;
56
+ /** Deepest BFS depth actually reached. */
57
+ depth: number;
58
+ /** Wall-clock duration in ms. */
59
+ durationMs: number;
60
+ /** True if the crawl was aborted/stopped before finishing. */
61
+ stoppedEarly: boolean;
62
+ }
63
+ /**
64
+ * Options for {@link WotGraph.filterByWoT}.
65
+ */
66
+ interface FilterByWoTOptions {
67
+ /** Only keep pubkeys within this many hops. Default 2. */
68
+ maxHops?: number;
69
+ }
70
+ /**
71
+ * A pluggable WebSocket constructor forwarded to the underlying pool
72
+ * (e.g. a proxy-safe implementation).
73
+ */
74
+ type WebSocketLike = typeof WebSocket;
75
+ /**
76
+ * Local query source consumed by `@nostr-wot/wot`'s `WoT` class.
77
+ * Structurally shared: `@nostr-wot/wot` declares an identical interface.
78
+ */
79
+ interface WoTLocalSource {
80
+ /** Distance in hops from the root, or `null` if unreached/unknown. */
81
+ getDistance(target: string): number | null;
82
+ /** Whether `target` is within `maxHops` of the root. */
83
+ isInMyWoT(target: string, maxHops?: number): boolean;
84
+ /** Trusted subset of `pubkeys`, sorted by score descending. */
85
+ filterByWoT(pubkeys: string[], opts?: FilterByWoTOptions): string[];
86
+ }
87
+
88
+ /**
89
+ * BFS crawler for kind:3 contact lists.
90
+ *
91
+ * Ported from the extension (`lib/sync.ts`, `GraphSync`) but with the raw
92
+ * `WebSocket` transport replaced by `@nostr-wot/relay`'s pool. The pool handles
93
+ * connection/reconnect across relays; this class keeps the proven crawl logic:
94
+ *
95
+ * - BFS by depth: fetch the root's kind:3, enqueue its follows for the next
96
+ * depth, and so on up to `maxDepth`.
97
+ * - Newest-per-author: for each pubkey, take the kind:3 event with the highest
98
+ * `created_at` seen across relays.
99
+ * - Rate limiting: a base delay between dispatches and a max-concurrent cap.
100
+ * - Tolerates unreachable relays; throws `CrawlError` only when zero relays are
101
+ * configured to connect.
102
+ * - Abortable via `signal` or `stop()`; a stopped crawl leaves partial data
103
+ * usable and reports `stoppedEarly: true`.
104
+ */
105
+
106
+ interface CrawlSubCloser {
107
+ close(): void;
108
+ }
109
+ interface CrawlEvent {
110
+ created_at: number;
111
+ tags: string[][];
112
+ [key: string]: unknown;
113
+ }
114
+ interface CrawlPool {
115
+ subscribe(filter: {
116
+ kinds?: number[];
117
+ authors?: string[];
118
+ limit?: number;
119
+ [key: string]: unknown;
120
+ }, handlers: {
121
+ onEvent: (e: CrawlEvent) => void;
122
+ onEose?: () => void;
123
+ onStatus?: (s: string) => void;
124
+ }): CrawlSubCloser;
125
+ getConnectedCount?(): number;
126
+ }
127
+
128
+ /**
129
+ * `WotGraph` — the primary public entry point.
130
+ *
131
+ * Ties the four internal layers together: a namespaced {@link GraphStorage},
132
+ * a BFS {@link LocalGraph}, a {@link GraphCrawler}, and the pure scoring
133
+ * function. Consumers create one per origin/app, `load()` to rehydrate any
134
+ * cached graph, `crawl()` to build/refresh it, then run O(1)/O(n) queries.
135
+ */
136
+
137
+ interface WotGraphOptions {
138
+ /** IndexedDB partition key (e.g. the app name). */
139
+ namespace: string;
140
+ /** Relay URLs to crawl. */
141
+ relays: string[];
142
+ /** Optional shared pool; if omitted one is created from `relays`. */
143
+ pool?: CrawlPool;
144
+ /** Scoring overrides merged onto {@link DEFAULT_SCORING}. */
145
+ scoring?: Partial<ScoringConfig>;
146
+ /** WebSocket implementation forwarded to the created pool. */
147
+ websocketImplementation?: WebSocketLike;
148
+ }
149
+ interface WotGraphStats {
150
+ nodes: number;
151
+ edges: number;
152
+ root: string | null;
153
+ lastCrawl: number | null;
154
+ maxDepth: number | null;
155
+ }
156
+ declare class WotGraph {
157
+ readonly namespace: string;
158
+ private relays;
159
+ private scoring;
160
+ private websocketImplementation?;
161
+ private storage;
162
+ private graph;
163
+ private pool;
164
+ private ownPool;
165
+ private crawler;
166
+ private root;
167
+ private inFlight;
168
+ private controller;
169
+ private listeners;
170
+ constructor(options: WotGraphOptions);
171
+ /** Hydrate any cached graph from IndexedDB (fast path). */
172
+ load(): Promise<void>;
173
+ /**
174
+ * Build/refresh the graph by crawling kind:3 from `rootPubkey`.
175
+ * Concurrent calls return the same in-flight promise (idempotent).
176
+ */
177
+ crawl(rootPubkey: string, opts?: CrawlOptions): Promise<CrawlResult>;
178
+ /** Distance info from the crawled root, or `null` if unreached/unknown. */
179
+ getDistance(pubkey: string): DistanceInfo | null;
180
+ /** Trust score 0..1 via {@link calculateScore}. */
181
+ getScore(pubkey: string): number;
182
+ /** Whether `pubkey` is within `maxHops` of the root. */
183
+ isInWoT(pubkey: string, maxHops?: number): boolean;
184
+ /** Trusted subset of `pubkeys`, sorted by score descending. */
185
+ filterByWoT(pubkeys: string[], opts?: FilterByWoTOptions): string[];
186
+ /** Follow list of `pubkey` as hex strings. */
187
+ getFollows(pubkey: string): string[];
188
+ /** Aggregate stats + crawl meta. */
189
+ stats(): WotGraphStats;
190
+ /** True if the last crawl is older than `ttlMs` (or never happened). */
191
+ isStale(ttlMs: number): boolean;
192
+ /** Wipe this namespace. */
193
+ clear(): Promise<void>;
194
+ /** Abort an in-flight crawl. Partial data stays usable. */
195
+ stop(): void;
196
+ /** Adapter for `@nostr-wot/wot`'s `WoT` class. */
197
+ asWoTSource(): WoTLocalSource;
198
+ /** The root pubkey the graph is currently answering queries from. */
199
+ getRoot(): string | null;
200
+ /** Subscribe to graph changes (crawl / load / clear). Returns an unsubscribe. */
201
+ onChange(cb: () => void): () => void;
202
+ /** Release the pool/storage this instance owns. */
203
+ destroy(): void;
204
+ private notify;
205
+ private resolvePool;
206
+ }
207
+
208
+ interface WotGraphProviderProps extends WotGraphOptions {
209
+ children: ReactNode;
210
+ }
211
+ interface WotGraphContextValue {
212
+ graph: WotGraph;
213
+ ready: boolean;
214
+ crawling: boolean;
215
+ setCrawling: (v: boolean) => void;
216
+ /** Bumps whenever the graph changes (crawl / load / clear). */
217
+ version: number;
218
+ }
219
+ /**
220
+ * Constructs and holds a {@link WotGraph}, calling `load()` on mount.
221
+ *
222
+ * @example
223
+ * ```tsx
224
+ * <WotGraphProvider namespace="myapp" relays={["wss://relay.damus.io"]}>
225
+ * <App />
226
+ * </WotGraphProvider>
227
+ * ```
228
+ */
229
+ declare function WotGraphProvider({ children, ...options }: WotGraphProviderProps): react_jsx_runtime.JSX.Element;
230
+ /** The {@link WotGraph} instance plus `{ ready, crawling }` state. */
231
+ declare function useWotGraph(): {
232
+ graph: WotGraph;
233
+ ready: boolean;
234
+ crawling: boolean;
235
+ };
236
+ /** `{ hops, paths } | null` for a pubkey; recomputes when the graph changes. */
237
+ declare function useDistance(pubkey: string | null | undefined): DistanceInfo | null;
238
+ /** `{ crawl, stop, progress, crawling, error }` for driving a crawl from UI. */
239
+ declare function useCrawl(): {
240
+ crawl: (rootPubkey: string, opts?: CrawlOptions) => Promise<CrawlResult | null>;
241
+ stop: () => void;
242
+ progress: CrawlProgress | null;
243
+ crawling: boolean;
244
+ error: Error | null;
245
+ };
246
+
247
+ export { type CrawlOptions, type CrawlProgress, type CrawlResult, type DistanceInfo, type FilterByWoTOptions, type ScoringConfig, type WoTLocalSource, WotGraph, type WotGraphContextValue, type WotGraphOptions, WotGraphProvider, type WotGraphProviderProps, type WotGraphStats, useCrawl, useDistance, useWotGraph };