Files
xo-stack/packages/stack/src/utils/misc.ts
T
2025-10-16 06:23:59 +00:00

119 lines
3.6 KiB
TypeScript

import { binToHex } from '@bitauth/libauth';
// TODO: Put unsorted stuff in here and then try to sort them somewhere more sensible later.
export function getOutpointId(outpoint: {
outpointTransactionHash: Uint8Array;
outpointIndex: number;
}): string {
const outpointHashHex = binToHex(outpoint.outpointTransactionHash);
return `${outpointHashHex}:${outpoint.outpointIndex}`;
}
// TODO: Jason uses form timestampMs_entityId
export function generateActivityId() {
return Date.now().toString();
}
/**
* Checks if a URL has duplicate parameters.
*
* @param url - The URL to check
* @returns True if the URL has duplicate parameters, false otherwise
*/
export function hasDuplicateParams(url: string | URL): boolean {
if (typeof url === 'string') {
url = new URL(url);
}
const params = url.searchParams;
const seen = new Set<string>();
for (const [key] of params.entries()) {
if (seen.has(key)) {
return true;
}
seen.add(key);
}
return false;
}
/**
* Check if the given object is a Record.
*
* @param object The variable to check.
* @returns True if the object is a record.
*/
export function isRecord(
value: unknown,
): value is Record<string | number | symbol, unknown> {
if (typeof value !== 'object' || value === null) return false;
// Check if its a plain object (not a class instance, array, etc.)
const prototype = Object.getPrototypeOf(value);
return prototype === null || prototype === Object.prototype;
}
/**
* Find all the ocurrences of a given key in a plain JS object.
* NOTE: This function is intended to search keys in JSON objects
* and it will not search the key walking through collection object structures(Set, Map, etc.)
* NOTE: This function is intended to be used to traverse not too nested JSON objects.
*
* @param object The plain JS Object to traverse.
* @param key The Key to search.
*
* @throws If object can't be serializated as JSON.
* @throws If object is more than 100 levels nested.
* @returns A list of values for the given key.
*/
export function findAllKeyOcurrences(
object: Record<string | number | symbol, unknown>,
key: string,
): Array<unknown> {
// Check object serialization as JSON to avoid circular reference, BigInt values or other object structures(Set, Map, Date, etc..)
JSON.stringify(object);
// Under 100 the resource allocation is excessively fine for any JS environment or hardware.
// NOTE: If for some reason this needs to be changed be sure to add proper test cases to measure performance.
// Currently(11/09/2025) the JS stack size can handle roughly 10000 recursive calls on browsers and NodeJS.
const allowedNestedLevels = 100;
const keyValues: Array<unknown> = [];
function traverse(
currentObj: Record<string | number | symbol, unknown>,
depth: number = 0,
) {
// Stop if depth exceeds the amount of 'allowedNestedLevels'.
if (depth > allowedNestedLevels)
throw new Error(
`Maximum nesting level of ${allowedNestedLevels} reached.`,
);
// Stop when find a non object value.
if (typeof currentObj !== 'object' || currentObj === null) return;
if (Array.isArray(currentObj)) {
currentObj.forEach((item) => traverse(item, depth + 1));
return;
}
// Check if current object has the key property we are looking
if (key in currentObj) {
keyValues.push(currentObj[key]);
}
// Recursively traverse all properties
Object.values(currentObj).forEach((value) => {
if (isRecord(value)) traverse(value, depth + 1);
});
}
traverse(object);
return keyValues;
}