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