How to notify NPM package version update to user? - node.js

I have written a CLI tool in Node JS and published to NPM. Every time it's run in terminal, I need the user to be notified of a new version available and its type (patch | minor | major) so that he/she can update it accordingly. How can I implement this?
Moreover, is it possible to ask the user if he/she would like to have the package updated by itself?
A new version of Rapid React is available. Would you like to update it now?(Y\n)

Version Update Check:
I would suggest using update-notifier but strangely it doesn't work. So, I chose to handle this work by myself.
The latest version can be checked easily with package-json which fetches the metadata of a package from the npm registry. Alternatively latest-version can be used as well which uses package-json under the hood.
import boxen from 'boxen';
import chalk from 'chalk';
import semver from 'semver';
import pkgJson from 'package-json';
import semverDiff from 'semver-diff';
import { capitalizeFirstLetter } from '../utils';
import { name, version } from '../../package.json';
const checkUpdate = async () => {
const { version: latestVersion } = await pkgJson(name);
// check if local package version is less than the remote version
const updateAvailable = semver.lt(version, latestVersion as string);
if (updateAvailable) {
let updateType = '';
// check the type of version difference which is usually patch, minor, major etc.
let verDiff = semverDiff(version, latestVersion as string);
if (verDiff) {
updateType = capitalizeFirstLetter(verDiff);
}
const msg = {
updateAvailable: `${updateType} update available ${chalk.dim(version)} → ${chalk.green(latestVersion)}`,
runUpdate: `Run ${chalk.cyan(`npm i -g ${name}`)} to update`,
};
// notify the user about the available udpate
console.log(boxen(`${msg.updateAvailable}\n${msg.runUpdate}`, {
margin: 1,
padding: 1,
align: 'center',
}));
}
};
Update notification:
Every time the tool runs, user would see such a notification if an update is available.

Related

Get consuming service's package.name inside an npm package

I have the following
consuming-service
-package.json (has utilities-package as a dependency)
utilities-package (published to npm)
-package.json
-version.js
I'm trying to make version.js return the consuming service's name and version, but I'm not sure how to access consuming-service's package.json from within utilities-package
version.js
const pkg = require('../../package.json') // this doesn't work
function getVersion () {
return {
name: pkg.name,
version: pkg.version,
}
}
I'm struggling with finding the specific terms to google to find my answer.
The two best answers I have found are:
Use process.env.npm_package_name & process.env.npm_package_version. These values are automatically set if the consuming service is run with npm start or yarn start
Pass the package.json into the getVersion function.
// utilities-package/version.js
function getVersion (pkg) {
return {
name: pkg.name,
version: pkg.version,
}
}
// consuming-service
const utils = require('utilities-package')
const pkg = require('../../package.json')
const versionResult = utils.getVersion(pkg)

Is there any disadvantage of adding npm dependency on demand instead of optional dependency?

I want to add a package whenever it is required in my code than adding an optional dependency. Is there any disadvantage of this approach?
Example:
this.install('test-package');
Instead of in package.json
"optionalDependencies": {
"test-package": "^1.0.0"
},
I have used live-plugin-manager for one of my project worked well.
import {PluginManager} from "live-plugin-manager";
const manager = new PluginManager();
async function run() {
await manager.install("moment");
const moment = manager.require("moment");
console.log(moment().format());
await manager.uninstall("moment");
}
run();
There are other tools too, I recommend you checking this link if you find anything useful.

Getting DialogSet.add(): Invalid dialog being added when testing

I'm trying to build some tests for my bot dialogs. I'm using the same test code (and modified test data) with two different bots with the identical dialog names. As such, the test.js file is the same for both bots. However, when I try to run my tests via Mocha on the second bot, I am getting an Error: DialogSet.add(): Invalid dialog being added. message for each test. This does not happen with my first bot. I even tried replacing the dialog file in the second bot with the one from the (working) first, and I still got the same error. As such I can't find anything different between the bots. I even replaced all of the files in question (the test, the test data/conversation, and the dialog itself) with the files from the first bot and still got the same error. Lastly, all botbuilder packages and other dependencies are the same version between the bots. I'm at a loss here...anyone have any ideas?
Here is the dialog that is being called. I left out the actual dialog steps but that shouldn't be relevant to the issue since all of the Dialog add activity happens in the constructor.
const { TextPrompt, ChoicePrompt, ConfirmPrompt, ChoiceFactory, ComponentDialog, WaterfallDialog, DialogSet, DialogTurnStatus } = require('botbuilder-dialogs');
const { VistaServiceHelper } = require('../helpers/vistaServiceHelper');
const { TrackingServiceHelper } = require('../helpers/trackingServiceHelper');
const { CosmosDbStorage } = require('botbuilder-azure');
const LINE_PROMPT = 'linePrompt';
const ORDER_PROMPT = 'orderPrompt';
const CRITERIA_PROMPT = 'criteriaPrompt';
const SEARCH_CRITERIA = ['GO', 'PO'];
const WATERFALL_DIALOG = 'waterfallDialog';
const CONFIRM_PROMPT = 'confirmPrompt';
// Static texts
const escalateMessage = `Escalation message here`
const msDay = 86400000;
class viewOrderDialog extends ComponentDialog {
constructor(dialogId, userDialogStateAccessor, userState) {
super(dialogId);
this.addDialog(new ChoicePrompt(CRITERIA_PROMPT));
this.addDialog(new TextPrompt(ORDER_PROMPT));
this.addDialog(new TextPrompt(LINE_PROMPT, this.validateLineNumber));
this.addDialog(new ConfirmPrompt(CONFIRM_PROMPT));
this.addDialog(new WaterfallDialog(WATERFALL_DIALOG, [
this.requestOrderNumber.bind(this),
this.selectSearchCriteria.bind(this),
this.displayLineItems.bind(this),
this.displayLineStatus.bind(this),
this.loopStep.bind(this)
]));
this.initialDialogId = WATERFALL_DIALOG;
this.integrationLog = new CosmosDbStorage({
serviceEndpoint: process.env.ACTUAL_SERVICE_ENDPOINT,
authKey: process.env.ACTUAL_AUTH_KEY,
databaseId: process.env.DATABASE,
collectionId: 'integration-logs'
});
this.queryData = {};
} // End constructor
I was able to fix this by deleting the botbuilder-testing folder inside the project's node_modules folder and rerunning npm install botbuilder-testing (even though I had already confirmed version in package.json and package-lock.json were showing latest version and had run npm install and npm update).
It appears this did stem from some sort of versioning issue and for whatever reason, only completely deleting the folder and reinstalling fixed it.
You may want to also verify the version of botbuilder inside your package.json file, because all of this packages must be at the same version
Ex:
"botbuilder": "~4.10.3",
"botbuilder-ai": "~4.10.3",
"botbuilder-dialogs": "~4.10.3",
"botbuilder-testing": "~4.10.3",
I Believe the accepted answer does not work in all cases . the correct answer would be to have the same botbuilder and botbuilder-testing versions .
I had the same problem and putting the same versions (or at least not putting a botbuilder-testing version above botbuilder worked)
Example
Here are example versions that work together :
"botbuilder": "~4.13.6",
"botbuilder-dialogs": "~4.13.6",
"botbuilder-testing": "^4.13.6",

Get the version number of an installed Node package without loading it?

It is possible to get the version of the current package via
const { version } = require('./package.json')
but how can I get the version number of an arbitrary, installed package without loading it?
I found a solution with require.resolve:
const path = require('path')
// get version number without requiring the module
function packageVersion(moduleName) {
const dir = path.dirname(require.resolve(moduleName))
return require(path.join(dir, 'package.json')).version
}

What version of Node does my library support?

I'm hoping for a library or a tool which will run through my code and tell me what version of Node is required in order to run it. Perhaps better would be it alerts me to areas of the code which could be changed to support older versions.
Is there anything like that in the wild?
I'm not sure if this exactly what you are looking for, but there is an existing package.json property called "engines" where package developers can specify what version(s) they require. Not too difficult to use glob and semver packages to look through all package.json files with an "engines" requirement and compile that into an object of:
{
[version1]: [{ packageName, currentlySupported }, { ... }],
[version2]: [...],
...
}
Here is a rudimentary example of a script which will create that object for you:
npm install glob semver
checkversions.js:
const glob = require('glob');
const path = require('path');
const semver = require('semver');
const currentVersion = process.version;
const versions = {};
glob('node_modules/*/package.json', (err, files) => {
files.forEach((file) => {
const pkg = require(path.resolve(__dirname, file));
// only check add package if it specifies "engines"
if (pkg.engines && pkg.engines.node) {
const reqdVersion = pkg.engines.node.replace(/\s+/g, '');
// assume you are using a supported version
let currentlySupported = true;
// check if current node version satisfies package requirements
if (!semver.satisfies(currentVersion, reqdVersion)) {
currentlySupported = false;
}
if (!Array.isArray(versions[reqdVersion])) {
versions[reqdVersion] = [];
}
versions[reqdVersion].push({
package: file.replace(/node_modules\/(.*)\/package.json/, '$1'),
currentlySupported,
});
}
});
console.log(versions);
});
Run it:
node checkversions.js

Resources