Allow more flexible installation via the palette manager + maybe a breaking change in the Editor?

Came across a bit of an issue while trying to test a new major version of UIBUILDER.

I need to do a bunch of install tests to make sure that installations are as robust as possible and that there are no strange timing or race conditions.

But to do that, I think I need to be able to use the palette manage to do the install the same way as a user would?

So my request would be the ability to be able to use any valid npm package definition string including local paths and remote github including branches.

If there is an alternative way of doing this that uses the same process as the palette manager, I'm all ears. :smiley:

So, as a temporary workaround, I've built this flow to use the admin API to install the local package:

[{"id":"f1a0c0de03","type":"inject","z":"f1a0c0de01","name":"Install from folder","props":[{"p":"modulePath","v":"/src/node-red-contrib-uibuilder","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":120,"y":120,"wires":[["f1a0c0de04"]]},{"id":"f1a0c0de04","type":"function","z":"f1a0c0de01","name":"Build JSON request","func":"const modulePath = msg.modulePath;\nif (!modulePath) {\n    node.error('msg.modulePath is required', msg);\n    return null;\n}\n\nmsg.payload = { module: modulePath };\nmsg.headers = {};\n\nconst base = (env.get('NR_ADMIN_URL') || 'http://localhost:1885').replace(/\\/+$/, '');\nmsg.method = 'POST';\nmsg.url = `${base}/nodes`;\n\nconst token = env.get('NR_ADMIN_TOKEN');\nif (token) {\n    msg.headers.Authorization = 'Bearer ' + token;\n}\n\nnode.status({ fill: 'blue', shape: 'ring', text: 'installing...' });\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":120,"wires":[["f1a0c0de08"]]},{"id":"f1a0c0de08","type":"http request","z":"f1a0c0de01","name":"POST /nodes","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":580,"y":120,"wires":[["f1a0c0de09"]]},{"id":"f1a0c0de09","type":"function","z":"f1a0c0de01","name":"Format result","func":"const body = msg.payload;\n\nif (msg.statusCode === 200 && body && body.name) {\n    node.status({ fill: 'green', shape: 'dot', text: body.name + '@' + body.version });\n    msg.payload = {\n        installed: body.name,\n        version: body.version,\n        nodes: (body.nodes || []).map(n => `${n.id} [${(n.types || []).join(', ')}]`)\n    };\n    return msg;\n}\n\nconst hints = {\n    401: 'Not authorised - set NR_ADMIN_TOKEN to a valid bearer token',\n    404: 'Not found - check the URL / httpAdminRoot, and that palette editing is enabled'\n};\n\nnode.status({ fill: 'red', shape: 'ring', text: 'failed (' + msg.statusCode + ')' });\nmsg.payload = {\n    error: true,\n    status: msg.statusCode,\n    hint: hints[msg.statusCode],\n    detail: body\n};\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":750,"y":120,"wires":[["f1a0c0de0a"]]},{"id":"f1a0c0de0a","type":"debug","z":"f1a0c0de01","name":"Install result","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":910,"y":120,"wires":[]}]

However, I'm not sure whether something has changed with Node-RED v5.0.9?

Previously, an Editor plugin would definitely run BEFORE any node Editor code is run. This no longer seems to be the case, my Editor plugin is running AFTER which is very much messing things up.

Not sure if this is something I've done in my code or whether something has changed in Node-RED?