Files
n8n-nodes-gwezz-changdunovel/node_modules/n8n-workflow/dist/cjs/utils.js
2025-10-26 23:10:15 +08:00

418 lines
18 KiB
JavaScript

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 };
};
(function (factory) {
if (typeof module === "object" && typeof module.exports === "object") {
var v = factory(require, exports);
if (v !== undefined) module.exports = v;
}
else if (typeof define === "function" && define.amd) {
define(["require", "exports", "@n8n/errors", "esprima-next", "form-data", "lodash/merge", "./constants", "./errors/execution-cancelled.error", "./logger-proxy"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.removeCircularRefs = exports.isTraversableObject = exports.sleepWithAbort = exports.sleep = exports.jsonStringify = exports.replaceCircularReferences = exports.base64DecodeUTF8 = exports.jsonParse = exports.deepCopy = exports.isObjectEmpty = void 0;
exports.fileTypeFromMimeType = fileTypeFromMimeType;
exports.assert = assert;
exports.updateDisplayOptions = updateDisplayOptions;
exports.randomInt = randomInt;
exports.randomString = randomString;
exports.hasKey = hasKey;
exports.isSafeObjectProperty = isSafeObjectProperty;
exports.setSafeObjectProperty = setSafeObjectProperty;
exports.isDomainAllowed = isDomainAllowed;
exports.isCommunityPackageName = isCommunityPackageName;
const errors_1 = require("@n8n/errors");
const esprima_next_1 = require("esprima-next");
const form_data_1 = __importDefault(require("form-data"));
const merge_1 = __importDefault(require("lodash/merge"));
const constants_1 = require("./constants");
const execution_cancelled_error_1 = require("./errors/execution-cancelled.error");
const LoggerProxy = __importStar(require("./logger-proxy"));
const readStreamClasses = new Set(['ReadStream', 'Readable', 'ReadableStream']);
// NOTE: BigInt.prototype.toJSON is not available, which causes JSON.stringify to throw an error
// as well as the flatted stringify method. This is a workaround for that.
BigInt.prototype.toJSON = function () {
return this.toString();
};
const isObjectEmpty = (obj) => {
if (obj === undefined || obj === null)
return true;
if (typeof obj === 'object') {
if (obj instanceof form_data_1.default)
return obj.getLengthSync() === 0;
if (Array.isArray(obj))
return obj.length === 0;
if (obj instanceof Set || obj instanceof Map)
return obj.size === 0;
if (ArrayBuffer.isView(obj) || obj instanceof ArrayBuffer)
return obj.byteLength === 0;
if (Symbol.iterator in obj || readStreamClasses.has(obj.constructor.name))
return false;
return Object.keys(obj).length === 0;
}
return true;
};
exports.isObjectEmpty = isObjectEmpty;
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-argument */
const deepCopy = (source, hash = new WeakMap(), path = '') => {
const hasOwnProp = Object.prototype.hasOwnProperty.bind(source);
// Primitives & Null & Function
if (typeof source !== 'object' || source === null || typeof source === 'function') {
return source;
}
// Date and other objects with toJSON method
// TODO: remove this when other code parts not expecting objects with `.toJSON` method called and add back checking for Date and cloning it properly
if (typeof source.toJSON === 'function') {
return source.toJSON();
}
if (hash.has(source)) {
return hash.get(source);
}
// Array
if (Array.isArray(source)) {
const clone = [];
const len = source.length;
for (let i = 0; i < len; i++) {
clone[i] = (0, exports.deepCopy)(source[i], hash, path + `[${i}]`);
}
return clone;
}
// Object
const clone = Object.create(Object.getPrototypeOf({}));
hash.set(source, clone);
for (const i in source) {
if (hasOwnProp(i)) {
clone[i] = (0, exports.deepCopy)(source[i], hash, path + `.${i}`);
}
}
return clone;
};
exports.deepCopy = deepCopy;
// eslint-enable
function syntaxNodeToValue(expression) {
switch (expression?.type) {
case esprima_next_1.Syntax.ObjectExpression:
return Object.fromEntries(expression.properties
.filter((prop) => prop.type === esprima_next_1.Syntax.Property)
.map(({ key, value }) => [syntaxNodeToValue(key), syntaxNodeToValue(value)]));
case esprima_next_1.Syntax.Identifier:
return expression.name;
case esprima_next_1.Syntax.Literal:
return expression.value;
case esprima_next_1.Syntax.ArrayExpression:
return expression.elements.map((exp) => syntaxNodeToValue(exp));
default:
return undefined;
}
}
/**
* Parse any JavaScript ObjectExpression, including:
* - single quoted keys
* - unquoted keys
*/
function parseJSObject(objectAsString) {
const jsExpression = (0, esprima_next_1.parse)(`(${objectAsString})`).body.find((node) => node.type === esprima_next_1.Syntax.ExpressionStatement && node.expression.type === esprima_next_1.Syntax.ObjectExpression);
return syntaxNodeToValue(jsExpression?.expression);
}
/**
* Parses a JSON string into an object with optional error handling and recovery mechanisms.
*
* @param {string} jsonString - The JSON string to parse.
* @param {Object} [options] - Optional settings for parsing the JSON string. Either `fallbackValue` or `errorMessage` can be set, but not both.
* @param {boolean} [options.acceptJSObject=false] - If true, attempts to recover from common JSON format errors by parsing the JSON string as a JavaScript Object.
* @param {string} [options.errorMessage] - A custom error message to throw if the JSON string cannot be parsed.
* @param {*} [options.fallbackValue] - A fallback value to return if the JSON string cannot be parsed.
* @returns {Object} - The parsed object, or the fallback value if parsing fails and `fallbackValue` is set.
*/
const jsonParse = (jsonString, options) => {
try {
return JSON.parse(jsonString);
}
catch (error) {
if (options?.acceptJSObject) {
try {
const jsonStringCleaned = parseJSObject(jsonString);
return jsonStringCleaned;
}
catch (e) {
// Ignore this error and return the original error or the fallback value
}
}
if (options?.fallbackValue !== undefined) {
if (options.fallbackValue instanceof Function) {
return options.fallbackValue();
}
return options.fallbackValue;
}
else if (options?.errorMessage) {
throw new errors_1.ApplicationError(options.errorMessage);
}
throw error;
}
};
exports.jsonParse = jsonParse;
/**
* Decodes a Base64 string with proper UTF-8 character handling.
*
* @param str - The Base64 string to decode
* @returns The decoded UTF-8 string
*/
const base64DecodeUTF8 = (str) => {
try {
// Use modern TextDecoder for proper UTF-8 handling
const bytes = new Uint8Array(atob(str)
.split('')
.map((char) => char.charCodeAt(0)));
return new TextDecoder('utf-8').decode(bytes);
}
catch (error) {
// Fallback method for older browsers
console.warn('TextDecoder not available, using fallback method');
return atob(str);
}
};
exports.base64DecodeUTF8 = base64DecodeUTF8;
const replaceCircularReferences = (value, knownObjects = new WeakSet()) => {
if (typeof value !== 'object' || value === null || value instanceof RegExp)
return value;
if ('toJSON' in value && typeof value.toJSON === 'function')
return value.toJSON();
if (knownObjects.has(value))
return '[Circular Reference]';
knownObjects.add(value);
const copy = (Array.isArray(value) ? [] : {});
for (const key in value) {
try {
copy[key] = (0, exports.replaceCircularReferences)(value[key], knownObjects);
}
catch (error) {
if (error instanceof TypeError &&
error.message.includes('Cannot assign to read only property')) {
LoggerProxy.error('Error while replacing circular references: ' + error.message, { error });
continue; // Skip properties that cannot be assigned to (readonly, non-configurable, etc.)
}
throw error;
}
}
knownObjects.delete(value);
return copy;
};
exports.replaceCircularReferences = replaceCircularReferences;
const jsonStringify = (obj, options = {}) => {
return JSON.stringify(options?.replaceCircularRefs ? (0, exports.replaceCircularReferences)(obj) : obj);
};
exports.jsonStringify = jsonStringify;
const sleep = async (ms) => await new Promise((resolve) => {
setTimeout(resolve, ms);
});
exports.sleep = sleep;
const sleepWithAbort = async (ms, abortSignal) => await new Promise((resolve, reject) => {
if (abortSignal?.aborted) {
reject(new execution_cancelled_error_1.ManualExecutionCancelledError(''));
return;
}
const timeout = setTimeout(resolve, ms);
const abortHandler = () => {
clearTimeout(timeout);
reject(new execution_cancelled_error_1.ManualExecutionCancelledError(''));
};
abortSignal?.addEventListener('abort', abortHandler, { once: true });
});
exports.sleepWithAbort = sleepWithAbort;
function fileTypeFromMimeType(mimeType) {
if (mimeType.startsWith('application/json'))
return 'json';
if (mimeType.startsWith('text/html'))
return 'html';
if (mimeType.startsWith('image/'))
return 'image';
if (mimeType.startsWith('audio/'))
return 'audio';
if (mimeType.startsWith('video/'))
return 'video';
if (mimeType.startsWith('text/') || mimeType.startsWith('application/javascript'))
return 'text';
if (mimeType.startsWith('application/pdf'))
return 'pdf';
return;
}
function assert(condition, msg) {
if (!condition) {
const error = new Error(msg ?? 'Invalid assertion');
// hide assert stack frame if supported
if (Error.hasOwnProperty('captureStackTrace')) {
// V8 only - https://nodejs.org/api/errors.html#errors_error_capturestacktrace_targetobject_constructoropt
Error.captureStackTrace(error, assert);
}
else if (error.stack) {
// fallback for IE and Firefox
error.stack = error.stack
.split('\n')
.slice(1) // skip assert function from stack frames
.join('\n');
}
throw error;
}
}
const isTraversableObject = (value) => {
return value && typeof value === 'object' && !Array.isArray(value) && !!Object.keys(value).length;
};
exports.isTraversableObject = isTraversableObject;
const removeCircularRefs = (obj, seen = new Set()) => {
seen.add(obj);
Object.entries(obj).forEach(([key, value]) => {
if ((0, exports.isTraversableObject)(value)) {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
seen.has(value) ? (obj[key] = { circularReference: true }) : (0, exports.removeCircularRefs)(value, seen);
return;
}
if (Array.isArray(value)) {
value.forEach((val, index) => {
if (seen.has(val)) {
value[index] = { circularReference: true };
return;
}
if ((0, exports.isTraversableObject)(val)) {
(0, exports.removeCircularRefs)(val, seen);
}
});
}
});
};
exports.removeCircularRefs = removeCircularRefs;
function updateDisplayOptions(displayOptions, properties) {
return properties.map((nodeProperty) => {
return {
...nodeProperty,
displayOptions: (0, merge_1.default)({}, nodeProperty.displayOptions, displayOptions),
};
});
}
/**
* Generates a random integer within a specified range.
*
* @param {number} min - The lower bound of the range. If `max` is not provided, this value is used as the upper bound and the lower bound is set to 0.
* @param {number} [max] - The upper bound of the range, not inclusive.
* @returns {number} A random integer within the specified range.
*/
function randomInt(min, max) {
if (max === undefined) {
max = min;
min = 0;
}
return min + (crypto.getRandomValues(new Uint32Array(1))[0] % (max - min));
}
/**
* Generates a random alphanumeric string of a specified length, or within a range of lengths.
*
* @param {number} minLength - If `maxLength` is not provided, this is the length of the string to generate. Otherwise, this is the lower bound of the range of possible lengths.
* @param {number} [maxLength] - The upper bound of the range of possible lengths. If provided, the actual length of the string will be a random number between `minLength` and `maxLength`, inclusive.
* @returns {string} A random alphanumeric string of the specified length or within the specified range of lengths.
*/
function randomString(minLength, maxLength) {
const length = maxLength === undefined ? minLength : randomInt(minLength, maxLength + 1);
return [...crypto.getRandomValues(new Uint32Array(length))]
.map((byte) => constants_1.ALPHABET[byte % constants_1.ALPHABET.length])
.join('');
}
/**
* Checks if a value is an object with a specific key and provides a type guard for the key.
*/
function hasKey(value, key) {
return value !== null && typeof value === 'object' && value.hasOwnProperty(key);
}
const unsafeObjectProperties = new Set(['__proto__', 'prototype', 'constructor', 'getPrototypeOf']);
/**
* Checks if a property key is safe to use on an object, preventing prototype pollution.
* setting untrusted properties can alter the object's prototype chain and introduce vulnerabilities.
*
* @see setSafeObjectProperty
*/
function isSafeObjectProperty(property) {
return !unsafeObjectProperties.has(property);
}
/**
* Safely sets a property on an object, preventing prototype pollution.
*
* @see isSafeObjectProperty
*/
function setSafeObjectProperty(target, property, value) {
if (isSafeObjectProperty(property)) {
target[property] = value;
}
}
function isDomainAllowed(urlString, options) {
if (!options.allowedDomains || options.allowedDomains.trim() === '') {
return true; // If no restrictions are set, allow all domains
}
try {
const url = new URL(urlString);
const hostname = url.hostname;
const allowedDomainsList = options.allowedDomains
.split(',')
.map((domain) => domain.trim())
.filter(Boolean);
for (const allowedDomain of allowedDomainsList) {
// Handle wildcard domains (*.example.com)
if (allowedDomain.startsWith('*.')) {
const domainSuffix = allowedDomain.substring(2); // Remove the *. part
if (hostname.endsWith(domainSuffix)) {
return true;
}
}
// Exact match
else if (hostname === allowedDomain) {
return true;
}
}
return false;
}
catch (error) {
// If URL parsing fails, deny access to be safe
return false;
}
}
const COMMUNITY_PACKAGE_NAME_REGEX = /^(?!@n8n\/)(@[\w.-]+\/)?n8n-nodes-(?!base\b)\b\w+/g;
function isCommunityPackageName(packageName) {
COMMUNITY_PACKAGE_NAME_REGEX.lastIndex = 0;
// Community packages names start with <@username/>n8n-nodes- not followed by word 'base'
const nameMatch = COMMUNITY_PACKAGE_NAME_REGEX.exec(packageName);
return !!nameMatch;
}
});
//# sourceMappingURL=utils.js.map