TypeScript SDK
BetaServer-side environments (Node.js, Deno, Bun, etc.)
Work in Progress
This SDK is currently in beta and under active development. It is not recommended for production use as APIs and functionality may change without notice.
Current Status:
- Designed for server-side use (Node.js primarily, with potential support for Deno, Bun, and Cloudflare Workers)
- Core functionality is implemented but may have breaking changes
- API responses and error handling are being standardized
- Documentation and examples are being expanded
For the latest updates and changes, please check the GitHub repository.
Installation
Install the SDK using your preferred package manager:
npm install @fynlink/sdk
yarn add @fynlink/sdk
pnpm add @fynlink/sdk
Dependencies
The SDK has the following dependencies that will be installed automatically:
axios
- HTTP client for making API requestsbad-words
- Content filtering and moderationlibsodium-wrappers-sumo
- Cryptographic operationsnanoid
- ID generation
Note: All modern package managers (npm, yarn, and pnpm) will handle these dependencies automatically. You don't need to install them separately.
Quick Start
Get started with the Fynlink SDK by following these examples:
Initialize Client
⚠️ Security Warning
This SDK is designed for server-side use only. Never expose your token or secret in client-side code or public repositories. Always store these credentials in secure environment variables on your server.
// Load credentials from environment variables
const token = process.env.FYNLINK_TOKEN;
const secret = process.env.FYNLINK_SECRET;
import { Fyn } from '@fynlink/sdk';
const fyn = new Fyn({
token, // Format: token_<your-token>
secret // Format: secret_<your-secret>, required only for view/list/update operations
});
import { Fyn } from '@fynlink/sdk';
// Initialize with all available options
const fyn = new Fyn({
// Required options
token: 'token_<your-token>',
secret: 'secret_<your-secret>', // Required only to view/list or update links
// Optional configuration
baseUrl: 'https://api.fyn.link/v1', // Custom API endpoint
timeout: 10000, // Request timeout in milliseconds
// Cache configuration
cache: {
enabled: true, // Enable/disable caching
maxSize: 1000, // Maximum number of items to cache
ttl: '1h', // Time to live for cached items
staleWhileRevalidate: true, // Use stale cache while fetching fresh data
},
// Retry configuration
retry: {
maxRetries: 3, // Maximum number of retry attempts
initialDelay: 1000, // Initial delay between retries (ms)
maxDelay: 5000, // Maximum delay between retries (ms)
backoffFactor: 2, // Exponential backoff factor
},
// Debug configuration
debug: {
enabled: false, // Enable debug logging
level: 'info', // Log level: 'debug' | 'info' | 'warn' | 'error'
handler: console.log, // Custom debug log handler
}
});
Configuration Reference
Required Options
token
Your API token from the Fynlink Dashboard. Format: token_*
secret
Your API secret. Required only for viewing, listing, or updating links. Format: secret_*
Optional Options
baseUrl
Custom API endpoint. Default: https://api.fyn.link/v1
timeout
Request timeout in milliseconds. Default: 10000
Cache Options
cache.enabled
Enable or disable caching. Default: true
cache.maxSize
Maximum number of items to cache. Default: 1000
cache.ttl
Time to live for cached items. Default: '1h'
cache.staleWhileRevalidate
Use stale cache while fetching fresh data. Default: true
Retry Options
retry.maxRetries
Maximum number of retry attempts. Default: 3
retry.initialDelay
Initial delay between retries in milliseconds. Default: 1000
retry.maxDelay
Maximum delay between retries in milliseconds. Default: 5000
retry.backoffFactor
Exponential backoff factor. Default: 2
Debug Options
debug.enabled
Enable debug logging. Default: false
debug.level
Log level. Default: 'info'
debug.handler
Custom debug log handler. Default: console.log
Links
Create Link
Basic Usage
Create a simple link with minimal configuration.
const link = await fyn.links.create({
target: 'https://example.com',
domain: 'fyn.li'
});
{
data: {
id: 'link_abc123',
short_url: 'https://fyn.li/xyz789',
target: {
default: 'https://example.com',
ios: null,
android: null,
geo: {}
},
clicks: 0,
created_at: '2024-03-15T10:30:00Z'
}
}
Advanced Usage
Create a link with advanced options like platform-specific targeting, password protection, and geo-targeting.
const link = await fyn.links.create({
target: 'https://example.com',
domain: 'fyn.li',
title: 'My Example Link',
notes: 'Important link for documentation',
tags: ['docs', 'example'],
privateLink: true,
safeMode: true,
password: 'secretpass123',
expiry: 86400, // 24 hours in seconds
iosLink: 'https://apps.apple.com/app/myapp',
androidLink: 'https://play.google.com/store/apps/myapp',
geoTargets: {
US: 'https://us.example.com',
UK: 'https://uk.example.com'
}
});
{
data: {
id: 'link_abc123',
short_url: 'https://fyn.li/xyz789',
target: {
default: 'https://example.com',
ios: 'https://apps.apple.com/app/myapp',
android: 'https://play.google.com/store/apps/myapp',
geo: {
US: 'https://us.example.com',
UK: 'https://uk.example.com'
}
},
title: 'My Example Link',
notes: 'Important link for documentation',
tags: ['docs', 'example'],
is_private: true,
safe_mode: true,
password_enabled: true,
clicks: 0,
created_at: '2024-03-15T10:30:00Z',
updated_at: '2024-03-15T10:30:00Z',
expire_at: '2024-03-16T10:30:00Z'
}
}
Get Link by ID
const link = await fyn.links.get('link_abc123');
{
data: {
id: 'link_abc123',
short_url: 'https://fyn.li/xyz789',
target: {
default: 'https://example.com',
ios: null,
android: null,
geo: {}
},
clicks: 42,
created_at: '2024-03-15T10:30:00Z',
updated_at: '2024-03-15T10:30:00Z'
}
}
List Links
Basic Usage
List all links with default pagination (20 items per page).
const links = await fyn.links.list();
{
data: [
{
id: 'link_abc123',
short_url: 'https://fyn.li/xyz789',
target: {
default: 'https://example.com',
ios: null,
android: null,
geo: {}
},
clicks: 42,
created_at: '2024-03-15T10:30:00Z'
},
// ... more links
],
meta: {
current_page: 1,
from: 1,
to: 20,
last_page: 5,
per_page: 20,
total: 100
}
}
Advanced Usage
List links with custom pagination, sorting, and filtering options.
import { SortBy, SortOrder, LinkStatus } from '@fynlink/sdk';
const links = await fyn.links.list({
page: 1,
limit: 20,
sortBy: SortBy.CreatedAt,
sortOrder: SortOrder.Desc,
filters: [
{
is_private: true,
safe_mode: true,
status: LinkStatus.Active
}
]
});
{
data: [/* array of link objects */],
meta: {
current_page: 1,
from: 1,
to: 20,
last_page: 5,
per_page: 20,
total: 100
}
}
Domains
Team
Analytics
Features
Explore the powerful features of the TypeScript SDK:
Automatic Retries
Smart retry mechanism for handling transient failures with configurable retry policies.
// Configure retry behavior
const fyn = new Fyn({
retry: {
maxRetries: 3, // Maximum retry attempts
initialDelay: 1000, // Initial delay in ms
maxDelay: 5000, // Maximum delay cap
backoffFactor: 2 // Exponential backoff multiplier
}
});
// Retry behavior in action
try {
const link = await fyn.links.get('link_123');
} catch (error) {
if (error instanceof RetryError) {
console.log(`Failed after ${error.attempts} attempts`);
console.log('Last error:', error.lastError);
console.log('Total time:', error.totalTime);
}
}
Caching Strategy
Sophisticated caching system with automatic ETag handling and performance optimization.
// Configure caching behavior
const fyn = new Fyn({
cache: {
enabled: true, // Enable/disable caching
maxSize: 1000, // Maximum cache entries
ttl: '1h', // Cache TTL
staleWhileRevalidate: true
}
});
// Cache in action
const link = await fyn.links.get('link_123', {
cache: {
ttl: '5m', // Override default TTL
staleWhileRevalidate: true,
tags: ['link', 'user_123']
}
});
// Cache operations
await fyn.cache.invalidate('link_123'); // Single entry
await fyn.cache.invalidateTag('link'); // By tag
await fyn.cache.clear(); // Full clear
// Cache statistics
const stats = fyn.cache.getStats();
console.log({
hits: stats.hits,
misses: stats.misses,
hitRate: stats.hitRate,
size: stats.size,
avgAccessTime: stats.avgAccessTime
});
Performance Metrics
Built-in performance monitoring with detailed metrics and statistics.
// Get detailed performance metrics
const metrics = await fyn.metrics.get({
timeframe: '5m', // Last 5 minutes
resolution: '1m' // 1-minute buckets
});
// Sample metrics response
{
requests: {
total: 150,
success: 148,
failed: 2,
successRate: 98.67
},
timing: {
avg: 245.5, // ms
p95: 450.2, // 95th percentile
p99: 850.1 // 99th percentile
},
rateLimit: {
remaining: 850,
reset: 1678892400,
limit: 1000
},
cache: {
hits: 45,
misses: 15,
hitRatio: 75.0,
size: 250,
evictions: 5
},
errors: {
byType: {
network: 1,
validation: 1,
server: 0
},
topEndpoints: [
{ path: '/links', count: 1 },
{ path: '/analytics', count: 1 }
]
}
}
Type Definitions
The SDK comes with comprehensive TypeScript definitions for a great development experience:
interface FynlinkClientOptions {
apiKey: string;
cache?: {
maxSize?: number; // Maximum number of items to cache
ttl?: string; // Time to live for cached items
enabled?: boolean; // Enable/disable caching
};
retry?: {
maxRetries?: number; // Maximum number of retry attempts
initialDelay?: number; // Initial delay between retries (ms)
maxDelay?: number; // Maximum delay between retries (ms)
backoffFactor?: number; // Exponential backoff factor
};
}
interface CreateUrlOptions {
longUrl: string; // The URL to shorten
expiresIn?: string; // Expiration time (e.g., '24h', '7d')
password?: string; // Password protection
customPath?: string; // Custom short URL path
domain?: string; // Custom domain
title?: string; // URL title
description?: string; // URL description
}
interface UrlAnalytics {
clicks: number; // Total number of clicks
countries: Record<string, number>; // Clicks by country
devices: Record<string, number>; // Clicks by device
browsers: Record<string, number>; // Clicks by browser
referrers: Record<string, number>; // Clicks by referrer
timeframes: {
last24h: number; // Clicks in last 24 hours
last7d: number; // Clicks in last 7 days
last30d: number; // Clicks in last 30 days
};
}
// Strongly typed error handling
interface FynlinkError extends Error {
code: 'INVALID_URL' | 'RATE_LIMIT' | 'NETWORK_ERROR' | 'UNAUTHORIZED';
status: number;
retryAttempt?: number;
nextRetryDelay?: number;
details?: Record<string, any>;
}