Quickest way I found was to use jsforce. My method is basically retrieving the source object's metadata, changing it's name all across, and then creating a new custom object with the changed metadata. Nice & easy, except that it doesn't clone the source object's page layouts (not yet supported by jsforce, it seems).
Here's some code for reference in case this helps anyone:
import { config } from './config.js';
import * as jsforce from 'jsforce';
String.prototype.replaceAll = function (search, replacement) {
var target = this;
return target.replace(new RegExp(search, 'g'), replacement);
};
function main() {
let conn = new jsforce.Connection({
loginUrl: config.salesForceLoginUrl
});
console.log('login with', config.salesForceUser);
conn.login(config.salesForceUser, config.salesForcePassword + config.salesForceSecurityToken,
function (err, loginRes) {
if (err) { return console.error(err); }
console.log('logged in!');
getMetadata(conn);
});
}
function getMetadata(conn) {
console.log('get meta data');
var fullNames = ['My_Source_Object__c'];
conn.metadata.read('CustomObject', fullNames, function (err, meta) {
if (err) { console.error(err); }
console.log(meta);
return;
let sMeta = JSON.stringify(meta);
sMeta = sMeta.replaceAll('My_Source_Object', 'My_Target_Object')
sMeta = sMeta.replaceAll('My Source Object', 'My Target Object')
conn.metadata.create('CustomObject', JSON.parse(sMeta), function (err, results) {
if (err) { console.err(err); }
console.log('new custom object created!');
});
});
}
main();