UNPKG

@catbee/utils

Version:

A modular, production-grade utility toolkit for Node.js and TypeScript, designed for robust, scalable applications (including Express-based services). All utilities are tree-shakable and can be imported independently.

260 lines (255 loc) 8.03 kB
/* * The MIT License * * Copyright (c) 2026 Catbee Technologies. https://catbee.in/license * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ 'use strict'; var url = require('url'); var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); function appendQueryParams(url$1, params) { const urlObj = new url.URL(url$1); for (const [key, value] of Object.entries(params)) { urlObj.searchParams.set(key, value.toString()); } return urlObj.toString(); } __name(appendQueryParams, "appendQueryParams"); function parseQueryString(query) { const cleanQuery = query.startsWith("?") ? query.slice(1) : query; return Object.fromEntries(new url.URLSearchParams(cleanQuery)); } __name(parseQueryString, "parseQueryString"); function isValidUrl(url$1, requireHttps = false) { try { const parsedUrl = new url.URL(url$1); if (!parsedUrl.protocol || !parsedUrl.hostname) return false; if (requireHttps && parsedUrl.protocol !== "https:") return false; return true; } catch { return false; } } __name(isValidUrl, "isValidUrl"); function getDomain(url$1, removeSubdomains = false) { try { const { hostname } = new url.URL(url$1); if (!removeSubdomains) { return hostname; } const parts = hostname.split("."); if (parts.length <= 2) return hostname; const secondLevelDomains = [ "co", "com", "org", "net", "gov", "edu", "ac" ]; const sld = parts[parts.length - 2]; if (secondLevelDomains.includes(sld) && parts.length > 2) { return parts.slice(-3).join("."); } return parts.slice(-2).join("."); } catch { return ""; } } __name(getDomain, "getDomain"); function joinPaths(...segments) { let result = segments.filter((s) => s !== void 0 && s !== null).map((segment, index) => { if (index === 0) return segment.replace(/\/+$/, ""); return segment.replace(/^\/+|\/+$/g, ""); }).filter(Boolean).join("/"); if (segments[0] === "" && !result.startsWith("/")) result = "/" + result; return result; } __name(joinPaths, "joinPaths"); function normalizeUrl(url$1, base) { try { let normalized = url$1.startsWith("//") ? `https:${url$1}` : url$1; const parsedUrl = base ? new url.URL(normalized, base) : new url.URL(normalized); parsedUrl.pathname = parsedUrl.pathname.replace(/\/+/g, "/"); parsedUrl.pathname = parsedUrl.pathname.replace(/\/+$/, ""); parsedUrl.hostname = parsedUrl.hostname.toLowerCase(); return parsedUrl.toString(); } catch { return url$1; } } __name(normalizeUrl, "normalizeUrl"); function updateQueryParam(url$1, key, value) { try { const urlObj = new url.URL(url$1); urlObj.searchParams.set(key, String(value)); return urlObj.toString(); } catch { return url$1; } } __name(updateQueryParam, "updateQueryParam"); function createUrlBuilder(baseUrl) { return { /** * Creates a full URL with the given path and query parameters. * * @param {string} path - The path to append to the base URL. * @param {Record<string, any>} [params] - Query parameters to add. * @returns {string} The complete URL. */ path(path, params) { const url = joinPaths(baseUrl, path); return params ? appendQueryParams(url, params) : url; }, /** * Creates a full URL with query parameters but no additional path. * * @param {Record<string, any>} params - Query parameters to add. * @returns {string} The complete URL with query parameters. */ query(params) { return appendQueryParams(baseUrl, params); } }; } __name(createUrlBuilder, "createUrlBuilder"); function extractQueryParams(url$1, paramNames) { try { const parsedUrl = new url.URL(url$1); const result = {}; for (const name of paramNames) { const value = parsedUrl.searchParams.get(name); if (value !== null) { result[name] = value; } } return result; } catch { return {}; } } __name(extractQueryParams, "extractQueryParams"); function removeQueryParams(url$1, paramsToRemove) { try { const parsedUrl = new url.URL(url$1); for (const param of paramsToRemove) { parsedUrl.searchParams.delete(param); } return parsedUrl.toString(); } catch { return url$1; } } __name(removeQueryParams, "removeQueryParams"); function getExtension(url$1) { try { const { pathname } = new url.URL(url$1); const match = pathname.match(/\.([^./\\?#]+)$/); return match ? match[1].toLowerCase() : ""; } catch { const match = url$1.match(/\.([^./\\?#]+)$/); return match ? match[1].toLowerCase() : ""; } } __name(getExtension, "getExtension"); function parseTypedQueryParams(url$1, converters) { try { const { searchParams } = new url.URL(url$1); const result = {}; for (const [key, value] of searchParams.entries()) { if (converters && key in converters) { try { result[key] = converters[key](value); } catch { } } else { result[key] = value; } } return result; } catch { return {}; } } __name(parseTypedQueryParams, "parseTypedQueryParams"); function getSubdomain(url$1) { try { const { hostname } = new url.URL(url$1); const parts = hostname.split("."); if (parts.length <= 2) return ""; return parts.slice(0, -2).join("."); } catch { return ""; } } __name(getSubdomain, "getSubdomain"); function isRelativeUrl(url$1) { if (!url$1 || typeof url$1 !== "string") return false; try { new url.URL(url$1); return false; } catch { return url$1.startsWith("/") || url$1.startsWith("./") || url$1.startsWith("../"); } } __name(isRelativeUrl, "isRelativeUrl"); function toAbsoluteUrl(relativeUrl, baseUrl) { try { return new url.URL(relativeUrl, baseUrl).toString(); } catch { return relativeUrl; } } __name(toAbsoluteUrl, "toAbsoluteUrl"); function sanitizeUrl(url$1, allowedProtocols = [ "http", "https" ]) { try { const parsedUrl = new url.URL(url$1); const protocol = parsedUrl.protocol.replace(":", ""); if (!allowedProtocols.includes(protocol)) { return null; } return parsedUrl.toString(); } catch { return null; } } __name(sanitizeUrl, "sanitizeUrl"); exports.appendQueryParams = appendQueryParams; exports.createUrlBuilder = createUrlBuilder; exports.extractQueryParams = extractQueryParams; exports.getDomain = getDomain; exports.getExtension = getExtension; exports.getSubdomain = getSubdomain; exports.isRelativeUrl = isRelativeUrl; exports.isValidUrl = isValidUrl; exports.joinPaths = joinPaths; exports.normalizeUrl = normalizeUrl; exports.parseQueryString = parseQueryString; exports.parseTypedQueryParams = parseTypedQueryParams; exports.removeQueryParams = removeQueryParams; exports.sanitizeUrl = sanitizeUrl; exports.toAbsoluteUrl = toAbsoluteUrl; exports.updateQueryParam = updateQueryParam;