217ee25bfc68097bff1259592c5450882588ebb1f39c2254eb68d6ec991680cc.json raw

   1  {"ast":null,"code":"import _asyncToGenerator from \"/home/mleku/src/orly.dev/next/signer/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js\";\nimport { SimplePool } from 'nostr-tools/pool';\nimport { FALLBACK_PROFILE_RELAYS } from '../../constants/fallback-relays';\nimport * as i0 from \"@angular/core\";\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours\nconst FETCH_TIMEOUT_MS = 10000; // 10 seconds\nconst STORAGE_KEY = 'relayListCache';\nexport let RelayListService = /*#__PURE__*/(() => {\n  class RelayListService {\n    #cache = {};\n    #pool = null;\n    #fetchPromises = new Map();\n    #initialized = false;\n    #initPromise = null;\n    /**\n     * Initialize the service by loading cache from session storage\n     */\n    initialize() {\n      var _this = this;\n      return _asyncToGenerator(function* () {\n        if (_this.#initialized) {\n          return;\n        }\n        if (_this.#initPromise) {\n          return _this.#initPromise;\n        }\n        _this.#initPromise = _this.#loadCacheFromStorage();\n        yield _this.#initPromise;\n        _this.#initialized = true;\n      })();\n    }\n    /**\n     * Load cache from browser session storage\n     */\n    #loadCacheFromStorage() {\n      var _this2 = this;\n      return _asyncToGenerator(function* () {\n        try {\n          if (typeof chrome !== 'undefined' && chrome.storage?.session) {\n            const result = yield chrome.storage.session.get(STORAGE_KEY);\n            if (result[STORAGE_KEY]) {\n              _this2.#cache = result[STORAGE_KEY];\n              _this2.#pruneStaleCache();\n            }\n          }\n        } catch (error) {\n          console.error('Failed to load relay list cache from storage:', error);\n        }\n      })();\n    }\n    /**\n     * Save cache to browser session storage\n     */\n    #saveCacheToStorage() {\n      var _this3 = this;\n      return _asyncToGenerator(function* () {\n        try {\n          if (typeof chrome !== 'undefined' && chrome.storage?.session) {\n            yield chrome.storage.session.set({\n              [STORAGE_KEY]: _this3.#cache\n            });\n          }\n        } catch (error) {\n          console.error('Failed to save relay list cache to storage:', error);\n        }\n      })();\n    }\n    /**\n     * Remove stale entries from cache\n     */\n    #pruneStaleCache() {\n      const now = Date.now();\n      for (const pubkey of Object.keys(this.#cache)) {\n        if (now - this.#cache[pubkey].fetchedAt > CACHE_TTL_MS) {\n          delete this.#cache[pubkey];\n        }\n      }\n    }\n    /**\n     * Get the SimplePool instance, creating it if necessary\n     */\n    #getPool() {\n      if (!this.#pool) {\n        this.#pool = new SimplePool();\n      }\n      return this.#pool;\n    }\n    /**\n     * Get cached relay list for a pubkey\n     */\n    getCachedRelayList(pubkey) {\n      const cached = this.#cache[pubkey];\n      if (!cached) {\n        return null;\n      }\n      if (Date.now() - cached.fetchedAt > CACHE_TTL_MS) {\n        delete this.#cache[pubkey];\n        return null;\n      }\n      return cached.relays;\n    }\n    /**\n     * Fetch NIP-65 relay list for a single pubkey\n     */\n    fetchRelayList(pubkey) {\n      var _this4 = this;\n      return _asyncToGenerator(function* () {\n        yield _this4.initialize();\n        // Check cache first\n        const cached = _this4.getCachedRelayList(pubkey);\n        if (cached) {\n          return cached;\n        }\n        // Check if already fetching\n        const existingPromise = _this4.#fetchPromises.get(pubkey);\n        if (existingPromise) {\n          return existingPromise;\n        }\n        // Start new fetch\n        const fetchPromise = _this4.#doFetchRelayList(pubkey);\n        _this4.#fetchPromises.set(pubkey, fetchPromise);\n        try {\n          const result = yield fetchPromise;\n          return result;\n        } finally {\n          _this4.#fetchPromises.delete(pubkey);\n        }\n      })();\n    }\n    /**\n     * Internal method to fetch a single relay list\n     */\n    #doFetchRelayList(pubkey) {\n      var _this5 = this;\n      return _asyncToGenerator(function* () {\n        const pool = _this5.#getPool();\n        try {\n          const events = yield _this5.#queryWithTimeout(pool, FALLBACK_PROFILE_RELAYS, [{\n            kinds: [10002],\n            authors: [pubkey]\n          }], FETCH_TIMEOUT_MS);\n          if (events.length === 0) {\n            return [];\n          }\n          // Get the most recent event (kind 10002 is replaceable)\n          const latestEvent = events.reduce((latest, event) => event.created_at > latest.created_at ? event : latest);\n          // Parse relay tags\n          const relays = [];\n          for (const tag of latestEvent.tags) {\n            if (tag[0] === 'r' && tag[1]) {\n              const url = tag[1];\n              const marker = tag[2]; // Optional: \"read\" or \"write\"\n              let read = true;\n              let write = true;\n              if (marker === 'read') {\n                write = false;\n              } else if (marker === 'write') {\n                read = false;\n              }\n              // No marker means both read and write\n              relays.push({\n                url,\n                read,\n                write\n              });\n            }\n          }\n          // Cache the result\n          _this5.#cache[pubkey] = {\n            pubkey,\n            relays,\n            fetchedAt: Date.now()\n          };\n          yield _this5.#saveCacheToStorage();\n          return relays;\n        } catch (error) {\n          console.error(`Failed to fetch relay list for ${pubkey}:`, error);\n          return [];\n        }\n      })();\n    }\n    /**\n     * Query relays with a timeout\n     */\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    #queryWithTimeout(pool, relays, filters, timeoutMs) {\n      return _asyncToGenerator(function* () {\n        return new Promise(resolve => {\n          // eslint-disable-next-line @typescript-eslint/no-explicit-any\n          const events = [];\n          let settled = false;\n          const timeout = setTimeout(() => {\n            if (!settled) {\n              settled = true;\n              resolve(events);\n            }\n          }, timeoutMs);\n          const sub = pool.subscribeMany(relays, filters, {\n            onevent(event) {\n              events.push(event);\n            },\n            oneose() {\n              if (!settled) {\n                settled = true;\n                clearTimeout(timeout);\n                sub.close();\n                resolve(events);\n              }\n            }\n          });\n        });\n      })();\n    }\n    /**\n     * Clear the cache\n     */\n    clearCache() {\n      var _this6 = this;\n      return _asyncToGenerator(function* () {\n        _this6.#cache = {};\n        yield _this6.#saveCacheToStorage();\n      })();\n    }\n    /**\n     * Clear cache for a specific pubkey\n     */\n    clearCacheForPubkey(pubkey) {\n      var _this7 = this;\n      return _asyncToGenerator(function* () {\n        delete _this7.#cache[pubkey];\n        yield _this7.#saveCacheToStorage();\n      })();\n    }\n    static ɵfac = function RelayListService_Factory(__ngFactoryType__) {\n      return new (__ngFactoryType__ || RelayListService)();\n    };\n    static ɵprov = /*@__PURE__*/i0.ɵɵdefineInjectable({\n      token: RelayListService,\n      factory: RelayListService.ɵfac,\n      providedIn: 'root'\n    });\n  }\n  return RelayListService;\n})();","map":null,"metadata":{},"sourceType":"module","externalDependencies":[]}