UNPKG

nforce-metadata

Version:

An nforce plugin that facilitates working with the metadata api

435 lines (328 loc) 10.9 kB
var stream = require('stream'); var soap = require('./lib/soap-client'); var Poller = require('./lib/poller'); var Promise = require('bluebird'); var INVALID_SESSION_RE = /INVALID\_SESSION\_ID/i; module.exports = function(nforce, name) { // throws if the plugin already exists var plugin = nforce.plugin(name || 'meta'); // create local vars for some utils provided by nforce var _ = nforce.util._; var createResolver = nforce.util.promises.createResolver; /* describe api call */ plugin.fn('describeApi', function(data, cb) { var opts = this._getOpts(data, cb); var resolver = createResolver(opts.callback); this.meta._getSoapClient(data, function(err, client) { if(err) return resolver.reject(err); return resolver.resolve(client.describe()); }); return resolver.promise; }); /* deploy api calls */ plugin.fn('deploy', function(data, cb) { var self = this; var opts = this._getOpts(data, cb); var resolver = createResolver(opts.callback); opts.method = 'deploy'; function doDeploy(zipInput) { opts.data = { 'ZipFile': zipInput, 'DeployOptions': opts.deployOptions || opts.options || {} }; opts._resolver = resolver; self.meta._apiRequest(data, function(err, res) { if(err) return resolver.reject(err); else return resolver.resolve(null, res); }); } if(opts.zipFile instanceof stream.Stream) { var bufs = []; opts.zipFile.on('data', function(d) { bufs.push(d); }); opts.zipFile.on('end', function() { doDeploy(Buffer.concat(bufs).toString('base64')); }); opts.zipFile.resume(); } else if (opts.zipFile instanceof Buffer) { doDeploy(opts.zipFile.toString('base64')); } else if (opts.zipFile instanceof String || typeof opts.zipFile === 'string') { doDeploy(opts.zipFile); } else { throw new Error('invalid zipFile'); } return resolver.promise; }); plugin.fn('deployAndPoll', function(data, cb) { var self = this; var opts = this._getOpts(data); var resolver = createResolver(opts.callback); resolver.promise = resolver.promise || {}; var poller = resolver.promise.poller = Poller.create({ interval: self.metaOpts.pollInterval || 2000 }); opts.data = { ZipFile: opts.zipFile, DeployOptions: opts.deployOptions || opts.options || {} }; this.meta.deploy(opts).then(function(res) { poller.opts.poll = function(cb) { self.meta.checkDeployStatus({ id: res.id, includeDetails: opts.includeDetails, oauth: opts.oauth }, function(err, res) { if(err) cb(err); else cb(null, res); }); }; poller.on('done', resolver.resolve); poller.on('error', resolver.reject); poller.start(); }).catch(resolver.reject); return resolver.promise; }); plugin.fn('checkDeployStatus', function(data, cb) { var opts = this._getOpts(data, cb); opts.data = { asyncProcessId: opts.asyncProcessId || opts.id, includeDetails: opts.includeDetails }; opts.method = 'checkDeployStatus'; return this.meta._apiRequest(opts, opts.callback); }); plugin.fn('cancelDeploy', function(data, cb) { var opts = this._getOpts(data, cb); opts.data = { id: opts.id }; opts.method = 'cancelDeploy'; return this.meta._apiRequest(opts, opts.callback); }); plugin.fn('cancelDeployAndPoll', function(data, cb) { var self = this; var opts = this._getOpts(data); var resolver = createResolver(opts.callback); resolver.promise = resolver.promise || {}; var poller = resolver.promise.poller = Poller.create({ interval: self.metaOpts.pollInterval || 2000 }); opts.data = { id: opts.id, includeDetails: opts.includeDetails }; this.meta.cancelDeploy(opts).then(function(res) { poller.opts.poll = function(cb) { self.meta.checkDeployStatus({ id: res.id, includeDetails: opts.includeDetails, oauth: opts.oauth }, function(err, res) { if(err) cb(err); else cb(null, res); }); }; poller.on('done', resolver.resolve); poller.on('error', resolver.reject); poller.start(); }).catch(resolver.reject); return resolver.promise; }); /* retrieve api calls */ plugin.fn('retrieve', function(data, cb) { var opts = this._getOpts(data); opts.data = { retrieveRequest: { apiVersion: opts.apiVersion || this.apiVersion.replace('v', ''), packageNames: opts.packageNames, singlePackage: opts.singlePackage, specificFiles: opts.specificFiles, unpackaged: opts.unpackaged } }; opts.method = 'retrieve'; return this.meta._apiRequest(opts, opts.callback); }); plugin.fn('retrieveAndPoll', function(data, cb) { var self = this; var opts = this._getOpts(data); var resolver = createResolver(opts.callback); resolver.promise = resolver.promise || {}; var poller = resolver.promise.poller = Poller.create({ interval: self.metaOpts.pollInterval || 2000 }); opts.data = { retrieveRequest: { apiVersion: opts.apiVersion || this.apiVersion, packageNames: opts.packageNames, singlePackage: opts.singlePackage, specificFiles: opts.specificFiles, unpackaged: opts.unpackaged } }; this.meta.retrieve(opts).then(function(res) { poller.opts.poll = function(cb) { self.meta.checkRetrieveStatus({ id: res.id, oauth: opts.oauth }, function(err, res) { if(err) cb(err); else cb(null, res); }); }; poller.on('done', resolver.resolve); poller.on('error', resolver.reject); poller.start(); }).catch(resolver.reject); return resolver.promise; }); plugin.fn('checkRetrieveStatus', function(data, cb) { var opts = this._getOpts(data, cb); opts.data = { id: opts.id }; opts.method = 'checkRetrieveStatus'; return this.meta._apiRequest(opts, opts.callback); }); /* crud-based api calls */ plugin.fn('createMetadata', function(data, cb) { var opts = this._getOpts(data, cb); var type = opts.type; opts.data = { metadata: _.map(opts.metadata, function(m) { m.$attributes = { 'xsi:type': type }; return m; }) }; opts.method = 'createMetadata'; return this.meta._apiRequest(opts, opts.callback); }); plugin.fn('readMetadata', function(data, cb) { var opts = this._getOpts(data, cb); opts.data = { metadataType: opts.metadataType, fullNames: opts.fullNames }; opts.method = 'readMetadata'; return this.meta._apiRequest(opts, opts.callback); }); plugin.fn('updateMetadata', function(data, cb) { var opts = this._getOpts(data); var type = opts.type; opts.data = { metadata: _.map(opts.metadata, function(m) { m.$attributes = { 'xsi:type': type }; return m; }) }; opts.method = 'updateMetadata'; return this.meta._apiRequest(opts, opts.callback); }); plugin.fn('upsertMetadata', function(data, cb) { var opts = this._getOpts(data); var type = opts.type; opts.data = { metadata: _.map(opts.metadata, function(m) { m.$attributes = { 'xsi:type': type }; return m; }) }; opts.method = 'upsertMetadata'; return this.meta._apiRequest(opts, opts.callback); }); plugin.fn('deleteMetadata', function(data, cb) { var opts = this._getOpts(data); opts.data = { metadataType: opts.type || opts.metadataType, fullNames: opts.fullNames }; opts.method = 'deleteMetadata'; return this.meta._apiRequest(opts, opts.callback); }); plugin.fn('renameMetadata', function(data, cb) { var opts = this._getOpts(data); opts.data = { metadataType: opts.type || opts.metadataType, oldFullName: opts.old || opts.oldFullname, newFullName: opts.new || opts.newFullname }; opts.method = 'renameMetadata'; return this.meta._apiRequest(opts, opts.callback); }); /* utility api calls */ plugin.fn('describeMetadata', function(data, cb) { var opts = this._getOpts(data); var self = this; opts.data = { apiVersion: parseFloat( opts.apiVersion || self.apiVersion.replace('v', ''), 10 ) }; opts.method = 'describeMetadata'; return this.meta._apiRequest(opts, opts.callback); }); plugin.fn('listMetadata', function(data, cb) { var opts = this._getOpts(data, cb); opts.data = { queries: opts.queries, asOfVersion: opts.asOfVersion }; opts.method = 'listMetadata'; return this.meta._apiRequest(opts, opts.callback); }); /* low-level api calls */ plugin.fn('_getSoapClient', function(data, cb) { var self = this; var opts = this._getOpts(data, cb); var resolver = createResolver(opts.callback); if(this.soapClient) { this.soapClient.setOAuth(opts.oauth); resolver.resolve(this.soapClient); } else { soap.createClient(opts.oauth, function(err, client) { if(err) return resolver.reject(err); self.soapClient = client; resolver.resolve(client); }); } return resolver.promise; }); plugin.fn('_apiRequest', function(data, cb) { var self = this; var opts = this._getOpts(data, cb); var resolver = opts._resolver || createResolver(opts.callback); var requestOpts = { uri: opts.oauth.instance_url + '/services/Soap/m/' + self.apiVersion.replace('v', '') }; this.meta._getSoapClient(opts).then(function(client) { client.MetadataService.Metadata[opts.method](opts.data, function(err, res) { if(err) { if((INVALID_SESSION_RE.test(err.message) || INVALID_SESSION_RE.test(err.body)) && self.autoRefresh === true && (opts.oauth.refresh_token || (self.getUsername() && self.getPassword())) && !opts._retryCount) { self.autoRefreshToken.call(self, opts, function(err2, res2) { if(err2) { return resolver.reject(err2); } else { opts._retryCount = 1; opts._resolver = resolver; return self.meta._apiRequest.call(self, opts); } }); } else { resolver.reject(err); } } else { return resolver.resolve(res.result); } }, requestOpts ); }).catch(function(err) { resolver.reject(err); }); return resolver.promise; }); };