UNPKG

woodwing-assets

Version:

TypeScript client for interacting with the WoodWing Assets Server API

217 lines (216 loc) 8.77 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AssetsServerBase = exports.AssetsError = void 0; const axios_1 = __importDefault(require("axios")); const form_data_1 = __importDefault(require("form-data")); const fs = __importStar(require("fs")); const https_1 = __importDefault(require("https")); class AssetsError extends Error { constructor(code, message) { super(message); this.code = code; this.name = 'AssetsError'; } } exports.AssetsError = AssetsError; class AssetsServerBase { constructor(config) { this.tokenResponse = {}; this.config = config; this.tokenValidity = (config.tokenValidityInMinutes ?? 30) * 60 * 1000; this.axiosInstance = axios_1.default.create({ baseURL: config.serverUrl, httpsAgent: new https_1.default.Agent({ rejectUnauthorized: config.rejectUnauthorized }), }); } // Generic verbs get(service, params = {}) { return this.call(service, 'GET', { params }); } post(service, data = {}, sendAsJson = false) { return this.call(service, 'POST', { data }, sendAsJson); } put(service, data = {}, sendAsJson = false) { return this.call(service, 'PUT', { data }, sendAsJson); } delete(service, params = {}) { return this.call(service, 'DELETE', { params }); } download(service, filePath) { return this.downloadFile(service, filePath); } setToken(TokenResponse) { this.tokenResponse = TokenResponse; } getToken() { return this.tokenResponse; } isTokenValid() { return (!!this.tokenResponse.authToken && !!this.tokenResponse.authTimestamp && Date.now() - this.tokenResponse.authTimestamp < this.tokenValidity); } // Main wrapper async call(service, method, options, sendAsJson = true) { if (!this.isTokenValid()) { this.tokenResponse = { authToken: undefined, authTimestamp: undefined }; } if (!this.tokenResponse.authToken) { await this.authenticate(); } try { return await this.callWithAuth(service, method, options, sendAsJson); } catch (err) { if (err instanceof AssetsError && err.code === 401) { await this.authenticate(); return await this.callWithAuth(service, method, options, sendAsJson); } throw err; } } async callWithAuth(service, method, options, sendAsJson) { const config = { method, url: service.startsWith('/') ? service.slice(1) : service, ...options, headers: { ...options.headers, Authorization: `Bearer ${this.tokenResponse.authToken ?? 'placeholder'}`, }, }; if (!sendAsJson && (method === 'POST' || method === 'PUT') && config.data) { const formData = new form_data_1.default(); for (const key in config.data) { formData.append(key, config.data[key]); } config.data = formData; config.headers = { ...config.headers, ...formData.getHeaders(), }; } let response; try { response = await this.axiosInstance.request(config); } catch (err) { if (axios_1.default.isAxiosError(err)) { const status = err.response?.status ?? 500; const data = err.response?.data; // Check if response data includes errorcode/message like a soft error if (data && typeof data === 'object' && 'errorcode' in data && typeof data.errorcode === 'number') { const message = data.message || 'Unknown error from Assets Server'; throw new AssetsError(data.errorcode, message); } throw new AssetsError(status, err.message || 'HTTP request failed'); } // Non-Axios errors throw new AssetsError(500, err instanceof Error ? err.message : 'Unexpected error in callWithAuth'); } const data = response.data; // Check for soft error outside the try if (data && typeof data === 'object' && 'errorcode' in data) { const code = Number(data.errorcode); const isValidHttp = Number.isInteger(code) && code >= 100 && code <= 599; throw new AssetsError(isValidHttp ? code : 500, data.message || 'Unknown error from Assets Server'); } return data; } // Token handshake async authenticate() { const form = new form_data_1.default(); form.append('username', this.config.username); form.append('password', this.config.password); const response = await this.axiosInstance.post('/services/apilogin', form, { headers: form.getHeaders(), }); if (response.data.loginSuccess) { this.tokenResponse.authToken = response.data.authToken; this.tokenResponse.authTimestamp = Date.now(); return this.tokenResponse; } else { throw new Error(response.data.loginFaultMessage || 'Login failed'); } } // For file streams (download) async downloadFile(service, filePath) { // Ensure authentication is valid if (!this.isTokenValid()) { this.tokenResponse = { authToken: undefined, authTimestamp: undefined }; } if (!this.tokenResponse.authToken) { await this.authenticate(); } try { return await this.downloadFileWithAuth(service, filePath); } catch (err) { if (err instanceof AssetsError && err.code === 401) { await this.authenticate(); return await this.downloadFileWithAuth(service, filePath); } throw err; } } async downloadFileWithAuth(service, filePath) { const response = await this.axiosInstance.get(service, { headers: { Authorization: `Bearer ${this.tokenResponse.authToken ?? 'placeholder'}` }, responseType: 'stream', }); const writer = fs.createWriteStream(filePath); return new Promise((resolve, reject) => { response.data.pipe(writer); writer.on('finish', () => resolve(filePath)); writer.on('error', reject); }); } } exports.AssetsServerBase = AssetsServerBase; // Replacement policies AssetsServerBase.FOLDER_REPLACE_POLICY_AUTO_RENAME = 'AUTO_RENAME'; AssetsServerBase.FOLDER_REPLACE_POLICY_MERGE = 'MERGE'; AssetsServerBase.FOLDER_REPLACE_POLICY_THROW_EXCEPTION = 'THROW_EXCEPTION'; AssetsServerBase.FILE_REPLACE_POLICY_AUTO_RENAME = 'AUTO_RENAME'; AssetsServerBase.FILE_REPLACE_POLICY_OVERWRITE = 'OVERWRITE'; AssetsServerBase.FILE_REPLACE_POLICY_OVERWRITE_IF_NEWER = 'OVERWRITE_IF_NEWER'; AssetsServerBase.FILE_REPLACE_POLICY_REMOVE_SOURCE = 'REMOVE_SOURCE'; AssetsServerBase.FILE_REPLACE_POLICY_THROW_EXCEPTION = 'THROW_EXCEPTION'; AssetsServerBase.FILE_REPLACE_POLICY_DO_NOTHING = 'DO_NOTHING';