sfcc-webdav
Version:
Salesforce Commerce Cloud simple webdav API
186 lines (185 loc) • 8.06 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fileDelete = exports.fileUpload = exports.Webdav = void 0;
const axios_1 = __importDefault(require("axios"));
const byte_size_1 = __importDefault(require("byte-size"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const picocolors_1 = __importDefault(require("picocolors"));
const cwd = process.cwd();
const { log, error } = console;
function getDwJson() {
let dwjsonpath = path_1.default.join(cwd, 'dw.json');
if (!fs_1.default.existsSync(dwjsonpath)) {
error(picocolors_1.default.red(`Missing file ${dwjsonpath}\n`));
throw new Error(`Missing file ${dwjsonpath}`);
}
const dwjson = JSON.parse(fs_1.default.readFileSync(path_1.default.join(cwd, 'dw.json'), { encoding: 'utf8' }));
return dwjson;
}
class Webdav {
constructor(dwJson) {
this.useDwJson(dwJson);
this.token = undefined;
this.trace = false;
this.axios = axios_1.default.create();
this.axios.interceptors.request.use(request => {
if (this.trace) {
log(picocolors_1.default.cyan('Sending Request:'));
log(picocolors_1.default.cyan('baseUrl: '), request.baseURL);
log(picocolors_1.default.cyan('url: '), request.url);
log(picocolors_1.default.cyan('method: '), request.method);
log(picocolors_1.default.cyan('headers: '), JSON.stringify(request.headers));
log(picocolors_1.default.cyan('data: '), JSON.stringify(request.data));
}
return request;
});
this.axios.interceptors.response.use(response => {
if (this.trace) {
log(picocolors_1.default.cyan('Sending Response:'));
log(picocolors_1.default.cyan('Status: '), response.status);
log(picocolors_1.default.cyan('Status Msg: '), response.statusText);
log(picocolors_1.default.cyan('Response Data: '), JSON.stringify(response.data));
}
return response;
});
}
useDwJson(dwJson) {
this.clientId = (dwJson === null || dwJson === void 0 ? void 0 : dwJson.client_id) || (dwJson === null || dwJson === void 0 ? void 0 : dwJson['client-id']);
this.clientSecret = (dwJson === null || dwJson === void 0 ? void 0 : dwJson.client_secret) || (dwJson === null || dwJson === void 0 ? void 0 : dwJson['client-secret']);
this.hostname = dwJson === null || dwJson === void 0 ? void 0 : dwJson.hostname;
this.codeVersion = dwJson === null || dwJson === void 0 ? void 0 : dwJson['code-version'];
}
toServerPath(file) {
let basepath = `/cartridges/${this.codeVersion}/`;
let cartridgepath = path_1.default.basename(file.substr(0, file.indexOf('/cartridge/'))) + file.substr(file.indexOf('/cartridge/'));
return `${basepath}${cartridgepath}`;
}
async authorize() {
if (!this.clientId) {
error(picocolors_1.default.red("Missing Client-id! Cannot make authorize request without it."));
throw "Missing Client-id";
}
if (!this.clientSecret) {
error(picocolors_1.default.red("Missing Client-secret! Cannot make authorize request without it."));
throw "Missing Client-secret";
}
const { data } = await this.axios.request({
url: 'https://account.demandware.com/dw/oauth2/access_token?grant_type=client_credentials',
method: 'post',
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
auth: {
username: this.clientId,
password: this.clientSecret
}
});
this.token = data.access_token;
}
async sendRequest(options, callback, retry) {
var _a;
try {
let { data } = await this.axios.request(options);
callback(data);
}
catch (err) {
error(picocolors_1.default.red(`Error processing request for file ${options.url}: ${err.message}`));
if ((_a = options === null || options === void 0 ? void 0 : options.headers) === null || _a === void 0 ? void 0 : _a.Authorization) {
if (this.trace)
console.debug(`Expiring Token! ${this.token}`);
await this.authorize();
if (this.trace)
console.debug(`New Token! ${this.token}`);
options.headers.Authorization = `Bearer ${this.token}`;
}
try {
if (retry) {
await retry();
}
else {
let { data } = await axios_1.default.request(options);
callback(data);
}
}
catch (innerErr) {
error(picocolors_1.default.red(`Error processing retry: ${err.message}`));
throw err;
}
}
}
async fileUpload(file, relativepath, retry) {
if (!this.hostname) {
error(picocolors_1.default.red("Missing hostname! Cannot make create a request without it."));
throw "Missing hostname";
}
if (!this.token)
await this.authorize();
const fileStream = fs_1.default.createReadStream(file);
fileStream.on('error', (err) => error(`On Upload request of file ${file}, ReadStream Error: ${err}`));
const size = fs_1.default.statSync(file).size;
fileStream.on('ready', async () => {
const options = {
baseURL: `https://${this.hostname}`,
url: `/on/demandware.servlet/webdav/Sites${relativepath}`,
headers: {
Authorization: `Bearer ${this.token}`
},
method: 'PUT',
decompress: true,
maxContentLength: Infinity,
maxBodyLength: Infinity,
data: fileStream
};
if (retry) {
await this.sendRequest(options, () => log(picocolors_1.default.cyan(`Uploaded ${relativepath} [${(0, byte_size_1.default)(size)}]`)), async () => this.fileUpload(file, relativepath, false));
}
else {
await this.sendRequest(options, () => log(picocolors_1.default.cyan(`Uploaded ${relativepath} [${(0, byte_size_1.default)(size)}]`)));
}
});
}
async fileDelete(file, relativepath) {
if (!this.hostname) {
error(picocolors_1.default.red("Missing hostname! Cannot make create a request without it."));
throw "Missing hostname";
}
if (!this.token)
await this.authorize();
const options = {
baseURL: `https://${this.hostname}`,
url: `/on/demandware.servlet/webdav/Sites${relativepath}`,
headers: {
Authorization: `Bearer ${this.token}`
},
method: 'DELETE'
};
await this.sendRequest(options, () => log(picocolors_1.default.cyan(`Deleted ${relativepath}`)));
}
}
exports.Webdav = Webdav;
const webdav = new Webdav(getDwJson());
webdav.Webdav = Webdav;
exports.default = webdav;
/**
* Upload a file via webdav
* @param {string} file Local file path
* @param {string} remote path, starting with '/cartridges'
*/
async function fileUpload(file, relativepath) {
await webdav.fileUpload(file, relativepath, true);
}
exports.fileUpload = fileUpload;
/**
* Deletes a file via webdav
* @param {string} file Local file path
* @param {string} remote path, starting with '/cartridges'
*/
async function fileDelete(file, relativepath) {
await webdav.fileDelete(file, relativepath);
}
exports.fileDelete = fileDelete;