@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.
- package/LICENSE +21 -0
- package/README.md +104 -0
- package/dist/index.cjs +754 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +413 -0
- package/dist/index.d.ts +413 -0
- package/dist/index.js +743 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.cjs +835 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +247 -0
- package/dist/react/index.d.ts +247 -0
- package/dist/react/index.js +829 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +88 -0
|
@@ -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"],"names":["_a","DEFAULT_MAX_HOPS","useWebSocketImplementation","RelayPool","SimplePool"],"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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trust-score configuration. Ported verbatim from the extension.
|
|
3
|
+
*/
|
|
4
|
+
interface ScoringConfig {
|
|
5
|
+
/** Base score per hop distance, e.g. `{ 1: 1.0, 2: 0.5, 3: 0.25, 4: 0.1 }`. */
|
|
6
|
+
distanceWeights: Record<number, number>;
|
|
7
|
+
/** Bonus per extra shortest path, keyed by hop level, e.g. `{ 2: 0.15, 3: 0.1, 4: 0.05 }`. */
|
|
8
|
+
pathBonus: Record<number, number>;
|
|
9
|
+
/** Maximum path bonus that can be added on top of the base score. */
|
|
10
|
+
maxPathBonus: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Result of a distance query: hops from root + count of shortest paths.
|
|
14
|
+
*/
|
|
15
|
+
interface DistanceInfo {
|
|
16
|
+
/** Number of hops from the root (0 = self). */
|
|
17
|
+
hops: number;
|
|
18
|
+
/** Count of shortest paths from the root (1 for self). */
|
|
19
|
+
paths: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Graph metadata persisted alongside the follow edges.
|
|
23
|
+
*/
|
|
24
|
+
interface GraphMeta {
|
|
25
|
+
/** Root pubkey the graph was last crawled from. */
|
|
26
|
+
root: string | null;
|
|
27
|
+
/** Timestamp (ms) of the last completed crawl. */
|
|
28
|
+
lastCrawl: number | null;
|
|
29
|
+
/** Max BFS depth of the last crawl. */
|
|
30
|
+
maxDepth: number | null;
|
|
31
|
+
/** Storage schema version. */
|
|
32
|
+
version: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Aggregate storage counts.
|
|
36
|
+
*/
|
|
37
|
+
interface StorageStats {
|
|
38
|
+
/** Nodes that have a stored follow list. */
|
|
39
|
+
nodes: number;
|
|
40
|
+
/** Total follow edges across all nodes. */
|
|
41
|
+
edges: number;
|
|
42
|
+
/** Distinct interned pubkeys. */
|
|
43
|
+
uniquePubkeys: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Progress emitted while crawling.
|
|
47
|
+
*/
|
|
48
|
+
interface CrawlProgress {
|
|
49
|
+
/** Current BFS depth being fetched. */
|
|
50
|
+
depth: number;
|
|
51
|
+
/** Number of pubkeys fetched so far. */
|
|
52
|
+
fetched: number;
|
|
53
|
+
/** Number of pubkeys queued for the next depth. */
|
|
54
|
+
queued: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Options for {@link GraphCrawler.crawl} / {@link WotGraph.crawl}.
|
|
58
|
+
*/
|
|
59
|
+
interface CrawlOptions {
|
|
60
|
+
/** Max BFS depth. Default 2. */
|
|
61
|
+
maxDepth?: number;
|
|
62
|
+
/** Progress callback. */
|
|
63
|
+
onProgress?: (p: CrawlProgress) => void;
|
|
64
|
+
/** Abort signal to cancel the crawl. */
|
|
65
|
+
signal?: AbortSignal;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Result of a crawl.
|
|
69
|
+
*/
|
|
70
|
+
interface CrawlResult {
|
|
71
|
+
/** Pubkeys whose kind:3 was successfully fetched. */
|
|
72
|
+
fetched: number;
|
|
73
|
+
/** Nodes with a stored follow list after the crawl. */
|
|
74
|
+
nodes: number;
|
|
75
|
+
/** Total follow edges after the crawl. */
|
|
76
|
+
edges: number;
|
|
77
|
+
/** Deepest BFS depth actually reached. */
|
|
78
|
+
depth: number;
|
|
79
|
+
/** Wall-clock duration in ms. */
|
|
80
|
+
durationMs: number;
|
|
81
|
+
/** True if the crawl was aborted/stopped before finishing. */
|
|
82
|
+
stoppedEarly: boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Options for {@link WotGraph.filterByWoT}.
|
|
86
|
+
*/
|
|
87
|
+
interface FilterByWoTOptions {
|
|
88
|
+
/** Only keep pubkeys within this many hops. Default 2. */
|
|
89
|
+
maxHops?: number;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* A pluggable WebSocket constructor forwarded to the underlying pool
|
|
93
|
+
* (e.g. a proxy-safe implementation).
|
|
94
|
+
*/
|
|
95
|
+
type WebSocketLike = typeof WebSocket;
|
|
96
|
+
/**
|
|
97
|
+
* Local query source consumed by `@nostr-wot/wot`'s `WoT` class.
|
|
98
|
+
* Structurally shared: `@nostr-wot/wot` declares an identical interface.
|
|
99
|
+
*/
|
|
100
|
+
interface WoTLocalSource {
|
|
101
|
+
/** Distance in hops from the root, or `null` if unreached/unknown. */
|
|
102
|
+
getDistance(target: string): number | null;
|
|
103
|
+
/** Whether `target` is within `maxHops` of the root. */
|
|
104
|
+
isInMyWoT(target: string, maxHops?: number): boolean;
|
|
105
|
+
/** Trusted subset of `pubkeys`, sorted by score descending. */
|
|
106
|
+
filterByWoT(pubkeys: string[], opts?: FilterByWoTOptions): string[];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* IndexedDB storage for the local WoT graph.
|
|
111
|
+
*
|
|
112
|
+
* Ported from the extension (`lib/storage.ts`), generalized from per-account
|
|
113
|
+
* databases to a `namespace` key and wrapped in a class so multiple graphs can
|
|
114
|
+
* coexist. Preserves the two performance-critical techniques:
|
|
115
|
+
*
|
|
116
|
+
* - **Interning**: pubkeys (64-hex) are mapped to small integer ids, so the
|
|
117
|
+
* graph is stored/traversed as numbers instead of strings.
|
|
118
|
+
* - **Delta encoding**: each node's sorted follow-id list is stored as a
|
|
119
|
+
* `Uint32Array` of deltas, which compresses well and keeps memory bounded for
|
|
120
|
+
* the 100k+ nodes a 2-hop crawl can yield.
|
|
121
|
+
*
|
|
122
|
+
* When `indexedDB` is unavailable (Node without a polyfill) the store operates
|
|
123
|
+
* in memory-only mode: crawl/query still work, nothing is persisted.
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
declare function encodeFollows(followIds: ArrayLike<number>): ArrayBuffer;
|
|
127
|
+
declare function decodeFollows(buffer: ArrayBuffer | null | undefined): Uint32Array;
|
|
128
|
+
declare class GraphStorage {
|
|
129
|
+
readonly namespace: string;
|
|
130
|
+
private db;
|
|
131
|
+
private memoryOnly;
|
|
132
|
+
private opened;
|
|
133
|
+
private pubkeyToId;
|
|
134
|
+
private idToPubkey;
|
|
135
|
+
private nextId;
|
|
136
|
+
private graphCache;
|
|
137
|
+
private metaCache;
|
|
138
|
+
private dirtyFollows;
|
|
139
|
+
private dirtyPubkeys;
|
|
140
|
+
constructor(namespace: string);
|
|
141
|
+
private dbName;
|
|
142
|
+
/** Open (or create) the namespace DB and hydrate in-memory caches. */
|
|
143
|
+
open(): Promise<void>;
|
|
144
|
+
/** Hydrate the in-memory interning + follow maps + meta from the DB. */
|
|
145
|
+
loadAll(): Promise<void>;
|
|
146
|
+
private getAll;
|
|
147
|
+
/** Numeric id for a pubkey, or null if never seen. */
|
|
148
|
+
getId(pubkey: string): number | null;
|
|
149
|
+
/** Numeric id for a pubkey, minting and buffering a new one if needed. */
|
|
150
|
+
getOrCreateId(pubkey: string): number;
|
|
151
|
+
/** Batch variant of {@link getOrCreateId}. */
|
|
152
|
+
getOrCreateIds(pubkeys: string[]): number[];
|
|
153
|
+
/** Pubkey for a numeric id, or null. */
|
|
154
|
+
getHex(id: number): string | null;
|
|
155
|
+
/** Highest assigned id (for typed-array sizing). */
|
|
156
|
+
getMaxId(): number;
|
|
157
|
+
/** Store `pubkey`'s follow list. Interns everything and updates the cache. */
|
|
158
|
+
saveFollows(pubkey: string, follows: string[]): void;
|
|
159
|
+
/** Follow ids for a node id — sync, from the in-memory cache. */
|
|
160
|
+
getFollowIdsSync(id: number): Uint32Array;
|
|
161
|
+
/** Follow ids for a pubkey (interned). Empty if unknown. */
|
|
162
|
+
getFollowIds(pubkey: string): Uint32Array;
|
|
163
|
+
/** Follow list of `pubkey` as hex strings. */
|
|
164
|
+
getFollows(pubkey: string): string[];
|
|
165
|
+
setMeta(key: string, value: unknown): Promise<void>;
|
|
166
|
+
getMeta<T = unknown>(key: string): T | undefined;
|
|
167
|
+
/** Read the structured graph meta record. */
|
|
168
|
+
getGraphMeta(): GraphMeta;
|
|
169
|
+
/** Flush buffered pubkey + follow writes to IndexedDB. No-op in memory mode. */
|
|
170
|
+
flush(): Promise<void>;
|
|
171
|
+
stats(): StorageStats;
|
|
172
|
+
/** Wipe this namespace: memory caches + persisted stores. */
|
|
173
|
+
clear(): Promise<void>;
|
|
174
|
+
/** Close the underlying DB connection. */
|
|
175
|
+
close(): void;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* BFS crawler for kind:3 contact lists.
|
|
180
|
+
*
|
|
181
|
+
* Ported from the extension (`lib/sync.ts`, `GraphSync`) but with the raw
|
|
182
|
+
* `WebSocket` transport replaced by `@nostr-wot/relay`'s pool. The pool handles
|
|
183
|
+
* connection/reconnect across relays; this class keeps the proven crawl logic:
|
|
184
|
+
*
|
|
185
|
+
* - BFS by depth: fetch the root's kind:3, enqueue its follows for the next
|
|
186
|
+
* depth, and so on up to `maxDepth`.
|
|
187
|
+
* - Newest-per-author: for each pubkey, take the kind:3 event with the highest
|
|
188
|
+
* `created_at` seen across relays.
|
|
189
|
+
* - Rate limiting: a base delay between dispatches and a max-concurrent cap.
|
|
190
|
+
* - Tolerates unreachable relays; throws `CrawlError` only when zero relays are
|
|
191
|
+
* configured to connect.
|
|
192
|
+
* - Abortable via `signal` or `stop()`; a stopped crawl leaves partial data
|
|
193
|
+
* usable and reports `stoppedEarly: true`.
|
|
194
|
+
*/
|
|
195
|
+
|
|
196
|
+
interface CrawlSubCloser {
|
|
197
|
+
close(): void;
|
|
198
|
+
}
|
|
199
|
+
interface CrawlEvent {
|
|
200
|
+
created_at: number;
|
|
201
|
+
tags: string[][];
|
|
202
|
+
[key: string]: unknown;
|
|
203
|
+
}
|
|
204
|
+
interface CrawlPool {
|
|
205
|
+
subscribe(filter: {
|
|
206
|
+
kinds?: number[];
|
|
207
|
+
authors?: string[];
|
|
208
|
+
limit?: number;
|
|
209
|
+
[key: string]: unknown;
|
|
210
|
+
}, handlers: {
|
|
211
|
+
onEvent: (e: CrawlEvent) => void;
|
|
212
|
+
onEose?: () => void;
|
|
213
|
+
onStatus?: (s: string) => void;
|
|
214
|
+
}): CrawlSubCloser;
|
|
215
|
+
getConnectedCount?(): number;
|
|
216
|
+
}
|
|
217
|
+
interface GraphCrawlerOptions {
|
|
218
|
+
pool: CrawlPool;
|
|
219
|
+
storage: GraphStorage;
|
|
220
|
+
relays: string[];
|
|
221
|
+
/** Base delay (ms) between fetch dispatches. Default 50. */
|
|
222
|
+
baseDelayMs?: number;
|
|
223
|
+
/** Max concurrent in-flight fetches. Default 5. */
|
|
224
|
+
maxConcurrent?: number;
|
|
225
|
+
/** Per-pubkey response timeout (ms). Default 10000. */
|
|
226
|
+
requestTimeoutMs?: number;
|
|
227
|
+
}
|
|
228
|
+
declare class CrawlError extends Error {
|
|
229
|
+
constructor(message: string);
|
|
230
|
+
}
|
|
231
|
+
declare class GraphCrawler {
|
|
232
|
+
private pool;
|
|
233
|
+
private storage;
|
|
234
|
+
private relays;
|
|
235
|
+
private baseDelayMs;
|
|
236
|
+
private maxConcurrent;
|
|
237
|
+
private requestTimeoutMs;
|
|
238
|
+
private aborted;
|
|
239
|
+
constructor(options: GraphCrawlerOptions);
|
|
240
|
+
/** Abort an in-flight crawl. */
|
|
241
|
+
stop(): void;
|
|
242
|
+
crawl(rootPubkey: string, opts?: CrawlOptions): Promise<CrawlResult>;
|
|
243
|
+
/**
|
|
244
|
+
* Fetch a single pubkey's newest kind:3 follow list across relays.
|
|
245
|
+
* Resolves to the follow pubkeys, or `null` if no event arrived.
|
|
246
|
+
*/
|
|
247
|
+
private fetchNewest;
|
|
248
|
+
/**
|
|
249
|
+
* Run `worker` over `items` with a max-concurrency cap and a base delay
|
|
250
|
+
* before each dispatch (preserving the crawler's per-relay rate limiting
|
|
251
|
+
* intent, now applied at the pool boundary).
|
|
252
|
+
*/
|
|
253
|
+
private mapLimited;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* `WotGraph` — the primary public entry point.
|
|
258
|
+
*
|
|
259
|
+
* Ties the four internal layers together: a namespaced {@link GraphStorage},
|
|
260
|
+
* a BFS {@link LocalGraph}, a {@link GraphCrawler}, and the pure scoring
|
|
261
|
+
* function. Consumers create one per origin/app, `load()` to rehydrate any
|
|
262
|
+
* cached graph, `crawl()` to build/refresh it, then run O(1)/O(n) queries.
|
|
263
|
+
*/
|
|
264
|
+
|
|
265
|
+
interface WotGraphOptions {
|
|
266
|
+
/** IndexedDB partition key (e.g. the app name). */
|
|
267
|
+
namespace: string;
|
|
268
|
+
/** Relay URLs to crawl. */
|
|
269
|
+
relays: string[];
|
|
270
|
+
/** Optional shared pool; if omitted one is created from `relays`. */
|
|
271
|
+
pool?: CrawlPool;
|
|
272
|
+
/** Scoring overrides merged onto {@link DEFAULT_SCORING}. */
|
|
273
|
+
scoring?: Partial<ScoringConfig>;
|
|
274
|
+
/** WebSocket implementation forwarded to the created pool. */
|
|
275
|
+
websocketImplementation?: WebSocketLike;
|
|
276
|
+
}
|
|
277
|
+
interface WotGraphStats {
|
|
278
|
+
nodes: number;
|
|
279
|
+
edges: number;
|
|
280
|
+
root: string | null;
|
|
281
|
+
lastCrawl: number | null;
|
|
282
|
+
maxDepth: number | null;
|
|
283
|
+
}
|
|
284
|
+
declare class WotGraph {
|
|
285
|
+
readonly namespace: string;
|
|
286
|
+
private relays;
|
|
287
|
+
private scoring;
|
|
288
|
+
private websocketImplementation?;
|
|
289
|
+
private storage;
|
|
290
|
+
private graph;
|
|
291
|
+
private pool;
|
|
292
|
+
private ownPool;
|
|
293
|
+
private crawler;
|
|
294
|
+
private root;
|
|
295
|
+
private inFlight;
|
|
296
|
+
private controller;
|
|
297
|
+
private listeners;
|
|
298
|
+
constructor(options: WotGraphOptions);
|
|
299
|
+
/** Hydrate any cached graph from IndexedDB (fast path). */
|
|
300
|
+
load(): Promise<void>;
|
|
301
|
+
/**
|
|
302
|
+
* Build/refresh the graph by crawling kind:3 from `rootPubkey`.
|
|
303
|
+
* Concurrent calls return the same in-flight promise (idempotent).
|
|
304
|
+
*/
|
|
305
|
+
crawl(rootPubkey: string, opts?: CrawlOptions): Promise<CrawlResult>;
|
|
306
|
+
/** Distance info from the crawled root, or `null` if unreached/unknown. */
|
|
307
|
+
getDistance(pubkey: string): DistanceInfo | null;
|
|
308
|
+
/** Trust score 0..1 via {@link calculateScore}. */
|
|
309
|
+
getScore(pubkey: string): number;
|
|
310
|
+
/** Whether `pubkey` is within `maxHops` of the root. */
|
|
311
|
+
isInWoT(pubkey: string, maxHops?: number): boolean;
|
|
312
|
+
/** Trusted subset of `pubkeys`, sorted by score descending. */
|
|
313
|
+
filterByWoT(pubkeys: string[], opts?: FilterByWoTOptions): string[];
|
|
314
|
+
/** Follow list of `pubkey` as hex strings. */
|
|
315
|
+
getFollows(pubkey: string): string[];
|
|
316
|
+
/** Aggregate stats + crawl meta. */
|
|
317
|
+
stats(): WotGraphStats;
|
|
318
|
+
/** True if the last crawl is older than `ttlMs` (or never happened). */
|
|
319
|
+
isStale(ttlMs: number): boolean;
|
|
320
|
+
/** Wipe this namespace. */
|
|
321
|
+
clear(): Promise<void>;
|
|
322
|
+
/** Abort an in-flight crawl. Partial data stays usable. */
|
|
323
|
+
stop(): void;
|
|
324
|
+
/** Adapter for `@nostr-wot/wot`'s `WoT` class. */
|
|
325
|
+
asWoTSource(): WoTLocalSource;
|
|
326
|
+
/** The root pubkey the graph is currently answering queries from. */
|
|
327
|
+
getRoot(): string | null;
|
|
328
|
+
/** Subscribe to graph changes (crawl / load / clear). Returns an unsubscribe. */
|
|
329
|
+
onChange(cb: () => void): () => void;
|
|
330
|
+
/** Release the pool/storage this instance owns. */
|
|
331
|
+
destroy(): void;
|
|
332
|
+
private notify;
|
|
333
|
+
private resolvePool;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Centralized trust score calculation.
|
|
338
|
+
*
|
|
339
|
+
* Formula: score = base + pathBonus (capped at maxPathBonus)
|
|
340
|
+
*
|
|
341
|
+
* Where:
|
|
342
|
+
* - base: base score per hop distance (1 hop = 100%, 2 hops = 50%, etc.)
|
|
343
|
+
* - pathBonus: bonus based on number of shortest paths, capped at maxPathBonus
|
|
344
|
+
*
|
|
345
|
+
* Ported verbatim from the extension (`lib/scoring.ts`).
|
|
346
|
+
*/
|
|
347
|
+
|
|
348
|
+
declare const DEFAULT_SCORING: ScoringConfig;
|
|
349
|
+
/**
|
|
350
|
+
* Calculate trust score from hops and path count.
|
|
351
|
+
*
|
|
352
|
+
* @param hops - Number of hops (0 = self, 1 = direct follow, etc.)
|
|
353
|
+
* @param paths - Number of shortest paths (null if unknown)
|
|
354
|
+
* @param scoring - Scoring configuration
|
|
355
|
+
* @returns Score between 0 and 1
|
|
356
|
+
*/
|
|
357
|
+
declare function calculateScore(hops: number | null | undefined, paths: number | null, scoring?: ScoringConfig): number;
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* In-memory BFS over the hydrated follow graph.
|
|
361
|
+
*
|
|
362
|
+
* Ported from the extension (`lib/graph.ts`, `LocalGraph`). Given the interned
|
|
363
|
+
* follow map (from {@link GraphStorage}) and a root pubkey, a single BFS pass
|
|
364
|
+
* fills two typed arrays indexed by node id:
|
|
365
|
+
*
|
|
366
|
+
* - `hops` (`Uint8Array`) — distance from root, stored as `hop + 1` so `0`
|
|
367
|
+
* means "not reached" (255 max).
|
|
368
|
+
* - `paths` (`Uint32Array`) — count of shortest paths to each node.
|
|
369
|
+
*
|
|
370
|
+
* The cache is keyed by root and invalidated on crawl / root change / clear.
|
|
371
|
+
*/
|
|
372
|
+
|
|
373
|
+
declare class LocalGraph {
|
|
374
|
+
private storage;
|
|
375
|
+
private cache;
|
|
376
|
+
private cachedRoot;
|
|
377
|
+
constructor(storage: GraphStorage);
|
|
378
|
+
/** Invalidate the precomputed cache (called on crawl / root change / clear). */
|
|
379
|
+
invalidateCache(): void;
|
|
380
|
+
/**
|
|
381
|
+
* Precompute hops and paths from a root pubkey using a single BFS pass.
|
|
382
|
+
* Results stored in typed arrays indexed by node id for O(1) lookup.
|
|
383
|
+
*/
|
|
384
|
+
private buildCache;
|
|
385
|
+
/** Ensure the cache is built for `root`. */
|
|
386
|
+
private ensureCache;
|
|
387
|
+
/**
|
|
388
|
+
* Distance info from `root` to `pubkey`. Returns `{ hops, paths }`, or `null`
|
|
389
|
+
* when unreached / unknown. Self → `{ hops: 0, paths: 1 }`.
|
|
390
|
+
*/
|
|
391
|
+
getDistance(root: string, pubkey: string, maxHops?: number): DistanceInfo | null;
|
|
392
|
+
/** Follow list of `pubkey` as hex strings. */
|
|
393
|
+
getFollows(pubkey: string): string[];
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Adapter turning a {@link WotGraph} into the small `WoTLocalSource` shape that
|
|
398
|
+
* `@nostr-wot/wot`'s `WoT` class can consume as a local query source instead of
|
|
399
|
+
* the remote Oracle.
|
|
400
|
+
*/
|
|
401
|
+
|
|
402
|
+
/** Minimal surface {@link createWoTSource} needs from a graph. */
|
|
403
|
+
interface WoTSourceGraph {
|
|
404
|
+
getDistance(pubkey: string): {
|
|
405
|
+
hops: number;
|
|
406
|
+
paths: number;
|
|
407
|
+
} | null;
|
|
408
|
+
isInWoT(pubkey: string, maxHops?: number): boolean;
|
|
409
|
+
filterByWoT(pubkeys: string[], opts?: FilterByWoTOptions): string[];
|
|
410
|
+
}
|
|
411
|
+
declare function createWoTSource(graph: WoTSourceGraph): WoTLocalSource;
|
|
412
|
+
|
|
413
|
+
export { CrawlError, type CrawlEvent, type CrawlOptions, type CrawlPool, type CrawlProgress, type CrawlResult, type CrawlSubCloser, DEFAULT_SCORING, type DistanceInfo, type FilterByWoTOptions, GraphCrawler, type GraphCrawlerOptions, type GraphMeta, GraphStorage, LocalGraph, type ScoringConfig, type StorageStats, type WebSocketLike, type WoTLocalSource, type WoTSourceGraph, WotGraph, type WotGraphOptions, type WotGraphStats, calculateScore, createWoTSource, decodeFollows, encodeFollows };
|