Files
bruno/packages/bruno-js/src/bru.js
2025-12-04 01:37:20 +05:30

285 lines
8.1 KiB
JavaScript

const { cloneDeep } = require('lodash');
const xmlFormat = require('xml-formatter');
const { interpolate: _interpolate } = require('@usebruno/common');
const { sendRequest } = require('@usebruno/requests').scripting;
const { jar: createCookieJar } = require('@usebruno/requests').cookies;
const variableNameRegex = /^[\w-.]*$/;
class Bru {
constructor(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables, oauth2CredentialVariables, collectionName, promptVariables) {
this.envVariables = envVariables || {};
this.runtimeVariables = runtimeVariables || {};
this.promptVariables = promptVariables || {};
this.processEnvVars = cloneDeep(processEnvVars || {});
this.collectionVariables = collectionVariables || {};
this.folderVariables = folderVariables || {};
this.requestVariables = requestVariables || {};
this.globalEnvironmentVariables = globalEnvironmentVariables || {};
this.oauth2CredentialVariables = oauth2CredentialVariables || {};
this.collectionPath = collectionPath;
this.collectionName = collectionName;
this.sendRequest = sendRequest;
this.cookies = {
jar: () => {
const cookieJar = createCookieJar();
return {
getCookie: (url, cookieName, callback) => {
const interpolatedUrl = this.interpolate(url);
return cookieJar.getCookie(interpolatedUrl, cookieName, callback);
},
getCookies: (url, callback) => {
const interpolatedUrl = this.interpolate(url);
return cookieJar.getCookies(interpolatedUrl, callback);
},
setCookie: (url, nameOrCookieObj, valueOrCallback, maybeCallback) => {
const interpolatedUrl = this.interpolate(url);
return cookieJar.setCookie(interpolatedUrl, nameOrCookieObj, valueOrCallback, maybeCallback);
},
setCookies: (url, cookiesArray, callback) => {
const interpolatedUrl = this.interpolate(url);
return cookieJar.setCookies(interpolatedUrl, cookiesArray, callback);
},
// Clear entire cookie jar
clear: (callback) => {
return cookieJar.clear(callback);
},
// Delete cookies for a specific URL/domain
deleteCookies: (url, callback) => {
const interpolatedUrl = this.interpolate(url);
return cookieJar.deleteCookies(interpolatedUrl, callback);
},
deleteCookie: (url, cookieName, callback) => {
const interpolatedUrl = this.interpolate(url);
return cookieJar.deleteCookie(interpolatedUrl, cookieName, callback);
}
};
}
};
// Holds variables that are marked as persistent by scripts
this.persistentEnvVariables = {};
this.runner = {
skipRequest: () => {
this.skipRequest = true;
},
stopExecution: () => {
this.stopExecution = true;
},
setNextRequest: (nextRequest) => {
this.nextRequest = nextRequest;
}
};
this.utils = {
minifyJson: (json) => {
if (json === null || json === undefined) {
throw new Error('Failed to minify');
}
if (typeof json === 'object') {
try {
return JSON.stringify(json);
} catch (err) {
throw new Error(`Failed to minify: ${err?.message || err}`);
}
}
if (typeof json === 'string') {
const trimmed = json.trim();
if (trimmed === '') return trimmed;
try {
return JSON.stringify(JSON.parse(trimmed));
} catch (err) {
throw new Error(`Failed to minify: ${err?.message || err}`);
}
}
throw new TypeError('minifyJson expects a string or object');
},
minifyXml: (xml) => {
if (xml === null || xml === undefined) {
throw new Error('Failed to minify');
}
if (typeof xml === 'string') {
try {
return xmlFormat(xml, { collapseContent: false, indentation: '', lineSeparator: '' });
} catch (err) {
throw new Error(`Failed to minify: ${err?.message || err}`);
}
}
throw new TypeError('minifyXml expects a string');
}
};
}
interpolate = (strOrObj) => {
if (!strOrObj) return strOrObj;
const isObj = typeof strOrObj === 'object';
const strToInterpolate = isObj ? JSON.stringify(strOrObj) : strOrObj;
const combinedVars = {
...this.globalEnvironmentVariables,
...this.collectionVariables,
...this.envVariables,
...this.folderVariables,
...this.requestVariables,
...this.oauth2CredentialVariables,
...this.runtimeVariables,
...this.promptVariables,
process: {
env: {
...this.processEnvVars
}
}
};
const interpolatedStr = _interpolate(strToInterpolate, combinedVars);
return isObj ? JSON.parse(interpolatedStr) : interpolatedStr;
};
cwd() {
return this.collectionPath;
}
getEnvName() {
return this.envVariables.__name__;
}
getProcessEnv(key) {
return this.processEnvVars[key];
}
hasEnvVar(key) {
return Object.hasOwn(this.envVariables, key);
}
getEnvVar(key) {
return this.interpolate(this.envVariables[key]);
}
setEnvVar(key, value, options = {}) {
if (!key) {
throw new Error('Creating a env variable without specifying a name is not allowed.');
}
if (variableNameRegex.test(key) === false) {
throw new Error(
`Variable name: "${key}" contains invalid characters! Names must only contain alpha-numeric characters, "-", "_", "."`
);
}
// When persist is true, only string values are allowed
if (options?.persist && typeof value !== 'string') {
throw new Error(`Persistent environment variables must be strings. Received ${typeof value} for key "${key}".`);
}
this.envVariables[key] = value;
if (options?.persist) {
this.persistentEnvVariables[key] = value;
} else {
if (this.persistentEnvVariables[key]) {
delete this.persistentEnvVariables[key];
}
}
}
deleteEnvVar(key) {
delete this.envVariables[key];
}
getGlobalEnvVar(key) {
return this.interpolate(this.globalEnvironmentVariables[key]);
}
setGlobalEnvVar(key, value) {
if (!key) {
throw new Error('Creating a env variable without specifying a name is not allowed.');
}
this.globalEnvironmentVariables[key] = value;
}
getOauth2CredentialVar(key) {
return this.interpolate(this.oauth2CredentialVariables[key]);
}
hasVar(key) {
return Object.hasOwn(this.runtimeVariables, key);
}
setVar(key, value) {
if (!key) {
throw new Error('Creating a variable without specifying a name is not allowed.');
}
if (variableNameRegex.test(key) === false) {
throw new Error(
`Variable name: "${key}" contains invalid characters!`
+ ' Names must only contain alpha-numeric characters, "-", "_", "."'
);
}
this.runtimeVariables[key] = this.interpolate(value);
}
getVar(key) {
if (variableNameRegex.test(key) === false) {
throw new Error(
`Variable name: "${key}" contains invalid characters!`
+ ' Names must only contain alpha-numeric characters, "-", "_", "."'
);
}
return this.interpolate(this.runtimeVariables[key]);
}
deleteVar(key) {
delete this.runtimeVariables[key];
}
deleteAllVars() {
for (let key in this.runtimeVariables) {
if (this.runtimeVariables.hasOwnProperty(key)) {
delete this.runtimeVariables[key];
}
}
}
getCollectionVar(key) {
return this.interpolate(this.collectionVariables[key]);
}
getFolderVar(key) {
return this.interpolate(this.folderVariables[key]);
}
getRequestVar(key) {
return this.interpolate(this.requestVariables[key]);
}
setNextRequest(nextRequest) {
this.nextRequest = nextRequest;
}
sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
getCollectionName() {
return this.collectionName;
}
}
module.exports = Bru;