Oooh, apply_upgrade
looks perfect. I would use that, but it looks like it isn't in factorio stable (2.0.60) yet. Once version 2.0.61 ships then I would definitely try using that instead.
order_upgrade is available now, but without apply_upgrade the player would need to have the item in the logistic's network or inventory. That would be really nice for a non-cheat version of the mod now though.
For now, I use surface.create_entity, and pass in all the parameters available to setup the entity correctly, then set the mirror flag.
https://lua-api.factorio.com/stable/classes/LuaSurface.html#create_entity
You can see the code here: https://github.com/aarons/factorio-quality-control/blob/main/scripts/core.lua#L303
I'll be traveling for the next week, so probably won't be able to do much, but a patch is absolutely welcome if you want to take a pass at it if 2.0.61 is released soon. The ./package.sh command will zip all the lua files for the mod and copy it to factorio's directory for easy testing.
I think enabling a non-cheat mode that uses order_upgrade instead of create_entity would be a really nice option.