• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict'
2
3const npa = require('npm-package-arg')
4const npmFetch = require('npm-registry-fetch')
5
6const npar = (spec) => {
7  spec = npa(spec)
8  if (!spec.registry) {
9    throw new Error('must use package name only')
10  }
11  return spec
12}
13
14const parseTeam = (scopeTeam) => {
15  let slice = 0
16  if (scopeTeam.startsWith('@')) {
17    slice = 1
18  }
19  const [scope, team] = scopeTeam.slice(slice).split(':').map(encodeURIComponent)
20  return { scope, team }
21}
22
23const getPackages = async (scopeTeam, opts) => {
24  const { scope, team } = parseTeam(scopeTeam)
25
26  let uri
27  if (team) {
28    uri = `/-/team/${scope}/${team}/package`
29  } else {
30    uri = `/-/org/${scope}/package`
31  }
32  try {
33    return await npmFetch.json(uri, opts)
34  } catch (err) {
35    if (err.code === 'E404') {
36      uri = `/-/user/${scope}/package`
37      return npmFetch.json(uri, opts)
38    }
39    throw err
40  }
41}
42
43const getCollaborators = async (pkg, opts) => {
44  const spec = npar(pkg)
45  const uri = `/-/package/${spec.escapedName}/collaborators`
46  return npmFetch.json(uri, opts)
47}
48
49const getVisibility = async (pkg, opts) => {
50  const spec = npar(pkg)
51  const uri = `/-/package/${spec.escapedName}/visibility`
52  return npmFetch.json(uri, opts)
53}
54
55const setAccess = async (pkg, access, opts) => {
56  const spec = npar(pkg)
57  const uri = `/-/package/${spec.escapedName}/access`
58  await npmFetch(uri, {
59    ...opts,
60    method: 'POST',
61    body: { access },
62    spec,
63    ignoreBody: true,
64  })
65  return true
66}
67
68const setMfa = async (pkg, level, opts) => {
69  const spec = npar(pkg)
70  const body = {}
71  switch (level) {
72    case 'none':
73      body.publish_requires_tfa = false
74      break
75    case 'publish':
76      // tfa is required, automation tokens can not override tfa
77      body.publish_requires_tfa = true
78      body.automation_token_overrides_tfa = false
79      break
80    case 'automation':
81      // tfa is required, automation tokens can override tfa
82      body.publish_requires_tfa = true
83      body.automation_token_overrides_tfa = true
84      break
85    default:
86      throw new Error(`Invalid mfa setting ${level}`)
87  }
88  const uri = `/-/package/${spec.escapedName}/access`
89  await npmFetch(uri, {
90    ...opts,
91    method: 'POST',
92    body,
93    spec,
94    ignoreBody: true,
95  })
96  return true
97}
98
99const setPermissions = async (scopeTeam, pkg, permissions, opts) => {
100  const spec = npar(pkg)
101  const { scope, team } = parseTeam(scopeTeam)
102  if (!scope || !team) {
103    throw new Error('team must be in format `scope:team`')
104  }
105  const uri = `/-/team/${scope}/${team}/package`
106  await npmFetch(uri, {
107    ...opts,
108    method: 'PUT',
109    body: { package: spec.name, permissions },
110    scope,
111    spec,
112    ignoreBody: true,
113  })
114  return true
115}
116
117const removePermissions = async (scopeTeam, pkg, opts) => {
118  const spec = npar(pkg)
119  const { scope, team } = parseTeam(scopeTeam)
120  const uri = `/-/team/${scope}/${team}/package`
121  await npmFetch(uri, {
122    ...opts,
123    method: 'DELETE',
124    body: { package: spec.name },
125    scope,
126    spec,
127    ignoreBody: true,
128  })
129  return true
130}
131
132module.exports = {
133  getCollaborators,
134  getPackages,
135  getVisibility,
136  removePermissions,
137  setAccess,
138  setMfa,
139  setPermissions,
140}
141