verdaccio
Version:
A lightweight private npm proxy registry
1 lines • 45.9 kB
Source Map (JSON)
{"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"}