update-notifier
Advanced tools
Comparing version
14
check.js
/* eslint-disable unicorn/no-process-exit */ | ||
'use strict'; | ||
let updateNotifier = require('.'); | ||
import process from 'node:process'; | ||
import UpdateNotifier from './update-notifier.js'; | ||
const options = JSON.parse(process.argv[2]); | ||
const updateNotifier = new UpdateNotifier(JSON.parse(process.argv[2])); | ||
updateNotifier = new updateNotifier.UpdateNotifier(options); | ||
(async () => { | ||
try { | ||
// Exit process when offline | ||
@@ -25,5 +23,5 @@ setTimeout(process.exit, 1000 * 30); | ||
process.exit(); | ||
})().catch(error => { | ||
} catch (error) { | ||
console.error(error); | ||
process.exit(1); | ||
}); | ||
} |
187
index.js
@@ -1,188 +0,7 @@ | ||
'use strict'; | ||
const {spawn} = require('child_process'); | ||
const path = require('path'); | ||
const {format} = require('util'); | ||
const importLazy = require('import-lazy')(require); | ||
import UpdateNotifier from './update-notifier.js'; | ||
const configstore = importLazy('configstore'); | ||
const chalk = importLazy('chalk'); | ||
const semver = importLazy('semver'); | ||
const semverDiff = importLazy('semver-diff'); | ||
const latestVersion = importLazy('latest-version'); | ||
const isNpm = importLazy('is-npm'); | ||
const isInstalledGlobally = importLazy('is-installed-globally'); | ||
const isYarnGlobal = importLazy('is-yarn-global'); | ||
const hasYarn = importLazy('has-yarn'); | ||
const boxen = importLazy('boxen'); | ||
const xdgBasedir = importLazy('xdg-basedir'); | ||
const isCi = importLazy('is-ci'); | ||
const pupa = importLazy('pupa'); | ||
const ONE_DAY = 1000 * 60 * 60 * 24; | ||
class UpdateNotifier { | ||
constructor(options = {}) { | ||
this.options = options; | ||
options.pkg = options.pkg || {}; | ||
options.distTag = options.distTag || 'latest'; | ||
// Reduce pkg to the essential keys. with fallback to deprecated options | ||
// TODO: Remove deprecated options at some point far into the future | ||
options.pkg = { | ||
name: options.pkg.name || options.packageName, | ||
version: options.pkg.version || options.packageVersion | ||
}; | ||
if (!options.pkg.name || !options.pkg.version) { | ||
throw new Error('pkg.name and pkg.version required'); | ||
} | ||
this.packageName = options.pkg.name; | ||
this.packageVersion = options.pkg.version; | ||
this.updateCheckInterval = typeof options.updateCheckInterval === 'number' ? options.updateCheckInterval : ONE_DAY; | ||
this.disabled = 'NO_UPDATE_NOTIFIER' in process.env || | ||
process.env.NODE_ENV === 'test' || | ||
process.argv.includes('--no-update-notifier') || | ||
isCi(); | ||
this.shouldNotifyInNpmScript = options.shouldNotifyInNpmScript; | ||
if (!this.disabled) { | ||
try { | ||
const ConfigStore = configstore(); | ||
this.config = new ConfigStore(`update-notifier-${this.packageName}`, { | ||
optOut: false, | ||
// Init with the current time so the first check is only | ||
// after the set interval, so not to bother users right away | ||
lastUpdateCheck: Date.now() | ||
}); | ||
} catch { | ||
// Expecting error code EACCES or EPERM | ||
const message = | ||
chalk().yellow(format(' %s update check failed ', options.pkg.name)) + | ||
format('\n Try running with %s or get access ', chalk().cyan('sudo')) + | ||
'\n to the local update config store via \n' + | ||
chalk().cyan(format(' sudo chown -R $USER:$(id -gn $USER) %s ', xdgBasedir().config)); | ||
process.on('exit', () => { | ||
console.error(boxen()(message, {align: 'center'})); | ||
}); | ||
} | ||
} | ||
} | ||
check() { | ||
if ( | ||
!this.config || | ||
this.config.get('optOut') || | ||
this.disabled | ||
) { | ||
return; | ||
} | ||
this.update = this.config.get('update'); | ||
if (this.update) { | ||
// Use the real latest version instead of the cached one | ||
this.update.current = this.packageVersion; | ||
// Clear cached information | ||
this.config.delete('update'); | ||
} | ||
// Only check for updates on a set interval | ||
if (Date.now() - this.config.get('lastUpdateCheck') < this.updateCheckInterval) { | ||
return; | ||
} | ||
// Spawn a detached process, passing the options as an environment property | ||
spawn(process.execPath, [path.join(__dirname, 'check.js'), JSON.stringify(this.options)], { | ||
detached: true, | ||
stdio: 'ignore' | ||
}).unref(); | ||
} | ||
async fetchInfo() { | ||
const {distTag} = this.options; | ||
const latest = await latestVersion()(this.packageName, {version: distTag}); | ||
return { | ||
latest, | ||
current: this.packageVersion, | ||
type: semverDiff()(this.packageVersion, latest) || distTag, | ||
name: this.packageName | ||
}; | ||
} | ||
notify(options) { | ||
const suppressForNpm = !this.shouldNotifyInNpmScript && isNpm().isNpmOrYarn; | ||
if (!process.stdout.isTTY || suppressForNpm || !this.update || !semver().gt(this.update.latest, this.update.current)) { | ||
return this; | ||
} | ||
options = { | ||
isGlobal: isInstalledGlobally(), | ||
isYarnGlobal: isYarnGlobal()(), | ||
...options | ||
}; | ||
let installCommand; | ||
if (options.isYarnGlobal) { | ||
installCommand = `yarn global add ${this.packageName}`; | ||
} else if (options.isGlobal) { | ||
installCommand = `npm i -g ${this.packageName}`; | ||
} else if (hasYarn()()) { | ||
installCommand = `yarn add ${this.packageName}`; | ||
} else { | ||
installCommand = `npm i ${this.packageName}`; | ||
} | ||
const defaultTemplate = 'Update available ' + | ||
chalk().dim('{currentVersion}') + | ||
chalk().reset(' → ') + | ||
chalk().green('{latestVersion}') + | ||
' \nRun ' + chalk().cyan('{updateCommand}') + ' to update'; | ||
const template = options.message || defaultTemplate; | ||
options.boxenOptions = options.boxenOptions || { | ||
padding: 1, | ||
margin: 1, | ||
align: 'center', | ||
borderColor: 'yellow', | ||
borderStyle: 'round' | ||
}; | ||
const message = boxen()( | ||
pupa()(template, { | ||
packageName: this.packageName, | ||
currentVersion: this.update.current, | ||
latestVersion: this.update.latest, | ||
updateCommand: installCommand | ||
}), | ||
options.boxenOptions | ||
); | ||
if (options.defer === false) { | ||
console.error(message); | ||
} else { | ||
process.on('exit', () => { | ||
console.error(message); | ||
}); | ||
process.on('SIGINT', () => { | ||
console.error(''); | ||
process.exit(); | ||
}); | ||
} | ||
return this; | ||
} | ||
} | ||
module.exports = options => { | ||
export default function updateNotifier(options) { | ||
const updateNotifier = new UpdateNotifier(options); | ||
updateNotifier.check(); | ||
return updateNotifier; | ||
}; | ||
module.exports.UpdateNotifier = UpdateNotifier; | ||
} |
{ | ||
"name": "update-notifier", | ||
"version": "5.1.0", | ||
"version": "6.0.0", | ||
"description": "Update notifications for your CLI app", | ||
@@ -13,10 +13,13 @@ "license": "BSD-2-Clause", | ||
}, | ||
"type": "module", | ||
"exports": "./index.js", | ||
"engines": { | ||
"node": ">=10" | ||
"node": ">=14.16" | ||
}, | ||
"scripts": { | ||
"test": "xo && ava --timeout=20s --serial" | ||
"test": "xo && ava" | ||
}, | ||
"files": [ | ||
"index.js", | ||
"update-notifier.js", | ||
"check.js" | ||
@@ -38,25 +41,29 @@ ], | ||
"dependencies": { | ||
"boxen": "^5.0.0", | ||
"chalk": "^4.1.0", | ||
"configstore": "^5.0.1", | ||
"has-yarn": "^2.1.0", | ||
"import-lazy": "^2.1.0", | ||
"is-ci": "^2.0.0", | ||
"boxen": "^7.0.0", | ||
"chalk": "^5.0.1", | ||
"configstore": "^6.0.0", | ||
"has-yarn": "^3.0.0", | ||
"import-lazy": "^4.0.0", | ||
"is-ci": "^3.0.1", | ||
"is-installed-globally": "^0.4.0", | ||
"is-npm": "^5.0.0", | ||
"is-yarn-global": "^0.3.0", | ||
"latest-version": "^5.1.0", | ||
"pupa": "^2.1.1", | ||
"semver": "^7.3.4", | ||
"semver-diff": "^3.1.1", | ||
"xdg-basedir": "^4.0.0" | ||
"is-npm": "^6.0.0", | ||
"is-yarn-global": "^0.4.0", | ||
"latest-version": "^6.0.0", | ||
"pupa": "^3.1.0", | ||
"semver": "^7.3.7", | ||
"semver-diff": "^4.0.0", | ||
"xdg-basedir": "^5.1.0" | ||
}, | ||
"devDependencies": { | ||
"ava": "^2.4.0", | ||
"clear-module": "^4.1.1", | ||
"ava": "^4.3.0", | ||
"clear-module": "^4.1.2", | ||
"fixture-stdout": "^0.2.1", | ||
"mock-require": "^3.0.3", | ||
"strip-ansi": "^6.0.0", | ||
"xo": "^0.37.1" | ||
"strip-ansi": "^7.0.1", | ||
"xo": "^0.50.0" | ||
}, | ||
"ava": { | ||
"timeout": "20s", | ||
"serial": true | ||
} | ||
} |
@@ -20,5 +20,5 @@ # update-notifier | ||
```sh | ||
npm install update-notifier | ||
``` | ||
$ npm install update-notifier | ||
``` | ||
@@ -30,6 +30,6 @@ ## Usage | ||
```js | ||
const updateNotifier = require('update-notifier'); | ||
const pkg = require('./package.json'); | ||
import updateNotifier from 'update-notifier'; | ||
import packageJson from './package.json' assert {type: 'json'}; | ||
updateNotifier({pkg}).notify(); | ||
updateNotifier({pkg: packageJson}).notify(); | ||
``` | ||
@@ -40,7 +40,7 @@ | ||
```js | ||
const updateNotifier = require('update-notifier'); | ||
const pkg = require('./package.json'); | ||
import updateNotifier from 'update-notifier'; | ||
import packageJson from './package.json' assert {type: 'json'}; | ||
// Checks for available update and returns an instance | ||
const notifier = updateNotifier({pkg}); | ||
const notifier = updateNotifier({pkg: packageJson}); | ||
@@ -186,3 +186,3 @@ // Notify using the built-in convenience method | ||
Type: `object`\ | ||
Default: `{padding: 1, margin: 1, align: 'center', borderColor: 'yellow', borderStyle: 'round'}` *(See screenshot)* | ||
Default: `{padding: 1, margin: 1, textAlignment: 'center', borderColor: 'yellow', borderStyle: 'round'}` *(See screenshot)* | ||
@@ -189,0 +189,0 @@ Options object that will be passed to [`boxen`](https://github.com/sindresorhus/boxen). |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
15441
1.15%6
20%190
4.97%Yes
NaN1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated
Updated