UNPKG

sfcc-webdav

Version:

Salesforce Commerce Cloud simple webdav API

186 lines (185 loc) 8.06 kB
#!/usr/bin/env node "use strict"; 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;