UNPKG

@unitio-code/url-shortener

Version:
116 lines (115 loc) 4.01 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createShortUrl = createShortUrl; exports.decodeUrl = decodeUrl; const utils_1 = require("./utils"); /** * Default options for creating a short URL */ const DEFAULT_CREATE_OPTIONS = { ...utils_1.DEFAULT_SHORT_URL_OPTIONS, hashAlgorithm: "djb2", maxRetries: 10, }; /** * Creates a short URL from a long URL with customizable options * @param longUrl - The original long URL to shorten * @param domain - Domain name for the short URL * @param options - Optional configuration options * @returns The shortened URL */ async function createShortUrl(longUrl, domain, options) { if (!(0, utils_1.isValidUrl)(longUrl)) { throw new Error("Invalid URL provided"); } const opts = { ...DEFAULT_CREATE_OPTIONS, domain, ...options, }; const storage = opts.storage || utils_1.defaultStorage; const maxRetries = opts.maxRetries || 10; let hash; let attempts = 0; let positiveHash; if (opts.hashAlgorithm === "custom" && opts.customHashFn) { hash = opts.customHashFn(longUrl); } else if (opts.hashAlgorithm === "sdbm") { hash = 0; for (let i = 0; i < longUrl.length; i++) { const char = longUrl.charCodeAt(i); hash = char + (hash << 6) + (hash << 16) - hash; } } else { hash = 5381; for (let i = 0; i < longUrl.length; i++) { const char = longUrl.charCodeAt(i); hash = (hash << 5) + hash + char; } } positiveHash = Math.abs(hash); if (await (0, utils_1.hasUrlMapping)(positiveHash, storage)) { const existingUrl = await (0, utils_1.getOriginalUrl)(positiveHash, storage); if (existingUrl === longUrl) { return (0, utils_1.buildShortUrl)(positiveHash, opts); } } do { if (attempts > 0) { if (opts.hashAlgorithm === "custom" && opts.customHashFn) { hash = opts.customHashFn(longUrl + attempts); } else if (opts.hashAlgorithm === "sdbm") { hash = 0; const input = longUrl + attempts; for (let i = 0; i < input.length; i++) { const char = input.charCodeAt(i); hash = char + (hash << 6) + (hash << 16) - hash; } } else { hash = 5381; const input = longUrl + attempts; for (let i = 0; i < input.length; i++) { const char = input.charCodeAt(i); hash = (hash << 5) + hash + char; } } positiveHash = Math.abs(hash); } attempts++; } while (await (0, utils_1.hasUrlMapping)(positiveHash, storage) && attempts < maxRetries); if (attempts >= maxRetries) { throw new Error("Failed to generate unique short URL after maximum retries"); } await (0, utils_1.storeUrlMapping)(positiveHash, longUrl, storage, opts.ttl); return (0, utils_1.buildShortUrl)(positiveHash, opts); } /** * Extracts the short code from a short URL * @param shortUrl - The short URL * @returns The extracted short code */ function extractShortCode(shortUrl) { const urlWithoutProtocol = shortUrl.replace(/^https?:\/\//, ""); const parts = urlWithoutProtocol.split("/"); return parts[parts.length - 1]; } /** * Decodes a short URL back to its original URL * @param shortUrl - The shortened URL to decode * @param storage - Storage instance to use (optional) * @returns The original URL if found, or undefined if not found */ async function decodeUrl(shortUrl, storage) { try { const shortCode = extractShortCode(shortUrl); const id = (0, utils_1.decodeShortUrl)(shortCode); return await (0, utils_1.getOriginalUrl)(id, storage || utils_1.defaultStorage); } catch (error) { return undefined; } }