Your IP : 18.189.182.15
const { fixer } = require('normalize-package-data')
const npmFetch = require('npm-registry-fetch')
const npa = require('npm-package-arg')
const semver = require('semver')
const { URL } = require('url')
const ssri = require('ssri')
const publish = async (manifest, tarballData, opts) => {
if (manifest.private) {
throw Object.assign(
new Error(`This package has been marked as private
Remove the 'private' field from the package.json to publish it.`),
{ code: 'EPRIVATE' }
)
}
// spec is used to pick the appropriate registry/auth combo
const spec = npa.resolve(manifest.name, manifest.version)
opts = {
defaultTag: 'latest',
// if scoped, restricted by default
access: spec.scope ? 'restricted' : 'public',
algorithms: ['sha512'],
...opts,
spec,
}
const reg = npmFetch.pickRegistry(spec, opts)
const pubManifest = patchManifest(manifest, opts)
// registry-frontdoor cares about the access level,
// which is only configurable for scoped packages
if (!spec.scope && opts.access === 'restricted') {
throw Object.assign(
new Error("Can't restrict access to unscoped packages."),
{ code: 'EUNSCOPED' }
)
}
const metadata = buildMetadata(reg, pubManifest, tarballData, opts)
try {
return await npmFetch(spec.escapedName, {
...opts,
method: 'PUT',
body: metadata,
ignoreBody: true,
})
} catch (err) {
if (err.code !== 'E409') {
throw err
}
// if E409, we attempt exactly ONE retry, to protect us
// against malicious activity like trying to publish
// a bunch of new versions of a package at the same time
// and/or spamming the registry
const current = await npmFetch.json(spec.escapedName, {
...opts,
query: { write: true },
})
const newMetadata = patchMetadata(current, metadata)
return npmFetch(spec.escapedName, {
...opts,
method: 'PUT',
body: newMetadata,
ignoreBody: true,
})
}
}
const patchManifest = (_manifest, opts) => {
const { npmVersion } = opts
// we only update top-level fields, so a shallow clone is fine
const manifest = { ..._manifest }
manifest._nodeVersion = process.versions.node
if (npmVersion) {
manifest._npmVersion = npmVersion
}
fixer.fixNameField(manifest, { strict: true, allowLegacyCase: true })
const version = semver.clean(manifest.version)
if (!version) {
throw Object.assign(
new Error('invalid semver: ' + manifest.version),
{ code: 'EBADSEMVER' }
)
}
manifest.version = version
return manifest
}
const buildMetadata = (registry, manifest, tarballData, opts) => {
const { access, defaultTag, algorithms } = opts
const root = {
_id: manifest.name,
name: manifest.name,
description: manifest.description,
'dist-tags': {},
versions: {},
access,
}
root.versions[manifest.version] = manifest
const tag = manifest.tag || defaultTag
root['dist-tags'][tag] = manifest.version
const tarballName = `${manifest.name}-${manifest.version}.tgz`
const tarballURI = `${manifest.name}/-/${tarballName}`
const integrity = ssri.fromData(tarballData, {
algorithms: [...new Set(['sha1'].concat(algorithms))],
})
manifest._id = `${manifest.name}@${manifest.version}`
manifest.dist = { ...manifest.dist }
// Don't bother having sha1 in the actual integrity field
manifest.dist.integrity = integrity.sha512[0].toString()
// Legacy shasum support
manifest.dist.shasum = integrity.sha1[0].hexDigest()
// NB: the CLI always fetches via HTTPS if the registry is HTTPS,
// regardless of what's here. This makes it so that installing
// from an HTTP-only mirror doesn't cause problems, though.
manifest.dist.tarball = new URL(tarballURI, registry).href
.replace(/^https:\/\//, 'http://')
root._attachments = {}
root._attachments[tarballName] = {
content_type: 'application/octet-stream',
data: tarballData.toString('base64'),
length: tarballData.length,
}
return root
}
const patchMetadata = (current, newData) => {
const curVers = Object.keys(current.versions || {})
.map(v => semver.clean(v, true))
.concat(Object.keys(current.time || {})
.map(v => semver.valid(v, true) && semver.clean(v, true))
.filter(v => v))
const newVersion = Object.keys(newData.versions)[0]
if (curVers.indexOf(newVersion) !== -1) {
const { name: pkgid, version } = newData
throw Object.assign(
new Error(
`Cannot publish ${pkgid}@${version} over existing version.`
), {
code: 'EPUBLISHCONFLICT',
pkgid,
version,
})
}
current.versions = current.versions || {}
current.versions[newVersion] = newData.versions[newVersion]
for (const i in newData) {
switch (i) {
// objects that copy over the new stuffs
case 'dist-tags':
case 'versions':
case '_attachments':
for (const j in newData[i]) {
current[i] = current[i] || {}
current[i][j] = newData[i][j]
}
break
// copy
default:
current[i] = newData[i]
break
}
}
return current
}
module.exports = publish