UNPKG

balena-sdk

Version:
203 lines (202 loc) • 7.25 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BalenaWebResourceFile = exports.limitedMap = exports.delay = exports.groupByMap = exports.isNotFoundResponse = exports.isUnauthorizedResponse = exports.withSupervisorLockedError = exports.isFullUuid = exports.isId = exports.onlyIf = exports.notImplemented = void 0; exports.mergePineOptionsTyped = mergePineOptionsTyped; exports.mergePineOptions = mergePineOptions; const tslib_1 = require("tslib"); const errors = tslib_1.__importStar(require("balena-errors")); const mime = tslib_1.__importStar(require("mime")); const notImplemented = () => { throw new Error('The method is not implemented.'); }; exports.notImplemented = notImplemented; const onlyIf = (condition) => (fn) => { if (condition) { return fn; } else { return exports.notImplemented; } }; exports.onlyIf = onlyIf; const isId = (v) => typeof v === 'number'; exports.isId = isId; const isFullUuid = (v) => typeof v === 'string' && (v.length === 32 || v.length === 62); exports.isFullUuid = isFullUuid; const SUPERVISOR_LOCKED_STATUS_CODE = 423; const withSupervisorLockedError = async (fn) => { try { return await fn(); } catch (err) { if (err.statusCode === SUPERVISOR_LOCKED_STATUS_CODE) { throw new errors.BalenaSupervisorLockedError(); } throw err; } }; exports.withSupervisorLockedError = withSupervisorLockedError; const isBalenaRequestErrorResponseWithCode = (error, statusCode) => error.code === 'BalenaRequestError' && error.statusCode === statusCode; const isUnauthorizedResponse = (err) => isBalenaRequestErrorResponseWithCode(err, 401); exports.isUnauthorizedResponse = isUnauthorizedResponse; const isNotFoundResponse = (err) => isBalenaRequestErrorResponseWithCode(err, 404); exports.isNotFoundResponse = isNotFoundResponse; // TODO: Make it so that it also infers the extras param function mergePineOptionsTyped(defaults, extras) { return mergePineOptions(defaults, extras); } const passthroughPineOptionKeys = ['$top', '$skip', '$orderby']; function mergePineOptions(defaults, extras) { if (!extras) { return defaults; } const result = { ...defaults }; if (extras.$select != null) { const extraSelect = extras.$select == null || Array.isArray(extras.$select) || extras.$select === '*' ? // TS should be able to infer this extras.$select : [extras.$select]; if (extraSelect === '*') { result.$select = '*'; } else { result.$select = [ ...(typeof result.$select === 'string' ? [result.$select] : Array.isArray(result.$select) ? result.$select : []), ...(extraSelect !== null && extraSelect !== void 0 ? extraSelect : []), ]; } } for (const key of passthroughPineOptionKeys) { if (key in extras) { // @ts-expect-error TS doesn't realize that for the same key the values are compatible result[key] = extras[key]; } } if (extras.$filter != null) { result.$filter = defaults.$filter != null ? { $and: [defaults.$filter, extras.$filter], } : extras.$filter; } if (extras.$expand != null) { result.$expand = mergeExpandOptions(defaults.$expand, extras.$expand); } return result; } const mergeExpandOptions = (defaultExpand, extraExpand) => { var _a; if (defaultExpand == null) { return extraExpand; } // We only need to clone the defaultExpand as it's the only one we mutate const $defaultExpand = convertExpandToObject(defaultExpand, true); const $extraExpand = convertExpandToObject(extraExpand); for (const expandKey of Object.keys($extraExpand || {})) { $defaultExpand[expandKey] = mergePineOptions((_a = $defaultExpand[expandKey]) !== null && _a !== void 0 ? _a : {}, $extraExpand[expandKey]); } return $defaultExpand; }; // Converts a valid expand object in any format into a new object // containing (at most) $expand, $filter and $select keys const convertExpandToObject = (expandOption, cloneIfNeeded = false) => { if (expandOption == null) { return {}; } if (typeof expandOption === 'string') { return { [expandOption]: {}, }; } if (Array.isArray(expandOption)) { // Reduce the array into a single object return expandOption.reduce((result, option) => Object.assign(result, typeof option === 'string' ? { [option]: {} } : option), {}); } if (cloneIfNeeded) { return { ...expandOption }; } return expandOption; }; /** * Useful when you want to avoid having to manually parse the key * or when need order guarantees while iterating the keys. * @private */ const groupByMap = (entries, iteratee) => { const result = new Map(); for (const entry of entries) { const key = iteratee(entry); let keyGroup = result.get(key); if (keyGroup == null) { keyGroup = []; result.set(key, keyGroup); } keyGroup.push(entry); } return result; }; exports.groupByMap = groupByMap; const delay = (ms) => new Promise((resolve) => { setTimeout(resolve, ms); }); exports.delay = delay; const DEFAULT_CONCURRENCY_LIMIT = 50; const limitedMap = (arr, fn, { concurrency = DEFAULT_CONCURRENCY_LIMIT, } = {}) => { if (concurrency >= arr.length) { return Promise.all(arr.map(fn)); } return new Promise((resolve, reject) => { const result = new Array(arr.length); let inFlight = 0; let idx = 0; const runNext = async () => { // Store the idx to use for this call before incrementing the main counter const i = idx; idx++; if (i >= arr.length) { return; } try { inFlight++; result[i] = await fn(arr[i], i, arr); void runNext(); } catch (err) { // Stop any further iterations idx = arr.length; // Clear the results so far for gc result.length = 0; reject(err); } finally { inFlight--; if (inFlight === 0) { resolve(result); } } }; while (inFlight < concurrency) { void runNext(); } }); }; exports.limitedMap = limitedMap; class BalenaWebResourceFile extends Blob { constructor(blobParts, name, options) { var _a, _b; const opts = { ...options, type: (_b = (_a = options === null || options === void 0 ? void 0 : options.type) !== null && _a !== void 0 ? _a : mime.getType(name)) !== null && _b !== void 0 ? _b : undefined, }; super(blobParts, opts); this.name = name; } } exports.BalenaWebResourceFile = BalenaWebResourceFile;