1import fs from 'fs-extra'; 2import glob from 'glob-promise'; 3 4import { spawnAsync, spawnJSONCommandAsync } from './Utils'; 5 6export const EXPO_DEVELOPERS_TEAM_NAME = 'expo:developers'; 7 8export type PackageViewType = null | { 9 name: string; 10 version: string; 11 'dist-tags': { 12 latest: string; 13 [tag: string]: string; 14 }; 15 versions: string[]; 16 time: { 17 created: string; 18 modified: string; 19 [time: string]: string; 20 }; 21 maintainers: string[]; 22 description: string; 23 author: string; 24 gitHead: string; 25 dist: { 26 tarball: string; 27 }; 28 // and more but these are the basic ones, we shouldn't need more. 29 [key: string]: unknown; 30}; 31 32/** 33 * Runs `npm view` for package with given name. Returns null if package is not published yet. 34 */ 35export async function getPackageViewAsync( 36 packageName: string, 37 version?: string 38): Promise<PackageViewType> { 39 try { 40 return await spawnJSONCommandAsync('npm', [ 41 'view', 42 version ? `${packageName}@${version}` : packageName, 43 '--json', 44 ]); 45 } catch { 46 return null; 47 } 48} 49 50/** 51 * Download npm tarball 52 */ 53export async function downloadPackageTarballAsync( 54 targetDir: string, 55 packageName: string, 56 version?: string 57): Promise<string> { 58 await fs.ensureDir(targetDir); 59 await spawnAsync('npm', ['pack', version ? `${packageName}@${version}` : packageName], { 60 cwd: targetDir, 61 stdio: 'ignore', 62 }); 63 const result = await glob('*.tgz', { cwd: targetDir }); 64 if (result.length === 0) { 65 throw new Error('Download tarball not found'); 66 } 67 return result[0]; 68} 69 70/** 71 * Publishes a package at given directory to the global npm registry. 72 */ 73export async function publishPackageAsync( 74 packageDir: string, 75 tagName: string = 'latest', 76 dryRun: boolean = false 77): Promise<void> { 78 const args = ['publish', '--tag', tagName, '--access', 'public']; 79 80 if (dryRun) { 81 args.push('--dry-run'); 82 } 83 await spawnAsync('npm', args, { 84 cwd: packageDir, 85 }); 86} 87 88/** 89 * Adds dist-tag to a specific version of the package. 90 */ 91export async function addTagAsync( 92 packageName: string, 93 version: string, 94 tagName: string 95): Promise<void> { 96 await spawnAsync('npm', ['dist-tag', 'add', `${packageName}@${version}`, tagName]); 97} 98 99/** 100 * Removes package's tag with given name. 101 */ 102export async function removeTagAsync(packageName: string, tagName: string): Promise<void> { 103 await spawnAsync('npm', ['dist-tag', 'rm', packageName, tagName]); 104} 105 106/** 107 * Gets a list of user names in the team with given team name. 108 */ 109export async function getTeamMembersAsync(teamName: string): Promise<string[]> { 110 return await spawnJSONCommandAsync('npm', ['team', 'ls', teamName, '--json']); 111} 112 113/** 114 * Adds a package to organization team granting access to everyone in the team. 115 */ 116export async function grantReadWriteAccessAsync( 117 packageName: string, 118 teamName: string 119): Promise<void> { 120 await spawnAsync('npm', ['access', 'grant', 'read-write', teamName, packageName]); 121} 122 123/** 124 * Returns a name of the currently logged in user or `null` if logged out. 125 */ 126export async function whoamiAsync(): Promise<string | null> { 127 try { 128 const { stdout } = await spawnAsync('npm', ['whoami']); 129 return stdout.trim(); 130 } catch { 131 return null; 132 } 133} 134