UNPKG

@nasriya/orchestriq

Version:

A package to generate Docker files

267 lines (266 loc) 12.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const os_1 = __importDefault(require("os")); const fs_1 = __importDefault(require("fs")); const undici_1 = __importDefault(require("undici")); const helpers_1 = __importDefault(require("../../utils/helpers")); const isWindows = os_1.default.platform() === 'win32'; class DockerSocket { #_configs = undefined; #_dispatcher = new undici_1.default.Agent({ socketPath: 'unix:/var/run/docker.sock' }); constructor(configs) { this.update(configs); } #_helpers = { createURL: (str) => { try { const url = new URL(str); return url; } catch (error) { return undefined; } }, validateAuthOptions: (options) => { if (options === 'none') { return; } if (!(options && typeof options === 'object' && Object.keys(options).length > 0)) { throw new TypeError("The 'options' parameter must be an object."); } if (!('type' in options)) { throw new Error(`The authorization type must be specified.`); } switch (options.type) { case 'Basic': { if (!('username' in options)) { throw new Error(`The 'username' option is required when the 'type' is set to 'basic'.`); } if (typeof options.username !== 'string') { throw new Error(`The 'username' option must be a string when the 'type' is set to 'basic'.`); } if (options.username.length === 0) { throw new Error(`The 'username' option must not be empty when the 'type' is set to 'basic'.`); } if (!('password' in options)) { throw new Error(`The 'password' option is required when the 'type' is set to 'basic'.`); } if (typeof options.password !== 'string') { throw new Error(`The 'password' option must be a string when the 'type' is set to 'basic'.`); } if (options.password.length === 0) { throw new Error(`The 'password' option must not be empty when the 'type' is set to 'basic'.`); } break; } case 'Bearer': { if (!('token' in options)) { throw new Error(`The 'token' option is required when the 'type' is set to 'bearer'.`); } if (typeof options.token !== 'string') { throw new Error(`The 'token' option must be a string when the 'type' is set to 'bearer'.`); } if (options.token.length === 0) { throw new Error(`The 'token' option must not be empty when the 'type' is set to 'bearer'.`); } break; } default: { throw new Error(`The 'type' option must be one of 'basic' or 'bearer'.`); } } }, changeConfigs: (options) => { this.#_configs = options; if (this.#_configs.hostType === 'local') { this.#_dispatcher = new undici_1.default.Agent({ socketPath: this.#_configs.socketPath }); } }, request: { getURL: (endpoint) => { const url = new URL(this.#_configs.url.toString()); const [path, query] = endpoint.split('?'); url.pathname += path; url.pathname = url.pathname.replace(/\/+/g, '/'); if (query) { const params = new URLSearchParams(query); params.forEach((value, key) => { url.searchParams.set(key, value); }); } return url; }, getFetchOptions: (options = { method: 'GET' }) => { const hostType = this.#_configs.hostType; const headers = {}; if (hostType === 'local') { options.dispatcher = this.#_dispatcher; } if (hostType === 'network' || hostType === 'remote') { if (this.#_configs.authentication && this.#_configs.authentication !== 'none') { if (!options.headers) { options.headers = {}; } switch (this.#_configs.authentication.type) { case 'Basic': { headers['Authorization'] = `Basic ${Buffer.from(`${this.#_configs.authentication.username}:${this.#_configs.authentication.password}`).toString('base64')}`; break; } case 'Bearer': { headers['Authorization'] = `Bearer ${this.#_configs.authentication.token}`; break; } } } } options.headers = { ...options.headers, ...headers }; return options; }, }, response: { parseJSON: async (response) => { try { const json = await response.json(); return json; } catch (error) { return undefined; } }, } }; update(options) { const baseHeaders = {}; if (options === undefined || options?.hostType === 'local') { let socketPath = isWindows ? '//./pipe/docker_engine' : '/var/run/docker.sock'; if (options && 'socketPath' in options) { if (typeof options.socketPath !== 'string') { throw new Error(`The 'socketPath' option must be a string when the 'hostType' is set to 'local'.`); } if (options.socketPath.length === 0) { throw new Error(`The 'socketPath' option must not be empty when the 'hostType' is set to 'local'.`); } if (!fs_1.default.existsSync(options.socketPath)) { throw new Error(`The 'socketPath' option must point to a valid socket when the 'hostType' is set to 'local'.`); } socketPath = options.socketPath; } this.#_helpers.changeConfigs({ hostType: 'local', socketPath, url: new URL(`http://localhost:2375`) }); } else { if (!(typeof options === 'object' && Object.keys(options).length > 0)) { throw new TypeError("The 'options' parameter must be an object."); } if (!('host' in options)) { throw new Error(`The 'host' option is required when the 'hostType' is set to external ('network' or 'remote').`); } if (typeof options.host !== 'string') { throw new Error(`The 'host' option must be a string when the 'hostType' is set to 'network' or 'remote'.`); } if (options.host.length === 0) { throw new Error(`The 'host' option must not be empty when the 'hostType' is set to 'network' or 'remote'.`); } const url = this.#_helpers.createURL(options.host); if (!url) { throw new Error(`The 'host' option must be a valid URL when the 'hostType' is set to 'network'.`); } let authentication; if ('credentials' in options && options.credentials) { this.#_helpers.validateAuthOptions({ type: 'Basic', ...options.credentials }); url.username = encodeURIComponent(options.credentials.username); url.password = encodeURIComponent(options.credentials.password); } if (helpers_1.default.hasOwnProperty(options, 'authentication')) { this.#_helpers.validateAuthOptions(options.authentication); if (options?.authentication !== 'none') { authentication = options.authentication; } } const baseOptions = { url, authentication, headers: baseHeaders }; switch (options.hostType) { case 'network': { if (helpers_1.default.hasOwnProperty(options, 'protocol')) { if (options.protocol !== 'http' && options.protocol !== 'https' && options.protocol !== 'tcp') { throw new Error(`The 'protocol' option for a 'network' host must be one of 'http', 'https' or 'tcp'.`); } url.protocol = options.protocol; } else { url.protocol = 'tcp'; } if (helpers_1.default.hasOwnProperty(options, 'port')) { if (typeof options.port !== 'number') { throw new Error(`The 'port' option for a 'network' host must be a number.`); } url.port = options.port.toString(); } else { url.port = '2375'; } this.#_helpers.changeConfigs({ hostType: 'network', ...baseOptions }); return; } case 'remote': { if (helpers_1.default.hasOwnProperty(options, 'protocol')) { if (options.protocol !== 'https') { throw new Error(`The 'protocol' option for a 'remote' host must always a secure connection ('https').`); } url.protocol = 'https'; } else { url.protocol = 'https'; } if (helpers_1.default.hasOwnProperty(options, 'port')) { if (typeof options.port !== 'number') { throw new Error(`The 'port' option for a 'remote' host must be a number.`); } url.port = options.port.toString(); } this.#_helpers.changeConfigs({ hostType: 'remote', ...baseOptions }); return; } default: { throw new Error(`The 'hostType' option must be one of 'local', 'network' or 'remote'.`); } } } } /** * Makes a request to the Docker Engine API. * * @param {string} endpoint - The path to the Docker Engine API endpoint. * @param {RequestInit & { returnJSON?: boolean }} [options] - Optional parameters for the request. * @param {boolean} [options.returnJSON=true] - If true, automatically parses the response as JSON and returns the parsed object. * @returns {Promise<any>} - A promise that resolves with the response, or the parsed JSON object if `returnJSON` is true. * @throws {Error} - Throws an error if the request fails, or if the response is not a valid JSON object when `returnJSON` is true. */ async fetch(endpoint, options = { method: 'GET', returnJSON: true }) { try { const url = this.#_helpers.request.getURL(endpoint); const fetchOptions = this.#_helpers.request.getFetchOptions(options); const returnJSON = options?.returnJSON === true; const proxy = this.#_configs.hostType === 'local' ? undici_1.default.fetch : fetch; const response = await proxy(url, fetchOptions); const json = returnJSON ? await this.#_helpers.response.parseJSON(response) : undefined; if (returnJSON && !response.ok) { const message = json?.message ?? `Failed to fetch: ${response.statusText}`; throw new Error(message); } return returnJSON ? json : response; } catch (error) { console.error(error); throw error; } } /** * Retrieves the current socket configuration. * * @returns {SocketConfig} The socket configuration object. */ get configs() { return this.#_configs; } } exports.default = DockerSocket;