unpublish.js 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. 'use strict'
  2. const figgyPudding = require('figgy-pudding')
  3. const npa = require('npm-package-arg')
  4. const npmFetch = require('npm-registry-fetch')
  5. const semver = require('semver')
  6. const url = require('url')
  7. const UnpublishConfig = figgyPudding({
  8. force: { default: false },
  9. Promise: { default: () => Promise }
  10. })
  11. module.exports = unpublish
  12. function unpublish (spec, opts) {
  13. opts = UnpublishConfig(opts)
  14. return new opts.Promise(resolve => resolve()).then(() => {
  15. spec = npa(spec)
  16. // NOTE: spec is used to pick the appropriate registry/auth combo.
  17. opts = opts.concat({ spec })
  18. const pkgUri = spec.escapedName
  19. return npmFetch.json(pkgUri, opts.concat({
  20. query: { write: true }
  21. })).then(pkg => {
  22. if (!spec.rawSpec || spec.rawSpec === '*') {
  23. return npmFetch(`${pkgUri}/-rev/${pkg._rev}`, opts.concat({
  24. method: 'DELETE',
  25. ignoreBody: true
  26. }))
  27. } else {
  28. const version = spec.rawSpec
  29. const allVersions = pkg.versions || {}
  30. const versionPublic = allVersions[version]
  31. let dist
  32. if (versionPublic) {
  33. dist = allVersions[version].dist
  34. }
  35. delete allVersions[version]
  36. // if it was the only version, then delete the whole package.
  37. if (!Object.keys(allVersions).length) {
  38. return npmFetch(`${pkgUri}/-rev/${pkg._rev}`, opts.concat({
  39. method: 'DELETE',
  40. ignoreBody: true
  41. }))
  42. } else if (versionPublic) {
  43. const latestVer = pkg['dist-tags'].latest
  44. Object.keys(pkg['dist-tags']).forEach(tag => {
  45. if (pkg['dist-tags'][tag] === version) {
  46. delete pkg['dist-tags'][tag]
  47. }
  48. })
  49. if (latestVer === version) {
  50. pkg['dist-tags'].latest = Object.keys(
  51. allVersions
  52. ).sort(semver.compareLoose).pop()
  53. }
  54. delete pkg._revisions
  55. delete pkg._attachments
  56. // Update packument with removed versions
  57. return npmFetch(`${pkgUri}/-rev/${pkg._rev}`, opts.concat({
  58. method: 'PUT',
  59. body: pkg,
  60. ignoreBody: true
  61. })).then(() => {
  62. // Remove the tarball itself
  63. return npmFetch.json(pkgUri, opts.concat({
  64. query: { write: true }
  65. })).then(({ _rev, _id }) => {
  66. const tarballUrl = url.parse(dist.tarball).pathname.substr(1)
  67. return npmFetch(`${tarballUrl}/-rev/${_rev}`, opts.concat({
  68. method: 'DELETE',
  69. ignoreBody: true
  70. }))
  71. })
  72. })
  73. }
  74. }
  75. }, err => {
  76. if (err.code !== 'E404') {
  77. throw err
  78. }
  79. })
  80. }).then(() => true)
  81. }