{"version":3,"file":"storage.mjs","names":[],"sources":["../../src/lib/storage.ts"],"sourcesContent":["import assert from 'assert';\nimport async from 'async';\nimport buildDebug from 'debug';\nimport _ from 'lodash';\nimport Stream from 'stream';\n\nimport { hasProxyTo } from '@verdaccio/config';\nimport { PLUGIN_CATEGORY, pluginUtils, validationUtils } from '@verdaccio/core';\nimport { asyncLoadPlugin } from '@verdaccio/loaders';\nimport LocalDatabasePluginModule from '@verdaccio/local-storage-legacy';\nimport { SearchMemoryIndexer } from '@verdaccio/search-indexer';\nimport { ReadTarball } from '@verdaccio/streams';\nimport {\n  Callback,\n  Config,\n  DistFile,\n  Logger,\n  Manifest,\n  MergeTags,\n  Version,\n  Versions,\n} from '@verdaccio/types';\nimport { GenericBody, Token, TokenFilter } from '@verdaccio/types';\n\nimport { StoragePluginLegacy } from '../../types/custom';\nimport { logger } from '../lib/logger';\nimport { IPluginFilters, ISyncUplinks, StringValue } from '../types';\nimport { API_ERROR, DIST_TAGS, HTTP_STATUS } from './constants';\nimport LocalStorage, { StoragePlugin } from './local-storage';\nimport { mergeVersions } from './metadata-utils';\nimport {\n  checkPackageLocal,\n  checkPackageRemote,\n  cleanUpLinksRef,\n  convertAbbreviatedManifest,\n  generatePackageTemplate,\n  lookupDistFile,\n  mergeUplinkTimeIntoLocal,\n  publishPackage,\n} from './storage-utils';\nimport ProxyStorage from './up-storage';\nimport { setupUpLinks, updateVersionsHiddenUpLink } from './uplink-util';\nimport { ErrorCode, hasTarball, isObject, normalizeDistTags } from './utils';\n\nconst debug = buildDebug('verdaccio:storage');\n\nclass Storage {\n  public localStorage: LocalStorage;\n  public config: Config;\n  public logger: Logger;\n  public uplinks: Record<string, ProxyStorage>;\n  public filters: IPluginFilters | undefined;\n\n  public constructor(config: Config) {\n    this.config = config;\n    this.uplinks = setupUpLinks(config);\n    this.logger = logger;\n    // @ts-ignore\n    this.localStorage = null;\n  }\n\n  /**\n   * Initialize the storage: load the storage plugin (or the default\n   * local storage) and the filter plugins. Safe to call once; subsequent\n   * calls only reload missing filters.\n   * @param {Config} config verdaccio configuration\n   * @param {IPluginFilters} filters preloaded filter plugins; when omitted they are loaded from the configuration\n   */\n  public async init(config: Config, filters?: IPluginFilters): Promise<void> {\n    if (this.localStorage === null) {\n      this.filters = filters;\n      const storageInstance = await this.loadStorage(config, this.logger);\n      this.localStorage = new LocalStorage(this.config, logger, storageInstance);\n      await this.localStorage.getSecret(config);\n      debug('initialization completed');\n    } else {\n      debug('storage has been already initialized');\n    }\n\n    if (!this.filters) {\n      this.filters = await asyncLoadPlugin<pluginUtils.ManifestFilter<unknown>>(\n        this.config.filters,\n        {\n          config: this.config,\n          logger: this.logger,\n        },\n        (plugin: pluginUtils.ManifestFilter<Config>) => {\n          return typeof plugin.filter_metadata !== 'undefined';\n        },\n        true,\n        this.config?.serverSettings?.pluginPrefix,\n        PLUGIN_CATEGORY.FILTER\n      );\n      debug('filters available %o', this.filters.length);\n    }\n  }\n\n  /**\n   * Resolve the storage backend: a configured storage plugin when available,\n   * otherwise the default `@verdaccio/local-storage` on the configured path.\n   * @return {Promise<StoragePlugin>} the storage plugin instance\n   */\n  private async loadStorage(config: Config, logger: Logger): Promise<StoragePlugin> {\n    const Storage = await this.loadStorePlugin();\n    if (_.isNil(Storage)) {\n      assert(this.config.storage, 'CONFIG: storage path not defined');\n      debug('no custom storage found, loading default storage @verdaccio/local-storage');\n      // the package is CJS with an `exports.default`; in the ESM build the default\n      // import is the whole `module.exports`, so unwrap `.default` when present\n      const LocalDatabasePlugin =\n        (LocalDatabasePluginModule as unknown as { default?: typeof LocalDatabasePluginModule })\n          .default ?? LocalDatabasePluginModule;\n      const localStorage = new LocalDatabasePlugin(config, logger);\n      logger.info(\n        { name: '@verdaccio/local-storage', pluginCategory: PLUGIN_CATEGORY.STORAGE },\n        'plugin @{name} successfully loaded (@{pluginCategory})'\n      );\n      return localStorage;\n    }\n    return Storage as StoragePlugin;\n  }\n\n  /**\n   * Load the storage plugins declared under `store` in the configuration.\n   * Only one storage is supported: with several plugins configured the\n   * first loaded one wins and a warning is logged.\n   * @return {Promise<StoragePluginLegacy<Config> | undefined>} the selected plugin, or undefined when none is configured\n   */\n  private async loadStorePlugin(): Promise<StoragePluginLegacy<Config> | undefined> {\n    const plugins: StoragePluginLegacy<Config>[] = await asyncLoadPlugin<\n      pluginUtils.Storage<unknown>\n    >(\n      this.config.store,\n      {\n        config: this.config,\n        logger: this.logger,\n      },\n      (plugin) => {\n        return typeof plugin.getPackageStorage !== 'undefined';\n      },\n      true,\n      this.config?.serverSettings?.pluginPrefix,\n      PLUGIN_CATEGORY.STORAGE\n    );\n\n    if (plugins.length > 1) {\n      this.logger.warn(\n        'more than one storage plugins has been detected, multiple storage are not supported, one will be selected automatically'\n      );\n    }\n\n    return _.head(plugins);\n  }\n\n  /**\n   * Add a package to the system (publish flow).\n   * Verifies the package does not exist locally nor on any uplink before\n   * creating it locally; uplinks being offline rejects the publish unless\n   * `publish.allow_offline` is enabled.\n   * Used storages: local (write) && uplinks\n   * @param {String} name package name\n   * @param {Object} metadata package manifest to publish\n   * @param {Function} callback invoked with an error when the publish is rejected\n   */\n  public async addPackage(name: string, metadata: any, callback: any): Promise<void> {\n    debug('add package %o', name);\n    try {\n      await checkPackageLocal(name, this.localStorage);\n      await checkPackageRemote(\n        name,\n        this._isAllowPublishOffline(),\n        this._syncUplinksMetadata.bind(this)\n      );\n      await publishPackage(name, metadata, this.localStorage);\n      callback();\n    } catch (err: any) {\n      callback(err);\n    }\n  }\n\n  /**\n   * Whether `publish.allow_offline` is enabled in the configuration.\n   * @return {Boolean} true when publishing with unreachable uplinks is allowed\n   */\n  private _isAllowPublishOffline(): boolean {\n    return (\n      typeof this.config.publish !== 'undefined' &&\n      _.isBoolean(this.config.publish.allow_offline) &&\n      this.config.publish.allow_offline\n    );\n  }\n\n  /**\n   * Read the npm tokens matching the filter from the token storage.\n   * Used storages: local (read)\n   */\n  public readTokens(filter: TokenFilter): Promise<Token[]> {\n    return this.localStorage.readTokens(filter);\n  }\n\n  /**\n   * Save an npm token to the token storage.\n   * Used storages: local (write)\n   */\n  public saveToken(token: Token): Promise<void> {\n    return this.localStorage.saveToken(token);\n  }\n\n  /**\n   * Delete an npm token from the token storage.\n   * Used storages: local (write)\n   */\n  public deleteToken(user: string, tokenKey: string): Promise<any> {\n    return this.localStorage.deleteToken(user, tokenKey);\n  }\n\n  /**\n   * Add a new version of a package to the system.\n   * Used storages: local (write)\n   * @param {String} name package name\n   * @param {String} version version id, eg. 1.0.0\n   * @param {Version} metadata version metadata\n   * @param {String} tag dist-tag pointing to the version\n   * @param {Function} callback\n   */\n  public addVersion(\n    name: string,\n    version: string,\n    metadata: Version,\n    tag: StringValue,\n    callback: Callback\n  ): void {\n    debug('add version %s package for %s', version, name);\n    this.localStorage.addVersion(name, version, metadata, tag, callback);\n  }\n\n  /**\n   * Tag package versions with the provided dist-tags.\n   * Used storages: local (write)\n   * @param {String} name package name\n   * @param {MergeTags} tagHash dist-tag to version mapping to merge\n   * @param {Function} callback\n   */\n  public mergeTags(name: string, tagHash: MergeTags, callback: Callback): void {\n    debug('merge tags for %o', name);\n    this.localStorage.mergeTags(name, tagHash, callback);\n  }\n\n  /**\n   * Change an existing package (eg. unpublish one version).\n   * Used storages: local (write)\n   * @param {String} name package name\n   * @param {Manifest} metadata updated package manifest\n   * @param {String} revision expected revision of the stored manifest\n   * @param {Function} callback\n   */\n  public changePackage(\n    name: string,\n    metadata: Manifest,\n    revision: string,\n    callback: Callback\n  ): void {\n    debug('change existing package for package %o revision %o', name, revision);\n    this.localStorage.changePackage(name, metadata, revision, callback);\n  }\n\n  /**\n   * Remove a package from the local storage and the search indexer.\n   * Used storages: local (write)\n   * @param {String} name package name\n   * @param {Function} callback\n   */\n  public removePackage(name: string, callback: Callback): void {\n    debug('remove package %o', name);\n    this.localStorage.removePackage(name, callback);\n    // update the indexer\n    SearchMemoryIndexer.remove(name).catch((reason) => {\n      debug('indexer has failed on remove item %o', reason);\n      logger.error('indexer has failed on remove item');\n    });\n  }\n\n  /**\n   * Remove a tarball from the local storage. The tarball must not be\n   * linked by any existing version, ie. the version should be\n   * unpublished first.\n   * Used storages: local (write)\n   * @param {String} name package name\n   * @param {String} filename tarball file name\n   * @param {String} revision expected revision of the stored manifest\n   * @param {Function} callback\n   */\n  public removeTarball(name: string, filename: string, revision: string, callback: Callback): void {\n    debug('remove tarball %s for %s', filename, name);\n    this.localStorage.removeTarball(name, filename, revision, callback);\n  }\n\n  /**\n   * Upload a tarball (publish flow). Synchronous, returns a writable\n   * stream the tarball body is piped into.\n   * Used storages: local (write)\n   * @param {String} name package name\n   * @param {String} filename tarball file name\n   * @return {Stream} writable upload stream\n   */\n  public addTarball(name: string, filename: string) {\n    debug('add a tarball for %o', name);\n    return this.localStorage.addTarball(name, filename);\n  }\n\n  /**\n   * Whether a tarball exists in the local storage, without reading it\n   * (the stream is aborted as soon as it opens).\n   * Used storages: local (read)\n   * @param {String} name package name\n   * @param {String} filename tarball file name\n   * @return {Promise<Boolean>} true when the tarball is stored locally\n   */\n  public hasLocalTarball(name: string, filename: string): Promise<boolean> {\n    const self = this;\n    return new Promise<boolean>((resolve, reject): void => {\n      let localStream: any = self.localStorage.getTarball(name, filename);\n      let isOpen = false;\n      localStream.on('error', (err): any => {\n        if (isOpen || err.status !== HTTP_STATUS.NOT_FOUND) {\n          reject(err);\n        }\n        // local reported 404 or request was aborted already\n        if (localStream) {\n          localStream.abort();\n          localStream = null;\n        }\n        resolve(false);\n      });\n      localStream.on('open', function (): void {\n        isOpen = true;\n        localStream.abort();\n        localStream = null;\n        resolve(true);\n      });\n    });\n  }\n\n  /**\n   * Get a tarball. Synchronous, returns a readable stream.\n   * The tarball is read locally first; on a local miss the distfile record\n   * is resolved from the package metadata (see lookupDistFile), syncing the\n   * uplinks when the local metadata does not know the file, and the tarball\n   * is then fetched from the uplink that serves the distfile url.\n   * Used storages: local || uplink (just one)\n   * @param {String} name package name\n   * @param {String} filename tarball file name\n   * @return {Stream} readable tarball stream\n   */\n  public getTarball(name: string, filename: string) {\n    debug('get tarball for package %o filename %o', name, filename);\n    const readStream = new ReadTarball({});\n    readStream.abort = function () {};\n\n    const self = this;\n\n    // Check if the tarball is allowed by filter plugins before serving.\n    // Filters may block specific versions, so we verify the tarball's version\n    // still exists in the filtered metadata.\n    this._isTarballAllowedByFilters(name, filename).then(async (allowed) => {\n      if (!allowed) {\n        readStream.emit('error', ErrorCode.getNotFound(API_ERROR.NO_PACKAGE));\n        return;\n      }\n\n      // trying local first\n      let localStream: any = self.localStorage.getTarball(name, filename);\n      let isOpen = false;\n      localStream.on('error', (err): any => {\n        if (isOpen || err.status !== HTTP_STATUS.NOT_FOUND) {\n          return readStream.emit('error', err);\n        }\n\n        // local reported 404\n        const err404 = err;\n        localStream.abort();\n        localStream = null; // we force for garbage collector\n\n        const lookupFromUplinks = (info: Manifest | null): void => {\n          self._syncUplinksMetadata(\n            name,\n            info as Manifest,\n            {},\n            (syncErr, syncInfo: Manifest): any => {\n              if (_.isNil(syncErr) === false) {\n                return readStream.emit('error', syncErr);\n              }\n              // _syncUplinksMetadata returns filter-applied metadata; if the\n              // version was removed by a filter, surface a 404 like a missing tarball.\n              if (self.filters?.length && !hasTarball(syncInfo, filename)) {\n                return readStream.emit('error', err404);\n              }\n              const distFile = lookupDistFile(syncInfo, filename);\n              if (_.isNil(distFile)) {\n                debug('remote tarball not found');\n                return readStream.emit('error', err404);\n              }\n              debug('dist file found, using it %o', (distFile as DistFile).url);\n              serveFile(distFile as DistFile);\n            }\n          );\n        };\n\n        self.localStorage.getPackageMetadataAsync(name).then(\n          (info) => {\n            const distFile = lookupDistFile(info, filename);\n            if (_.isNil(distFile) === false) {\n              // information about this file exists locally\n              debug('dist file found, using it %o', (distFile as DistFile).url);\n              serveFile(distFile as DistFile);\n            } else {\n              // we know nothing about this file, trying to get information elsewhere\n              debug('dist file not found, proceed update upstream');\n              lookupFromUplinks(info);\n            }\n          },\n          () => {\n            // we know nothing about this file, trying to get information elsewhere\n            lookupFromUplinks(null);\n          }\n        );\n      });\n      localStream.on('content-length', function (v): void {\n        readStream.emit('content-length', v);\n      });\n      localStream.on('open', function (): void {\n        isOpen = true;\n        localStream.pipe(readStream);\n      });\n    });\n\n    return readStream;\n\n    /**\n     * Stream the tarball from the uplink serving the distfile, caching it\n     * locally (and restoring the distfile record) when the uplink has the\n     * cache enabled.\n     * @param {DistFile} file distfile record resolved for the tarball\n     */\n    function serveFile(file: DistFile): void {\n      let uplink: any = null;\n\n      if (file.registry && self.uplinks[file.registry]) {\n        // the distfile records which uplink it was merged from\n        // (see LocalStorage._updateUplinkToRemoteProtocol)\n        uplink = self.uplinks[file.registry];\n        debug('tarball %o is served by the recorded uplink %o', filename, file.registry);\n      } else {\n        const candidates: any[] = [];\n        for (const uplinkId in self.uplinks) {\n          if (hasProxyTo(name, uplinkId, self.config.packages)) {\n            candidates.push(self.uplinks[uplinkId]);\n          }\n        }\n        debug('tarball %o has %o candidate uplinks', filename, candidates.length);\n\n        // pick the uplink that actually serves the distfile url, so the\n        // request carries the settings of the registry hosting it; with\n        // several matching uplinks (duplicated urls) the last configured\n        // one keeps winning, exactly like the previous selection did\n        for (const candidate of candidates) {\n          if (candidate.isUplinkValid(file.url)) {\n            uplink = candidate;\n          }\n        }\n\n        if (uplink !== null) {\n          debug('uplink %o url matches tarball %o', uplink.upname, file.url);\n        } else if (candidates.length === 1) {\n          // a single configured uplink keeps the legacy behavior: tarballs\n          // hosted elsewhere (a CDN) may still need its agent/proxy settings\n          uplink = candidates[0];\n          debug(\n            'using the single configured uplink %o for tarball %o hosted elsewhere',\n            uplink.upname,\n            file.url\n          );\n        }\n      }\n\n      if (uplink == null) {\n        debug('upstream not found, creating one for %o', name);\n        uplink = new ProxyStorage(\n          {\n            url: file.url,\n            cache: true,\n            _autogenerated: true,\n          },\n          self.config\n        );\n      }\n\n      let savestream: any = null;\n      if (uplink.config.cache) {\n        // persist which configured uplink served the tarball, so future\n        // fetches can pick it directly (autogenerated proxies have no name)\n        debug('cache remote tarball enabled');\n        let distFile: DistFile = file;\n        if (!file.registry && uplink.upname) {\n          debug('recording uplink %o on the persisted distfile for %o', uplink.upname, filename);\n          distFile = { ...file, registry: uplink.upname };\n        }\n        savestream = self.localStorage.addTarball(name, filename, distFile);\n      } else {\n        debug('cache remote tarball disabled');\n      }\n\n      let on_open = function (): void {\n        // prevent it from being called twice\n        on_open = function () {};\n        const rstream2 = uplink.fetchTarball(file.url);\n        rstream2.on('error', function (err): void {\n          if (savestream) {\n            savestream.abort();\n          }\n          savestream = null;\n          readStream.emit('error', err);\n        });\n        rstream2.on('end', function (): void {\n          if (savestream) {\n            savestream.done();\n          }\n        });\n\n        rstream2.on('content-length', function (v): void {\n          readStream.emit('content-length', v);\n          if (savestream) {\n            savestream.emit('content-length', v);\n          }\n        });\n        rstream2.pipe(readStream);\n        if (savestream) {\n          rstream2.pipe(savestream);\n        }\n      };\n\n      if (savestream) {\n        savestream.on('open', function (): void {\n          on_open();\n        });\n\n        savestream.on('error', function (err): void {\n          self.logger.warn(\n            { err: err, fileName: file },\n            'error saving file @{fileName}: @{err.message}\\n@{err.stack}'\n          );\n          if (savestream) {\n            savestream.abort();\n          }\n          savestream = null;\n          on_open();\n        });\n      } else {\n        on_open();\n      }\n    }\n  }\n\n  /**\n   * Retrieve the package metadata: the local manifest merged with the\n   * manifest of every uplink with proxy access to the package.\n   * Used storages: local && uplink (proxy_access)\n   * @param {Object} options\n   * @property {String} options.name package name\n   * @property {Object} options.req Express `req` object\n   * @property {Boolean} options.keepUpLinkData keep the uplink info (last update, etc.) in the package metadata\n   * @property {Boolean} options.abbreviated serve the abbreviated manifest (npm install)\n   * @property {Function} options.callback invoked with the merged manifest and any uplink errors\n   */\n  public getPackage(options): void {\n    debug('get package for %o', options.name);\n    this.localStorage.getPackageMetadata(options.name, (err, data): void => {\n      if (err && (!err.status || err.status >= HTTP_STATUS.INTERNAL_ERROR)) {\n        // report internal errors right away\n        return options.callback(err);\n      }\n\n      this._syncUplinksMetadata(\n        options.name,\n        data,\n        { req: options.req, uplinksLook: options.uplinksLook },\n        function getPackageSynUpLinksCallback(err, result: Manifest, uplinkErrors): void {\n          if (err) {\n            return options.callback(err);\n          }\n\n          normalizeDistTags(cleanUpLinksRef(options.keepUpLinkData, result));\n\n          // npm can throw if this field doesn't exist\n          result._attachments = {};\n          if (options.abbreviated === true) {\n            debug('get abbreviated manifest');\n            options.callback(null, convertAbbreviatedManifest(result), uplinkErrors);\n          } else {\n            debug('get full package manifest');\n            options.callback(null, result, uplinkErrors);\n          }\n        }\n      );\n    });\n  }\n\n  /**\n   * Retrieve remote and local packages more recent than the start key.\n   * All uplinks are streamed first, then the local packages; local\n   * packages can override registry ones just because they appear in the\n   * JSON last — a trade-off made to avoid memory issues.\n   * Used storages: local && uplink (proxy_access)\n   * @param {String} startkey timestamp to search from\n   * @param {Object} options request options; `local=1` in the query skips the uplinks\n   * @return {Stream} object stream of search results\n   */\n  public search(startkey: string, options: any) {\n    const self = this;\n    const searchStream: any = new Stream.PassThrough({ objectMode: true });\n    async.eachSeries(\n      Object.keys(this.uplinks),\n      function (up_name, cb): void {\n        // shortcut: if `local=1` is supplied, don't call uplinks\n        if (options.req?.query?.local !== undefined) {\n          return cb();\n        }\n        logger.info(`search for uplink ${up_name}`);\n        // search by keyword for each uplink\n        const uplinkStream = self.uplinks[up_name].search(options);\n        // join uplink stream with streams PassThrough\n        uplinkStream.pipe(searchStream, { end: false });\n        uplinkStream.on('error', function (err): void {\n          self.logger.error({ err: err }, 'uplink error: @{err.message}');\n          cb();\n          // to avoid call callback more than once\n          cb = function (): void {};\n        });\n        uplinkStream.on('end', function (): void {\n          cb();\n          // to avoid call callback more than once\n          cb = function (): void {};\n        });\n\n        searchStream.abort = function (): void {\n          if (uplinkStream.abort) {\n            uplinkStream.abort();\n          }\n          cb();\n          // to avoid call callback more than once\n          cb = function (): void {};\n        };\n      },\n      // executed after all series\n      function (): void {\n        // attach a local search results\n        const localSearchStream = self.localStorage.search(startkey, options);\n        searchStream.abort = function (): void {\n          localSearchStream.abort();\n        };\n        localSearchStream.pipe(searchStream, { end: true });\n        localSearchStream.on('error', function (err: any): void {\n          self.logger.error({ err: err }, 'search error: @{err.message}');\n          searchStream.end();\n        });\n      }\n    );\n\n    return searchStream;\n  }\n\n  /**\n   * Retrieve only private local packages, as the latest version of each.\n   * Used storages: local (read)\n   * @param {Function} callback invoked with the list of latest versions\n   */\n  public getLocalDatabase(callback: Callback): void {\n    this.localStorage.storagePlugin.get((err, locals): void => {\n      if (err) {\n        return callback(err);\n      }\n\n      this._collectLocalPackages(locals).then(\n        (packages) => callback(null, packages),\n        (err) => callback(err)\n      );\n    });\n  }\n\n  /**\n   * Read each local package name, apply filters, and collect the latest version.\n   */\n  private async _collectLocalPackages(locals: string[]): Promise<Version[]> {\n    const packages: Version[] = [];\n    for (const name of locals) {\n      try {\n        const pkgMetadata = await this.localStorage.getPackageMetadataAsync(name);\n        const { filteredPackage } = await this._applyFilters(pkgMetadata);\n        const latest = filteredPackage[DIST_TAGS]?.latest;\n        if (latest && filteredPackage.versions[latest]) {\n          const version: Version = filteredPackage.versions[latest];\n          const timeList = filteredPackage.time as GenericBody;\n          const time = timeList[latest];\n          // @ts-ignore\n          version.time = time;\n\n          // Add for stars api\n          // @ts-ignore\n          version.users = filteredPackage.users;\n\n          packages.push(version);\n        } else {\n          this.logger.warn({ package: name }, 'package @{package} does not have a \"latest\" tag?');\n        }\n      } catch (err) {\n        this.logger.error({ err, package: name }, 'error reading package @{package}');\n      }\n    }\n    return packages;\n  }\n\n  /**\n   * Fetch the package metadata from every uplink with proxy access and\n   * synchronize it with the local data; filter plugins are applied to the\n   * merged result.\n   * @param {String} name package name\n   * @param {Manifest} packageInfo local manifest; MUST be provided when the package exists locally\n   * @param {ISyncUplinks} options uplink request options\n   * @param {Function} callback invoked with (err, mergedManifest, uplinkErrors)\n   */\n  public _syncUplinksMetadata(\n    name: string,\n    packageInfo: Manifest,\n    options: ISyncUplinks,\n    callback: Callback\n  ): void {\n    let found = true;\n    const self = this;\n    const upLinks: ProxyStorage[] = [];\n    const hasToLookIntoUplinks = _.isNil(options.uplinksLook) || options.uplinksLook;\n\n    debug('sync uplinks for %o', name);\n    debug('is sync uplink enabled %o', hasToLookIntoUplinks);\n    if (!packageInfo) {\n      debug('local package %s not found', name);\n      found = false;\n      packageInfo = generatePackageTemplate(name);\n    }\n\n    for (const uplink in this.uplinks) {\n      if (hasProxyTo(name, uplink, this.config.packages) && hasToLookIntoUplinks) {\n        upLinks.push(this.uplinks[uplink]);\n      }\n    }\n    debug('uplinks found for %o: %o', name, upLinks.length);\n\n    async.map(\n      upLinks,\n      (upLink: ProxyStorage, cb): void => {\n        const _options = Object.assign({}, options);\n        const upLinkMeta = packageInfo._uplinks[upLink.upname];\n\n        if (isObject(upLinkMeta)) {\n          const fetched = upLinkMeta.fetched;\n\n          if (fetched && Date.now() - fetched < upLink.maxage) {\n            debug('returning cached manifest for %o', upLink.upname);\n            return cb();\n          }\n\n          _options.etag = upLinkMeta.etag;\n        }\n\n        upLink.getRemoteMetadata(name, _options, (err, upLinkResponse, eTag): void => {\n          if (err && err.remoteStatus === 304) {\n            debug('uplink %o responded 304 for %o, cache is up to date', upLink.upname, name);\n            upLinkMeta.fetched = Date.now();\n          }\n\n          if (err || !upLinkResponse) {\n            debug('error captured on uplink %o for %o: %o', upLink.upname, name, err?.message);\n            return cb(null, [err || ErrorCode.getInternalError('no data')]);\n          }\n\n          try {\n            upLinkResponse = validationUtils.normalizeMetadata(upLinkResponse, name);\n          } catch (err) {\n            self.logger.error(\n              {\n                sub: 'out',\n                err: err,\n              },\n              'package.json validating error @{!err.message}\\n@{err.stack}'\n            );\n            return cb(null, [err]);\n          }\n\n          packageInfo._uplinks[upLink.upname] = {\n            etag: eTag,\n            fetched: Date.now(),\n          };\n\n          packageInfo = mergeUplinkTimeIntoLocal(packageInfo, upLinkResponse);\n\n          updateVersionsHiddenUpLink(upLinkResponse.versions, upLink);\n\n          try {\n            mergeVersions(packageInfo, upLinkResponse);\n          } catch (err) {\n            self.logger.error(\n              {\n                sub: 'out',\n                err: err,\n              },\n              'package.json parsing error @{!err.message}\\n@{err.stack}'\n            );\n            return cb(null, [err]);\n          }\n\n          // if we got to this point, assume that the correct package exists\n          // on the uplink\n          debug('syncing on uplink %o', upLink.upname);\n          found = true;\n          cb();\n        });\n      },\n      // @ts-ignore\n      async (err: Error, upLinksErrors: any): Promise<void> => {\n        assert(!err && Array.isArray(upLinksErrors));\n\n        // Check for connection timeout or reset errors with uplink(s)\n        // (these should be handled differently from the package not being found)\n        if (!found) {\n          let uplinkTimeoutError;\n          for (let i = 0; i < upLinksErrors.length; i++) {\n            if (upLinksErrors[i]) {\n              for (let j = 0; j < upLinksErrors[i].length; j++) {\n                if (upLinksErrors[i][j]) {\n                  const code = upLinksErrors[i][j].code;\n                  if (code === 'ETIMEDOUT' || code === 'ESOCKETTIMEDOUT' || code === 'ECONNRESET') {\n                    uplinkTimeoutError = true;\n                    break;\n                  }\n                }\n              }\n            }\n          }\n\n          if (uplinkTimeoutError) {\n            debug('uplinks sync failed with timeout error');\n            return callback(ErrorCode.getServiceUnavailable(), null, upLinksErrors);\n          }\n          debug('uplinks sync failed with no package found');\n          return callback(ErrorCode.getNotFound(API_ERROR.NO_PACKAGE), null, upLinksErrors);\n        }\n\n        if (upLinks.length === 0) {\n          debug('no uplinks found for %o, upstream update aborted', name);\n          const { filteredPackage, filterErrors } = await self._applyFilters(\n            packageInfo as Manifest\n          );\n          return callback(null, filteredPackage, filterErrors);\n        }\n\n        try {\n          const packageJsonLocal = await self.localStorage.updateVersionsAsync(name, packageInfo);\n          const { filteredPackage, filterErrors } = await self._applyFilters(packageJsonLocal);\n          callback(null, filteredPackage, _.concat(upLinksErrors, filterErrors));\n        } catch (err) {\n          callback(err);\n        }\n      }\n    );\n  }\n\n  /**\n   * Apply all configured filter plugins to a package manifest sequentially.\n   * Each filter's output is passed as input to the next filter.\n   * Returns the filtered manifest and any errors that occurred.\n   */\n  private async _applyFilters(\n    packageInfo: Manifest\n  ): Promise<{ filteredPackage: Manifest; filterErrors: Error[] }> {\n    const filterErrors: Error[] = [];\n    let filteredPackage = packageInfo;\n    for (const filter of this.filters ?? []) {\n      try {\n        filteredPackage = await filter.filter_metadata(filteredPackage);\n      } catch (err: any) {\n        debug('filter plugin has failed on %o: %o', packageInfo.name, err?.message);\n        filterErrors.push(err);\n      }\n    }\n    return { filteredPackage, filterErrors };\n  }\n\n  /**\n   * Check if a tarball should be served based on filter plugins, using only\n   * local metadata. Returns true (defer) when the version isn't cached locally\n   * — the uplink-sync path in getTarball re-checks filters after sync, which\n   * avoids a redundant uplink round-trip and double filter application.\n   */\n  private async _isTarballAllowedByFilters(name: string, filename: string): Promise<boolean> {\n    if (!this.filters?.length) {\n      return true;\n    }\n\n    try {\n      const pkgMetadata = await this.localStorage.getPackageMetadataAsync(name);\n      if (!hasTarball(pkgMetadata, filename)) {\n        return true;\n      }\n      const { filteredPackage } = await this._applyFilters(pkgMetadata);\n      const allowed = hasTarball(filteredPackage, filename);\n      if (allowed === false) {\n        debug('tarball %o of %o is blocked by a filter plugin', filename, name);\n      }\n      return allowed;\n    } catch (err: any) {\n      if (err?.status === HTTP_STATUS.NOT_FOUND) {\n        return true;\n      }\n      this.logger.error(\n        { package: name, fileName: filename, err },\n        'error checking filters for tarball @{fileName} of package @{package}: @{err.message}'\n      );\n      return true;\n    }\n  }\n\n  /**\n   * Tag each version with the uplink it was fetched from, under a hidden\n   * (symbol) key. The local storage uses the tag to record the registry\n   * on the distfile records it creates.\n   * @param {Versions} versions versions fetched from the uplink\n   * @param {ProxyStorage} upLink uplink the versions were fetched from\n   */\n  public _updateVersionsHiddenUpLink(versions: Versions, upLink: ProxyStorage): void {\n    for (const i in versions) {\n      if (Object.prototype.hasOwnProperty.call(versions, i)) {\n        const version = versions[i];\n\n        // holds a \"hidden\" value to be used by the package storage.\n        version[Symbol.for('__verdaccio_uplink')] = upLink.upname;\n      }\n    }\n  }\n}\n\nexport default Storage;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA4CA,IAAM,QAAQ,YAAW,mBAAmB;AAE5C,IAAM,UAAN,MAAc;CACZ;CACA;CACA;CACA;CACA;CAEA,YAAmB,QAAgB;EACjC,KAAK,SAAS;EACd,KAAK,UAAU,aAAa,MAAM;EAClC,KAAK,SAAS;EAEd,KAAK,eAAe;CACtB;;;;;;;;CASA,MAAa,KAAK,QAAgB,SAAyC;EACzE,IAAI,KAAK,iBAAiB,MAAM;GAC9B,KAAK,UAAU;GACf,MAAM,kBAAkB,MAAM,KAAK,YAAY,QAAQ,KAAK,MAAM;GAClE,KAAK,eAAe,IAAI,aAAa,KAAK,QAAQ,QAAQ,eAAe;GACzE,MAAM,KAAK,aAAa,UAAU,MAAM;GACxC,MAAM,0BAA0B;EAClC,OACE,MAAM,sCAAsC;EAG9C,IAAI,CAAC,KAAK,SAAS;GACjB,KAAK,UAAU,MAAM,gBACnB,KAAK,OAAO,SACZ;IACE,QAAQ,KAAK;IACb,QAAQ,KAAK;GACf,IACC,WAA+C;IAC9C,OAAO,OAAO,OAAO,oBAAoB;GAC3C,GACA,MACA,KAAK,QAAQ,gBAAgB,cAC7B,gBAAgB,MAClB;GACA,MAAM,wBAAwB,KAAK,QAAQ,MAAM;EACnD;CACF;;;;;;CAOA,MAAc,YAAY,QAAgB,QAAwC;EAChF,MAAM,UAAU,MAAM,KAAK,gBAAgB;EAC3C,IAAI,EAAE,MAAM,OAAO,GAAG;GACpB,OAAO,KAAK,OAAO,SAAS,kCAAkC;GAC9D,MAAM,2EAA2E;GAMjF,MAAM,eAAe,KAFlB,0BACE,WAAW,2BAC6B,QAAQ,MAAM;GAC3D,OAAO,KACL;IAAE,MAAM;IAA4B,gBAAgB,gBAAgB;GAAQ,GAC5E,wDACF;GACA,OAAO;EACT;EACA,OAAO;CACT;;;;;;;CAQA,MAAc,kBAAoE;EAChF,MAAM,UAAyC,MAAM,gBAGnD,KAAK,OAAO,OACZ;GACE,QAAQ,KAAK;GACb,QAAQ,KAAK;EACf,IACC,WAAW;GACV,OAAO,OAAO,OAAO,sBAAsB;EAC7C,GACA,MACA,KAAK,QAAQ,gBAAgB,cAC7B,gBAAgB,OAClB;EAEA,IAAI,QAAQ,SAAS,GACnB,KAAK,OAAO,KACV,yHACF;EAGF,OAAO,EAAE,KAAK,OAAO;CACvB;;;;;;;;;;;CAYA,MAAa,WAAW,MAAc,UAAe,UAA8B;EACjF,MAAM,kBAAkB,IAAI;EAC5B,IAAI;GACF,MAAM,kBAAkB,MAAM,KAAK,YAAY;GAC/C,MAAM,mBACJ,MACA,KAAK,uBAAuB,GAC5B,KAAK,qBAAqB,KAAK,IAAI,CACrC;GACA,MAAM,eAAe,MAAM,UAAU,KAAK,YAAY;GACtD,SAAS;EACX,SAAS,KAAU;GACjB,SAAS,GAAG;EACd;CACF;;;;;CAMA,yBAA0C;EACxC,OACE,OAAO,KAAK,OAAO,YAAY,eAC/B,EAAE,UAAU,KAAK,OAAO,QAAQ,aAAa,KAC7C,KAAK,OAAO,QAAQ;CAExB;;;;;CAMA,WAAkB,QAAuC;EACvD,OAAO,KAAK,aAAa,WAAW,MAAM;CAC5C;;;;;CAMA,UAAiB,OAA6B;EAC5C,OAAO,KAAK,aAAa,UAAU,KAAK;CAC1C;;;;;CAMA,YAAmB,MAAc,UAAgC;EAC/D,OAAO,KAAK,aAAa,YAAY,MAAM,QAAQ;CACrD;;;;;;;;;;CAWA,WACE,MACA,SACA,UACA,KACA,UACM;EACN,MAAM,iCAAiC,SAAS,IAAI;EACpD,KAAK,aAAa,WAAW,MAAM,SAAS,UAAU,KAAK,QAAQ;CACrE;;;;;;;;CASA,UAAiB,MAAc,SAAoB,UAA0B;EAC3E,MAAM,qBAAqB,IAAI;EAC/B,KAAK,aAAa,UAAU,MAAM,SAAS,QAAQ;CACrD;;;;;;;;;CAUA,cACE,MACA,UACA,UACA,UACM;EACN,MAAM,sDAAsD,MAAM,QAAQ;EAC1E,KAAK,aAAa,cAAc,MAAM,UAAU,UAAU,QAAQ;CACpE;;;;;;;CAQA,cAAqB,MAAc,UAA0B;EAC3D,MAAM,qBAAqB,IAAI;EAC/B,KAAK,aAAa,cAAc,MAAM,QAAQ;EAE9C,oBAAoB,OAAO,IAAI,CAAC,CAAC,OAAO,WAAW;GACjD,MAAM,wCAAwC,MAAM;GACpD,OAAO,MAAM,mCAAmC;EAClD,CAAC;CACH;;;;;;;;;;;CAYA,cAAqB,MAAc,UAAkB,UAAkB,UAA0B;EAC/F,MAAM,4BAA4B,UAAU,IAAI;EAChD,KAAK,aAAa,cAAc,MAAM,UAAU,UAAU,QAAQ;CACpE;;;;;;;;;CAUA,WAAkB,MAAc,UAAkB;EAChD,MAAM,wBAAwB,IAAI;EAClC,OAAO,KAAK,aAAa,WAAW,MAAM,QAAQ;CACpD;;;;;;;;;CAUA,gBAAuB,MAAc,UAAoC;EACvE,MAAM,OAAO;EACb,OAAO,IAAI,SAAkB,SAAS,WAAiB;GACrD,IAAI,cAAmB,KAAK,aAAa,WAAW,MAAM,QAAQ;GAClE,IAAI,SAAS;GACb,YAAY,GAAG,UAAU,QAAa;IACpC,IAAI,UAAU,IAAI,WAAW,YAAY,WACvC,OAAO,GAAG;IAGZ,IAAI,aAAa;KACf,YAAY,MAAM;KAClB,cAAc;IAChB;IACA,QAAQ,KAAK;GACf,CAAC;GACD,YAAY,GAAG,QAAQ,WAAkB;IACvC,SAAS;IACT,YAAY,MAAM;IAClB,cAAc;IACd,QAAQ,IAAI;GACd,CAAC;EACH,CAAC;CACH;;;;;;;;;;;;CAaA,WAAkB,MAAc,UAAkB;EAChD,MAAM,0CAA0C,MAAM,QAAQ;EAC9D,MAAM,aAAa,IAAI,YAAY,CAAC,CAAC;EACrC,WAAW,QAAQ,WAAY,CAAC;EAEhC,MAAM,OAAO;EAKb,KAAK,2BAA2B,MAAM,QAAQ,CAAC,CAAC,KAAK,OAAO,YAAY;GACtE,IAAI,CAAC,SAAS;IACZ,WAAW,KAAK,SAAS,UAAU,YAAY,UAAU,UAAU,CAAC;IACpE;GACF;GAGA,IAAI,cAAmB,KAAK,aAAa,WAAW,MAAM,QAAQ;GAClE,IAAI,SAAS;GACb,YAAY,GAAG,UAAU,QAAa;IACpC,IAAI,UAAU,IAAI,WAAW,YAAY,WACvC,OAAO,WAAW,KAAK,SAAS,GAAG;IAIrC,MAAM,SAAS;IACf,YAAY,MAAM;IAClB,cAAc;IAEd,MAAM,qBAAqB,SAAgC;KACzD,KAAK,qBACH,MACA,MACA,CAAC,IACA,SAAS,aAA4B;MACpC,IAAI,EAAE,MAAM,OAAO,MAAM,OACvB,OAAO,WAAW,KAAK,SAAS,OAAO;MAIzC,IAAI,KAAK,SAAS,UAAU,CAAC,WAAW,UAAU,QAAQ,GACxD,OAAO,WAAW,KAAK,SAAS,MAAM;MAExC,MAAM,WAAW,eAAe,UAAU,QAAQ;MAClD,IAAI,EAAE,MAAM,QAAQ,GAAG;OACrB,MAAM,0BAA0B;OAChC,OAAO,WAAW,KAAK,SAAS,MAAM;MACxC;MACA,MAAM,gCAAiC,SAAsB,GAAG;MAChE,UAAU,QAAoB;KAChC,CACF;IACF;IAEA,KAAK,aAAa,wBAAwB,IAAI,CAAC,CAAC,MAC7C,SAAS;KACR,MAAM,WAAW,eAAe,MAAM,QAAQ;KAC9C,IAAI,EAAE,MAAM,QAAQ,MAAM,OAAO;MAE/B,MAAM,gCAAiC,SAAsB,GAAG;MAChE,UAAU,QAAoB;KAChC,OAAO;MAEL,MAAM,8CAA8C;MACpD,kBAAkB,IAAI;KACxB;IACF,SACM;KAEJ,kBAAkB,IAAI;IACxB,CACF;GACF,CAAC;GACD,YAAY,GAAG,kBAAkB,SAAU,GAAS;IAClD,WAAW,KAAK,kBAAkB,CAAC;GACrC,CAAC;GACD,YAAY,GAAG,QAAQ,WAAkB;IACvC,SAAS;IACT,YAAY,KAAK,UAAU;GAC7B,CAAC;EACH,CAAC;EAED,OAAO;;;;;;;EAQP,SAAS,UAAU,MAAsB;GACvC,IAAI,SAAc;GAElB,IAAI,KAAK,YAAY,KAAK,QAAQ,KAAK,WAAW;IAGhD,SAAS,KAAK,QAAQ,KAAK;IAC3B,MAAM,kDAAkD,UAAU,KAAK,QAAQ;GACjF,OAAO;IACL,MAAM,aAAoB,CAAC;IAC3B,KAAK,MAAM,YAAY,KAAK,SAC1B,IAAI,WAAW,MAAM,UAAU,KAAK,OAAO,QAAQ,GACjD,WAAW,KAAK,KAAK,QAAQ,SAAS;IAG1C,MAAM,uCAAuC,UAAU,WAAW,MAAM;IAMxE,KAAK,MAAM,aAAa,YACtB,IAAI,UAAU,cAAc,KAAK,GAAG,GAClC,SAAS;IAIb,IAAI,WAAW,MACb,MAAM,oCAAoC,OAAO,QAAQ,KAAK,GAAG;SAC5D,IAAI,WAAW,WAAW,GAAG;KAGlC,SAAS,WAAW;KACpB,MACE,yEACA,OAAO,QACP,KAAK,GACP;IACF;GACF;GAEA,IAAI,UAAU,MAAM;IAClB,MAAM,2CAA2C,IAAI;IACrD,SAAS,IAAI,aACX;KACE,KAAK,KAAK;KACV,OAAO;KACP,gBAAgB;IAClB,GACA,KAAK,MACP;GACF;GAEA,IAAI,aAAkB;GACtB,IAAI,OAAO,OAAO,OAAO;IAGvB,MAAM,8BAA8B;IACpC,IAAI,WAAqB;IACzB,IAAI,CAAC,KAAK,YAAY,OAAO,QAAQ;KACnC,MAAM,wDAAwD,OAAO,QAAQ,QAAQ;KACrF,WAAW;MAAE,GAAG;MAAM,UAAU,OAAO;KAAO;IAChD;IACA,aAAa,KAAK,aAAa,WAAW,MAAM,UAAU,QAAQ;GACpE,OACE,MAAM,+BAA+B;GAGvC,IAAI,UAAU,WAAkB;IAE9B,UAAU,WAAY,CAAC;IACvB,MAAM,WAAW,OAAO,aAAa,KAAK,GAAG;IAC7C,SAAS,GAAG,SAAS,SAAU,KAAW;KACxC,IAAI,YACF,WAAW,MAAM;KAEnB,aAAa;KACb,WAAW,KAAK,SAAS,GAAG;IAC9B,CAAC;IACD,SAAS,GAAG,OAAO,WAAkB;KACnC,IAAI,YACF,WAAW,KAAK;IAEpB,CAAC;IAED,SAAS,GAAG,kBAAkB,SAAU,GAAS;KAC/C,WAAW,KAAK,kBAAkB,CAAC;KACnC,IAAI,YACF,WAAW,KAAK,kBAAkB,CAAC;IAEvC,CAAC;IACD,SAAS,KAAK,UAAU;IACxB,IAAI,YACF,SAAS,KAAK,UAAU;GAE5B;GAEA,IAAI,YAAY;IACd,WAAW,GAAG,QAAQ,WAAkB;KACtC,QAAQ;IACV,CAAC;IAED,WAAW,GAAG,SAAS,SAAU,KAAW;KAC1C,KAAK,OAAO,KACV;MAAO;MAAK,UAAU;KAAK,GAC3B,6DACF;KACA,IAAI,YACF,WAAW,MAAM;KAEnB,aAAa;KACb,QAAQ;IACV,CAAC;GACH,OACE,QAAQ;EAEZ;CACF;;;;;;;;;;;;CAaA,WAAkB,SAAe;EAC/B,MAAM,sBAAsB,QAAQ,IAAI;EACxC,KAAK,aAAa,mBAAmB,QAAQ,OAAO,KAAK,SAAe;GACtE,IAAI,QAAQ,CAAC,IAAI,UAAU,IAAI,UAAU,YAAY,iBAEnD,OAAO,QAAQ,SAAS,GAAG;GAG7B,KAAK,qBACH,QAAQ,MACR,MACA;IAAE,KAAK,QAAQ;IAAK,aAAa,QAAQ;GAAY,GACrD,SAAS,6BAA6B,KAAK,QAAkB,cAAoB;IAC/E,IAAI,KACF,OAAO,QAAQ,SAAS,GAAG;IAG7B,kBAAkB,gBAAgB,QAAQ,gBAAgB,MAAM,CAAC;IAGjE,OAAO,eAAe,CAAC;IACvB,IAAI,QAAQ,gBAAgB,MAAM;KAChC,MAAM,0BAA0B;KAChC,QAAQ,SAAS,MAAM,2BAA2B,MAAM,GAAG,YAAY;IACzE,OAAO;KACL,MAAM,2BAA2B;KACjC,QAAQ,SAAS,MAAM,QAAQ,YAAY;IAC7C;GACF,CACF;EACF,CAAC;CACH;;;;;;;;;;;CAYA,OAAc,UAAkB,SAAc;EAC5C,MAAM,OAAO;EACb,MAAM,eAAoB,IAAI,OAAO,YAAY,EAAE,YAAY,KAAK,CAAC;EACrE,MAAM,WACJ,OAAO,KAAK,KAAK,OAAO,GACxB,SAAU,SAAS,IAAU;GAE3B,IAAI,QAAQ,KAAK,OAAO,UAAU,KAAA,GAChC,OAAO,GAAG;GAEZ,OAAO,KAAK,qBAAqB,SAAS;GAE1C,MAAM,eAAe,KAAK,QAAQ,QAAQ,CAAC,OAAO,OAAO;GAEzD,aAAa,KAAK,cAAc,EAAE,KAAK,MAAM,CAAC;GAC9C,aAAa,GAAG,SAAS,SAAU,KAAW;IAC5C,KAAK,OAAO,MAAM,EAAO,IAAI,GAAG,8BAA8B;IAC9D,GAAG;IAEH,KAAK,WAAkB,CAAC;GAC1B,CAAC;GACD,aAAa,GAAG,OAAO,WAAkB;IACvC,GAAG;IAEH,KAAK,WAAkB,CAAC;GAC1B,CAAC;GAED,aAAa,QAAQ,WAAkB;IACrC,IAAI,aAAa,OACf,aAAa,MAAM;IAErB,GAAG;IAEH,KAAK,WAAkB,CAAC;GAC1B;EACF,GAEA,WAAkB;GAEhB,MAAM,oBAAoB,KAAK,aAAa,OAAO,UAAU,OAAO;GACpE,aAAa,QAAQ,WAAkB;IACrC,kBAAkB,MAAM;GAC1B;GACA,kBAAkB,KAAK,cAAc,EAAE,KAAK,KAAK,CAAC;GAClD,kBAAkB,GAAG,SAAS,SAAU,KAAgB;IACtD,KAAK,OAAO,MAAM,EAAO,IAAI,GAAG,8BAA8B;IAC9D,aAAa,IAAI;GACnB,CAAC;EACH,CACF;EAEA,OAAO;CACT;;;;;;CAOA,iBAAwB,UAA0B;EAChD,KAAK,aAAa,cAAc,KAAK,KAAK,WAAiB;GACzD,IAAI,KACF,OAAO,SAAS,GAAG;GAGrB,KAAK,sBAAsB,MAAM,CAAC,CAAC,MAChC,aAAa,SAAS,MAAM,QAAQ,IACpC,QAAQ,SAAS,GAAG,CACvB;EACF,CAAC;CACH;;;;CAKA,MAAc,sBAAsB,QAAsC;EACxE,MAAM,WAAsB,CAAC;EAC7B,KAAK,MAAM,QAAQ,QACjB,IAAI;GACF,MAAM,cAAc,MAAM,KAAK,aAAa,wBAAwB,IAAI;GACxE,MAAM,EAAE,oBAAoB,MAAM,KAAK,cAAc,WAAW;GAChE,MAAM,SAAS,gBAAgB,UAAU,EAAE;GAC3C,IAAI,UAAU,gBAAgB,SAAS,SAAS;IAC9C,MAAM,UAAmB,gBAAgB,SAAS;IAIlD,QAAQ,OAHS,gBAAgB,KACX;IAMtB,QAAQ,QAAQ,gBAAgB;IAEhC,SAAS,KAAK,OAAO;GACvB,OACE,KAAK,OAAO,KAAK,EAAE,SAAS,KAAK,GAAG,oDAAkD;EAE1F,SAAS,KAAK;GACZ,KAAK,OAAO,MAAM;IAAE;IAAK,SAAS;GAAK,GAAG,kCAAkC;EAC9E;EAEF,OAAO;CACT;;;;;;;;;;CAWA,qBACE,MACA,aACA,SACA,UACM;EACN,IAAI,QAAQ;EACZ,MAAM,OAAO;EACb,MAAM,UAA0B,CAAC;EACjC,MAAM,uBAAuB,EAAE,MAAM,QAAQ,WAAW,KAAK,QAAQ;EAErE,MAAM,uBAAuB,IAAI;EACjC,MAAM,6BAA6B,oBAAoB;EACvD,IAAI,CAAC,aAAa;GAChB,MAAM,8BAA8B,IAAI;GACxC,QAAQ;GACR,cAAc,wBAAwB,IAAI;EAC5C;EAEA,KAAK,MAAM,UAAU,KAAK,SACxB,IAAI,WAAW,MAAM,QAAQ,KAAK,OAAO,QAAQ,KAAK,sBACpD,QAAQ,KAAK,KAAK,QAAQ,OAAO;EAGrC,MAAM,4BAA4B,MAAM,QAAQ,MAAM;EAEtD,MAAM,IACJ,UACC,QAAsB,OAAa;GAClC,MAAM,WAAW,OAAO,OAAO,CAAC,GAAG,OAAO;GAC1C,MAAM,aAAa,YAAY,SAAS,OAAO;GAE/C,IAAI,SAAS,UAAU,GAAG;IACxB,MAAM,UAAU,WAAW;IAE3B,IAAI,WAAW,KAAK,IAAI,IAAI,UAAU,OAAO,QAAQ;KACnD,MAAM,oCAAoC,OAAO,MAAM;KACvD,OAAO,GAAG;IACZ;IAEA,SAAS,OAAO,WAAW;GAC7B;GAEA,OAAO,kBAAkB,MAAM,WAAW,KAAK,gBAAgB,SAAe;IAC5E,IAAI,OAAO,IAAI,iBAAiB,KAAK;KACnC,MAAM,uDAAuD,OAAO,QAAQ,IAAI;KAChF,WAAW,UAAU,KAAK,IAAI;IAChC;IAEA,IAAI,OAAO,CAAC,gBAAgB;KAC1B,MAAM,0CAA0C,OAAO,QAAQ,MAAM,KAAK,OAAO;KACjF,OAAO,GAAG,MAAM,CAAC,OAAO,UAAU,iBAAiB,SAAS,CAAC,CAAC;IAChE;IAEA,IAAI;KACF,iBAAiB,gBAAgB,kBAAkB,gBAAgB,IAAI;IACzE,SAAS,KAAK;KACZ,KAAK,OAAO,MACV;MACE,KAAK;MACA;KACP,GACA,6DACF;KACA,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC;IACvB;IAEA,YAAY,SAAS,OAAO,UAAU;KACpC,MAAM;KACN,SAAS,KAAK,IAAI;IACpB;IAEA,cAAc,yBAAyB,aAAa,cAAc;IAElE,2BAA2B,eAAe,UAAU,MAAM;IAE1D,IAAI;KACF,cAAc,aAAa,cAAc;IAC3C,SAAS,KAAK;KACZ,KAAK,OAAO,MACV;MACE,KAAK;MACA;KACP,GACA,0DACF;KACA,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC;IACvB;IAIA,MAAM,wBAAwB,OAAO,MAAM;IAC3C,QAAQ;IACR,GAAG;GACL,CAAC;EACH,GAEA,OAAO,KAAY,kBAAsC;GACvD,OAAO,CAAC,OAAO,MAAM,QAAQ,aAAa,CAAC;GAI3C,IAAI,CAAC,OAAO;IACV,IAAI;IACJ,KAAK,IAAI,IAAI,GAAG,IAAI,cAAc,QAAQ,KACxC,IAAI,cAAc;UACX,IAAI,IAAI,GAAG,IAAI,cAAc,EAAE,CAAC,QAAQ,KAC3C,IAAI,cAAc,EAAE,CAAC,IAAI;MACvB,MAAM,OAAO,cAAc,EAAE,CAAC,EAAE,CAAC;MACjC,IAAI,SAAS,eAAe,SAAS,qBAAqB,SAAS,cAAc;OAC/E,qBAAqB;OACrB;MACF;KACF;;IAKN,IAAI,oBAAoB;KACtB,MAAM,wCAAwC;KAC9C,OAAO,SAAS,UAAU,sBAAsB,GAAG,MAAM,aAAa;IACxE;IACA,MAAM,2CAA2C;IACjD,OAAO,SAAS,UAAU,YAAY,UAAU,UAAU,GAAG,MAAM,aAAa;GAClF;GAEA,IAAI,QAAQ,WAAW,GAAG;IACxB,MAAM,oDAAoD,IAAI;IAC9D,MAAM,EAAE,iBAAiB,iBAAiB,MAAM,KAAK,cACnD,WACF;IACA,OAAO,SAAS,MAAM,iBAAiB,YAAY;GACrD;GAEA,IAAI;IACF,MAAM,mBAAmB,MAAM,KAAK,aAAa,oBAAoB,MAAM,WAAW;IACtF,MAAM,EAAE,iBAAiB,iBAAiB,MAAM,KAAK,cAAc,gBAAgB;IACnF,SAAS,MAAM,iBAAiB,EAAE,OAAO,eAAe,YAAY,CAAC;GACvE,SAAS,KAAK;IACZ,SAAS,GAAG;GACd;EACF,CACF;CACF;;;;;;CAOA,MAAc,cACZ,aAC+D;EAC/D,MAAM,eAAwB,CAAC;EAC/B,IAAI,kBAAkB;EACtB,KAAK,MAAM,UAAU,KAAK,WAAW,CAAC,GACpC,IAAI;GACF,kBAAkB,MAAM,OAAO,gBAAgB,eAAe;EAChE,SAAS,KAAU;GACjB,MAAM,sCAAsC,YAAY,MAAM,KAAK,OAAO;GAC1E,aAAa,KAAK,GAAG;EACvB;EAEF,OAAO;GAAE;GAAiB;EAAa;CACzC;;;;;;;CAQA,MAAc,2BAA2B,MAAc,UAAoC;EACzF,IAAI,CAAC,KAAK,SAAS,QACjB,OAAO;EAGT,IAAI;GACF,MAAM,cAAc,MAAM,KAAK,aAAa,wBAAwB,IAAI;GACxE,IAAI,CAAC,WAAW,aAAa,QAAQ,GACnC,OAAO;GAET,MAAM,EAAE,oBAAoB,MAAM,KAAK,cAAc,WAAW;GAChE,MAAM,UAAU,WAAW,iBAAiB,QAAQ;GACpD,IAAI,YAAY,OACd,MAAM,kDAAkD,UAAU,IAAI;GAExE,OAAO;EACT,SAAS,KAAU;GACjB,IAAI,KAAK,WAAW,YAAY,WAC9B,OAAO;GAET,KAAK,OAAO,MACV;IAAE,SAAS;IAAM,UAAU;IAAU;GAAI,GACzC,sFACF;GACA,OAAO;EACT;CACF;;;;;;;;CASA,4BAAmC,UAAoB,QAA4B;EACjF,KAAK,MAAM,KAAK,UACd,IAAI,OAAO,UAAU,eAAe,KAAK,UAAU,CAAC,GAAG;GACrD,MAAM,UAAU,SAAS;GAGzB,QAAQ,OAAO,IAAI,oBAAoB,KAAK,OAAO;EACrD;CAEJ;AACF"}