@adibarra/url-shortener
v1.0.1
Published
A simple and lightweight URL shortener utility library
Maintainers
Readme
@adibarra/url-shortener
A simple and lightweight URL shortener utility library for Node.js.
Provides several modular components for generating short codes, validating and normalizing URLs, and building URL shortening workflows with customizable options.
Features
- Modular design for flexible URL shortening workflows
- Highly customizable with options for generation, validation, and normalization
- Support for random and deterministic short codes
- Robust URL validation and normalization
- Batch processing and uniqueness validation
- Zero dependencies, full TypeScript support
Installation
# npm
npm install @adibarra/url-shortener
# pnpm
pnpm add @adibarra/url-shortener
# yarn
yarn add @adibarra/url-shortenerUsage
Code Generation
Basic Examples
import { generateShort, predefinedCharsets } from '@adibarra/url-shortener'
// Show all available charsets
console.log(predefinedCharsets)
const shortCode = generateShort(6, { charset: 'alphanumeric' }) // e.g., "aB3kL9"
const customCode = generateShort(6, { charset: 'abc123' }) // Custom charset
// With custom random function
function secureRandom(): number {
const buffer = randomBytes(4)
return buffer.readUInt32LE(0) / 0xFFFFFFFF
}
const secureCode = generateShort(8, { customRandomFunction: secureRandom })import { generateShortBatch } from '@adibarra/url-shortener'
const codes = generateShortBatch(5, { length: 6, charset: 'alphanumeric_lower' })
console.log(codes) // ["a1b2c3", "d4e5f6", ...]Advanced Examples
import { hashShort } from '@adibarra/url-shortener'
// Always generates the same code for the same URL
const code1 = hashShort('https://example.com', { length: 6 })
const code2 = hashShort('https://example.com', { length: 6 })
console.log(code1 === code2) // true
// With custom hash function
function customHash(url: string): number {
let hash = 0
for (let i = 0; i < url.length; i++) {
const char = url.charCodeAt(i)
hash = ((hash << 5) - hash) + char
hash = hash & hash // 32-bit integer
}
return Math.abs(hash)
}
const hashedCode = hashShort('https://example.com', {
customHashFunction: customHash,
length: 8
})URL Processing
Shortening URLs
import { shortenURL } from '@adibarra/url-shortener'
const result = shortenURL('https://example.com', { length: 6 })
console.log(result) // { code: "XyZ123", original: "https://example.com" }
const invalidResult = shortenURL('invalid-url', { length: 6 })
console.log(invalidResult) // { code: "XyZ123", original: "invalid-url" }import { shortenURL } from '@adibarra/url-shortener'
// Only shorten valid URLs
const result = shortenURL('https://example.com', {
urlProcessing: 'validate',
length: 6
})
console.log(result) // { code: "XyZ123", original: "https://example.com" }
const invalidResult = shortenURL('invalid-url', {
urlProcessing: 'validate',
length: 6
})
console.log(invalidResult) // nullimport { shortenURL } from '@adibarra/url-shortener'
// Normalize URL before shortening (also validates)
const result = shortenURL('https://EXAMPLE.COM/PATH/?query=value#fragment', {
urlProcessing: 'normalize',
lowercaseHost: true,
lowercasePath: true,
removeQuery: true,
removeFragment: true,
removeTrailingSlash: true,
length: 6
})
console.log(result) // { code: "XyZ123", original: "https://example.com/path" }import { shortenURLs } from '@adibarra/url-shortener'
const results = shortenURLs(['https://example.com', 'https://google.com'], { length: 6 })
console.log(results) // [{ code: "XyZ123", original: "https://example.com" }, { code: "AbC456", original: "https://google.com" }]Validation and Normalization
import { validateURL } from '@adibarra/url-shortener'
console.log(validateURL('https://example.com')) // true
console.log(validateURL('not-a-url')) // false
// Strict validation
console.log(validateURL('https://example.com', {
allowedProtocols: ['https:'],
allowedHosts: ['example.com']
})) // trueimport { normalizeURL } from '@adibarra/url-shortener'
console.log(normalizeURL('https://EXAMPLE.COM/PATH/?query=value#fragment', {
lowercaseHost: true,
removeQuery: true,
removeFragment: true,
removeTrailingSlash: true
})) // "https://example.com/PATH"
// Advanced normalization
console.log(normalizeURL('https://Example.Com:443//path//to//file/?q=1#hash', {
lowercaseHost: true,
lowercasePath: true,
removeDefaultPort: true,
removeDuplicateSlashes: true,
removeQuery: true,
removeFragment: true,
removeTrailingSlash: true
})) // "https://example.com/path/to/file"Custom Functions
// Custom validator
function customValidator(url: string): boolean {
return url.startsWith('https://') && url.includes('example.com')
}
console.log(validateURL('https://example.com/page', { customValidator })) // true
console.log(validateURL('https://google.com/page', { customValidator })) // false
// Custom normalizer (overrides built-in normalization options)
function customNormalizer(url: string): string | null {
try {
const parsed = new URL(url)
// Custom logic: always use HTTPS and remove www
parsed.protocol = 'https:'
parsed.hostname = parsed.hostname.replace(/^www\./, '')
return parsed.toString()
}
catch {
return null
}
}
console.log(normalizeURL('http://www.example.com/path', { customNormalizer }))
// "https://example.com/path"Advanced Usage
import { generateUniqueShortBatch, shortenURL } from '@adibarra/url-shortener'
// Example: Check uniqueness against a database
function getUniqueCodes(codes: string[]): string[] {
const existing = db.query('SELECT code FROM short_urls WHERE code IN (?)', [codes])
const existingSet = new Set(existing.map(row => row.code))
return codes.filter(code => !existingSet.has(code))
}
// Generate unique codes in bulk
const uniqueCodes = generateUniqueShortBatch(10, getUniqueCodes, { length: 6 })
console.log(uniqueCodes) // ["unique1", "unique2", ...]
// Or shorten URLs with uniqueness validation
const result = shortenURL('https://example.com', {
generator: 'validated',
getUniqueCodes,
length: 6
})
console.log(result) // { code: "uniqueCode", original: "https://example.com" }Full Example with All Options
import { shortenURL } from '@adibarra/url-shortener'
// Custom validator and normalizer functions
function customValidator(url: string): boolean {
return url.startsWith('https://') && !url.includes('spam')
}
function customNormalizer(url: string): string | null {
try {
const parsed = new URL(url)
parsed.protocol = 'https:'
parsed.hostname = parsed.hostname.replace(/^www\./, '')
return parsed.toString()
}
catch {
return null
}
}
// Example database uniqueness check
function getUniqueCodes(codes: string[]): string[] {
// Simulate checking against a database
const taken = new Set(['taken1', 'taken2'])
return codes.filter(code => !taken.has(code))
}
// Using ALL options together
const result = shortenURL('https://WWW.EXAMPLE.COM/PATH/?utm=123#frag', {
urlProcessing: 'normalize',
allowedProtocols: ['https:'],
allowedHosts: ['example.com'],
customValidator,
lowercaseHost: true,
lowercasePath: true,
removeDefaultPort: true,
removeQuery: true,
removeFragment: true,
removeTrailingSlash: true,
removeDuplicateSlashes: true,
customNormalizer,
length: 8,
charset: 'alphanumeric',
generator: 'validated',
getUniqueCodes,
maxAttempts: 1000
})
console.log(result) // { code: "uniqueCode", original: "https://example.com/path" }Error Handling
The library throws specific error types for better error handling:
UrlShortenerError: Base error classInvalidArgumentError: For invalid arguments like negative lengthsRequiredOptionError: For missing required options likegetUniqueCodesfor 'validated' generator
import { RequiredOptionError, shortenURL } from '@adibarra/url-shortener'
try {
shortenURL('https://example.com', { generator: 'validated' })
}
catch (e) {
if (e instanceof RequiredOptionError) {
console.log('Provide getUniqueCodes!')
}
}Examples
See EXAMPLES.md for detailed examples and comprehensive options.
