{"version":3,"file":"storage-utils.mjs","names":[],"sources":["../../src/lib/storage-utils.ts"],"sourcesContent":["import createDebug from 'debug';\nimport _ from 'lodash';\n\nimport { pkgUtils } from '@verdaccio/core';\nimport { SearchMemoryIndexer } from '@verdaccio/search-indexer';\nimport {\n  AbbreviatedManifest,\n  AbbreviatedVersions,\n  DistFile,\n  Manifest,\n  Version,\n} from '@verdaccio/types';\nimport { generateRandomHexString } from '@verdaccio/utils';\n\nimport { API_ERROR, DIST_TAGS, HTTP_STATUS, STORAGE, USERS } from './constants';\nimport LocalStorage from './local-storage';\nimport { logger } from './logger';\nimport { ErrorCode, isObject, normalizeDistTags } from './utils';\n\nconst debug = createDebug('verdaccio:storage-utils');\n\n/**\n * Create an empty package manifest with all the internal bookkeeping\n * sections (`_uplinks`, `_distfiles`, `_attachments`, `_rev`) initialized.\n * Used as the starting point when a package is seen for the first time.\n * @param name package name\n * @return an empty manifest for the given package\n */\nexport function generatePackageTemplate(name: string): Manifest {\n  return {\n    // standard things\n    name,\n    versions: {},\n    time: {},\n    [USERS]: {},\n    [DIST_TAGS]: {},\n    _uplinks: {},\n    _distfiles: {},\n    _attachments: {},\n    _rev: '',\n  };\n}\n\n/**\n * Normalize a manifest read from storage: ensure the object sections\n * (`versions`, `dist-tags`, `_distfiles`, `_attachments`, `_uplinks`, `time`)\n * exist, default the revision and `_id`, and normalize the dist-tags shape.\n * The manifest is mutated in place.\n * @param pkg package manifest reference\n * @return the same manifest, normalized\n */\nexport function normalizePackage(pkg: Manifest): Manifest {\n  const pkgProperties = ['versions', 'dist-tags', '_distfiles', '_attachments', '_uplinks', 'time'];\n\n  pkgProperties.forEach((key): void => {\n    const pkgProp = pkg[key];\n\n    if (_.isNil(pkgProp) || isObject(pkgProp) === false) {\n      pkg[key] = {};\n    }\n  });\n\n  if (_.isString(pkg._rev) === false) {\n    debug('package %o has no revision, setting default', pkg.name);\n    pkg._rev = STORAGE.DEFAULT_REVISION;\n  }\n\n  if (_.isString(pkg._id) === false) {\n    pkg._id = pkg.name;\n  }\n\n  // normalize dist-tags\n  normalizeDistTags(pkg);\n\n  return pkg;\n}\n\n/**\n * Produce the next revision id in the `<counter>-<hash>` format used by the\n * storage layer, incrementing the counter of the previous revision.\n * @param rev previous revision id, eg. `2-a1b2c3`\n * @return the next revision id\n */\nexport function generateRevision(rev: string): string {\n  const _rev = rev.split('-');\n\n  return (+_rev[0] || 0) + 1 + '-' + generateRandomHexString();\n}\n\n/**\n * Pick the most relevant readme for a package: the manifest readme or the\n * `latest` version readme first, otherwise the first readme found across the\n * `next`, `beta`, `alpha`, `test`, `dev` and `canary` dist-tags, in that order.\n * @param pkg package manifest\n * @return the readme content, or an empty string when none is available\n */\nexport function getLatestReadme(pkg: Manifest): string {\n  const versions = pkg['versions'] || {};\n  const distTags = pkg[DIST_TAGS] || {};\n  // FIXME: here is a bit tricky add the types\n  const latestVersion: Version | any = distTags['latest'] ? versions[distTags['latest']] || {} : {};\n  let readme = _.trim(pkg.readme || latestVersion.readme || '');\n  if (readme) {\n    return readme;\n  }\n\n  // In case of empty readme - trying to get ANY readme in the following order: 'next','beta','alpha','test','dev','canary'\n  const readmeDistTagsPriority = ['next', 'beta', 'alpha', 'test', 'dev', 'canary'];\n  readmeDistTagsPriority.map(function (tag): string | void {\n    if (readme) {\n      return readme;\n    }\n    const version: Version | any = distTags[tag] ? versions[distTags[tag]] || {} : {};\n    readme = _.trim(version.readme || readme);\n  });\n  return readme;\n}\n\n/**\n * Remove the readme from a version object: only one readme is kept per\n * package (see getLatestReadme), never one per version. The version is\n * mutated in place.\n * @param version version metadata\n * @return the same version without its readme\n */\nexport function cleanUpReadme(version: Version): Version {\n  if (_.isNil(version) === false) {\n    // @ts-ignore\n    delete version.readme;\n  }\n\n  return version;\n}\n\n/**\n * Manifest properties allowed in responses served to clients; everything\n * else is verdaccio-internal bookkeeping and is stripped by cleanUpLinksRef.\n */\nexport const WHITELIST = [\n  '_rev',\n  'name',\n  'versions',\n  'dist-tags',\n  'readme',\n  'time',\n  '_id',\n  'users',\n];\n\n/**\n * Strip verdaccio-internal sections (`_distfiles`, `_attachments`, ...) from\n * a manifest before serving it to a client. The manifest is mutated in place.\n * @param keepUpLinkData whether the `_uplinks` section should be preserved\n * @param result manifest to clean up\n * @return the same manifest with only whitelisted properties\n */\nexport function cleanUpLinksRef(keepUpLinkData: boolean, result: Manifest): Manifest {\n  const propertyToKeep = [...WHITELIST];\n  if (keepUpLinkData === true) {\n    propertyToKeep.push('_uplinks');\n  }\n\n  for (const i in result) {\n    if (propertyToKeep.indexOf(i) === -1) {\n      // Remove sections like '_uplinks' from response\n      delete result[i];\n    }\n  }\n\n  return result;\n}\n\n/**\n * Verify a package does not exist locally yet; part of the publish flow.\n * @param name package name\n * @param localStorage local storage instance\n * @throws conflict error when the package already exists locally\n */\nexport async function checkPackageLocal(name: string, localStorage: LocalStorage): Promise<void> {\n  debug('checking if %o already exists locally', name);\n  try {\n    const results = await localStorage.getPackageMetadataAsync(name);\n    if (results) {\n      debug('package %o already exists locally', name);\n      throw ErrorCode.getConflict(API_ERROR.PACKAGE_EXIST);\n    }\n  } catch (err: any) {\n    if (err.status === HTTP_STATUS.NOT_FOUND) {\n      debug('package %o does not exist locally', name);\n      return;\n    }\n    throw err;\n  }\n}\n\n/**\n * Create a new package in the local storage and register its latest version\n * in the in-memory search indexer.\n * @param name package name\n * @param metadata package manifest to store\n * @param localStorage local storage instance\n */\nexport function publishPackage(\n  name: string,\n  metadata: any,\n  localStorage: LocalStorage\n): Promise<void> {\n  debug('publishing a new package for %o', name);\n  return new Promise((resolve, reject): void => {\n    localStorage.addPackage(name, metadata, (err, latest): void => {\n      if (!_.isNull(err)) {\n        return reject(err);\n      } else if (!_.isUndefined(latest)) {\n        SearchMemoryIndexer.add(latest).catch((reason) => {\n          debug('indexer has failed on add item %o', reason);\n          logger.error('indexer has failed on add item');\n        });\n      }\n      return resolve();\n    });\n  });\n}\n\n/**\n * Verify a package does not exist on any uplink yet; part of the publish\n * flow. Uplink failures other than 404 reject the publish, unless\n * `publish.allow_offline` is enabled in the configuration.\n * @param name package name\n * @param isAllowPublishOffline whether publishing with unreachable uplinks is allowed\n * @param syncMetadata bound Storage._syncUplinksMetadata function\n * @throws conflict error when the package exists upstream, service unavailable when uplinks are offline\n */\nexport function checkPackageRemote(\n  name: string,\n  isAllowPublishOffline: boolean,\n  syncMetadata: any\n): Promise<void> {\n  debug('checking if %o already exists on uplinks', name);\n  return new Promise((resolve, reject): void => {\n    syncMetadata(name, null, {}, (err, packageJsonLocal, upLinksErrors): void => {\n      // something weird\n      if (err && err.status !== HTTP_STATUS.NOT_FOUND) {\n        return reject(err);\n      }\n\n      // checking package exist already\n      if (_.isNil(packageJsonLocal) === false) {\n        debug('package %o already exists on an uplink', name);\n        return reject(ErrorCode.getConflict(API_ERROR.PACKAGE_EXIST));\n      }\n\n      for (let errorItem = 0; errorItem < upLinksErrors.length; errorItem++) {\n        // checking error\n        // if uplink fails with a status other than 404, we report failure\n        if (_.isNil(upLinksErrors[errorItem][0]) === false) {\n          if (upLinksErrors[errorItem][0].status !== HTTP_STATUS.NOT_FOUND) {\n            if (isAllowPublishOffline) {\n              debug('uplink offline for %o, publish offline is allowed', name);\n              return resolve();\n            }\n\n            debug('uplink offline for %o, rejecting publish', name);\n            return reject(ErrorCode.getServiceUnavailable(API_ERROR.UPLINK_OFFLINE_PUBLISH));\n          }\n        }\n      }\n\n      return resolve();\n    });\n  });\n}\n\n/**\n * Merge the `time` field of a remote manifest into the cached one; remote\n * entries win on conflicts. Returns a new manifest, the inputs are untouched.\n * @param cacheManifest local cached manifest\n * @param remoteManifest manifest fetched from an uplink\n * @return the cached manifest with the merged time field\n */\nexport function mergeUplinkTimeIntoLocal(cacheManifest: Manifest, remoteManifest: Manifest): any {\n  if ('time' in remoteManifest) {\n    debug('merging remote time field into local manifest for %o', cacheManifest.name);\n    // remote override cache time conflicts\n    return { ...cacheManifest, time: { ...cacheManifest.time, ...remoteManifest.time } };\n  }\n\n  return cacheManifest;\n}\n\n/**\n * Build the search item emitted for a local package during a search stream,\n * based on its latest version: npm-search compatible maintainers\n * (`{ username, email }`), publisher (from `_npmUser`, falling back to the\n * first maintainer), license and links.\n * @param data package manifest\n * @param time modified time attached to the search item\n * @return the search item, or undefined when the package has no usable latest version\n */\nexport function prepareSearchPackage(data: Manifest, time: unknown): any {\n  const latest = pkgUtils.getLatest(data);\n\n  if (!latest || !data.versions[latest]) {\n    debug('no latest version found for %o, skipping search item', data.name);\n    return;\n  }\n\n  debug('preparing search item for %o@%o', data.name, latest);\n  if (latest && data.versions[latest]) {\n    const version: Version = data.versions[latest];\n    const versions: any = { [latest]: 'latest' };\n    // packument maintainers carry `name`, but the npm search API contract uses\n    // `username` and the npm CLI crashes on entries without it — emit both\n    const rawMaintainers = version.maintainers || [version.author].filter(Boolean);\n    const maintainers = Array.isArray(rawMaintainers)\n      ? rawMaintainers.map((maintainer: any) =>\n          typeof maintainer === 'string'\n            ? { username: maintainer, email: '' }\n            : {\n                ...maintainer,\n                username: maintainer?.username ?? maintainer?.name ?? '',\n                email: maintainer?.email ?? '',\n              }\n        )\n      : [];\n    // npmjs fills `publisher` with the user who published the version; use\n    // `_npmUser` when the publishing client provided it and fall back to the\n    // first maintainer, otherwise the npm CLI renders \"published by ???\"\n    const npmUser = (version as any)._npmUser;\n    const publisher = npmUser?.name\n      ? { username: npmUser.name, email: npmUser.email ?? '' }\n      : (maintainers[0] ?? {});\n    const pkg: any = {\n      name: version.name,\n      description: version.description,\n      [DIST_TAGS]: { latest },\n      maintainers,\n      publisher,\n      author: version.author,\n      repository: version.repository,\n      readmeFilename: version.readmeFilename || '',\n      homepage: version.homepage,\n      keywords: version.keywords,\n      time: {\n        modified: time,\n      },\n      bugs: version.bugs,\n      license: version.license,\n      versions,\n    };\n\n    return pkg;\n  }\n}\n\n/**\n * Whether the tarball url path ends with the given file name\n * (any query string or fragment is ignored, like the path parsing\n * in updateVersions).\n */\nexport function tarballMatchesFilename(tarball: string, filename: string): boolean {\n  return tarball.split(/[?#]/)[0].endsWith(`/${filename}`);\n}\n\n/**\n * Build a distfile record from a version's dist metadata when its tarball\n * url matches the given file name.\n */\nexport function distFileFromVersion(\n  version: Version | undefined,\n  filename: string\n): DistFile | null {\n  const dist = version?.dist;\n\n  if (dist?.tarball && tarballMatchesFilename(dist.tarball, filename)) {\n    return { url: dist.tarball, sha: dist.shasum };\n  }\n\n  return null;\n}\n\n/**\n * Resolve the distfile record for a tarball filename. Prefers the\n * `_distfiles` bookkeeping, but falls back to the version metadata when the\n * record is missing (storages written by other verdaccio versions cache\n * versions without their distfile records, which made those tarballs\n * permanently unavailable).\n * @param manifest cached manifest\n * @param filename tarball file name, eg. pkg-1.0.0.tgz\n */\nexport function lookupDistFile(manifest: Manifest, filename: string): DistFile | null {\n  const distFile = manifest?._distfiles?.[filename];\n  if (_.isNil(distFile) === false) {\n    return distFile;\n  }\n\n  const versions = manifest?.versions ?? {};\n\n  // tarballs are conventionally named <basename>-<version>.tgz, so the\n  // version can usually be derived from the filename without scanning\n  // manifests that carry thousands of versions\n  const basename = manifest?.name?.replace(/^.*\\//, '');\n  if (basename && filename.startsWith(`${basename}-`) && filename.endsWith('.tgz')) {\n    const versionId = filename.slice(basename.length + 1, -'.tgz'.length);\n    const distFromVersion = distFileFromVersion(versions[versionId], filename);\n\n    if (distFromVersion) {\n      debug('distfile record missing for %o, using version %o dist', filename, versionId);\n      return distFromVersion;\n    }\n  }\n\n  // unconventional tarball names: fall back to a scan\n  for (const versionId in versions) {\n    const distFromVersion = distFileFromVersion(versions[versionId], filename);\n\n    if (distFromVersion) {\n      debug('distfile record missing for %o, using version %o dist', filename, versionId);\n      return distFromVersion;\n    }\n  }\n\n  debug('no distfile record or version dist found for %o', filename);\n  return null;\n}\n\n/**\n * Check whether the package metadata has enough data to be published.\n * @param pkg package manifest\n * @return true when the manifest carries a versions section\n */\nexport function isPublishablePackage(pkg: Manifest): boolean {\n  const keys: string[] = Object.keys(pkg);\n\n  return keys.includes('versions');\n}\n\n/**\n * Whether a version declares an install lifecycle script (`install`,\n * `preinstall` or `postinstall`); surfaced in abbreviated manifests as\n * `hasInstallScript` so clients can warn about script execution.\n * @param version version metadata\n * @return true when an install script is present\n */\nexport function hasInstallScript(version: Version) {\n  if (version?.scripts) {\n    const scripts = Object.keys(version.scripts);\n    return (\n      scripts.find((item) => {\n        return ['install', 'preinstall', 'postinstall'].includes(item);\n      }) !== undefined\n    );\n  }\n  return false;\n}\n\n/**\n * Convert a full manifest into the abbreviated format served when the client\n * requests `application/vnd.npm.install-v1+json` (npm install), keeping only\n * the fields the npm registry contract defines for installation.\n * https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md\n * @param manifest full package manifest\n * @return the abbreviated manifest\n */\nexport function convertAbbreviatedManifest(manifest: Manifest): AbbreviatedManifest {\n  if (debug.enabled) {\n    debug(\n      'converting %o to abbreviated manifest with %o versions',\n      manifest.name,\n      Object.keys(manifest.versions).length\n    );\n  }\n  const abbreviatedVersions = Object.keys(manifest.versions).reduce(\n    (acc: AbbreviatedVersions, version: string) => {\n      const _version = manifest.versions[version];\n      // This should be align with this document\n      // https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md#abbreviated-version-object\n      const _version_abbreviated = {\n        name: _version.name,\n        version: _version.version,\n        description: _version.description,\n        deprecated: _version.deprecated,\n        bin: _version.bin,\n        dist: _version.dist,\n        engines: _version.engines,\n        cpu: _version.cpu,\n        os: _version.os,\n        funding: _version.funding,\n        directories: _version.directories,\n        dependencies: _version.dependencies,\n        devDependencies: _version.devDependencies,\n        peerDependencies: _version.peerDependencies,\n        peerDependenciesMeta: _version.peerDependenciesMeta,\n        optionalDependencies: _version.optionalDependencies,\n        bundleDependencies: _version.bundleDependencies,\n        // npm cli specifics\n        _hasShrinkwrap: _version._hasShrinkwrap,\n        hasInstallScript: hasInstallScript(_version),\n      };\n      acc[version] = _version_abbreviated;\n      return acc;\n    },\n    {}\n  );\n\n  const convertedManifest = {\n    name: manifest['name'],\n    [DIST_TAGS]: manifest[DIST_TAGS],\n    versions: abbreviatedVersions,\n    // @ts-ignore\n    modified: manifest?.time?.modified,\n    // NOTE: special case for pnpm https://github.com/pnpm/rfcs/pull/2\n    time: manifest?.time,\n  };\n\n  // @ts-ignore\n  return convertedManifest;\n}\n"],"mappings":"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"}