Library Showcases

Stacks.js uses a suite of companion libraries, many packaged separately from the framework. Separate packaging does not guarantee zero dependencies or standalone compatibility; inspect each package manifest, runtime assumptions, and tests before adopting it outside Stacks.js.

Protocol context — This page describes companion libraries of the Stacks.js reference implementation. The capabilities map to contracts in the Stacks Protocol white paper; the specific packages and Bun tooling shown here are TypeScript/Bun-specific.

ts-collect

A Laravel-inspired collection library for JavaScript with full TypeScript support.

bun add ts-collect

Basic Usage

import { collect } from 'ts-collect'

// Create a collection
const users = collect([
  { name: 'John', age: 30, role: 'admin' },
  { name: 'Jane', age: 25, role: 'user' },
  { name: 'Bob', age: 35, role: 'user' },
])

// Chain operations fluently
const result = users
  .where('role', 'user')
  .sortBy('age')
  .pluck('name')
  .all()
// ['Jane', 'Bob']

Collection Methods

// Filtering
collect([1, 2, 3, 4, 5]).filter(n => n > 2) // [3, 4, 5]
collect(users).where('age', '>', 25)
collect(users).whereIn('role', ['admin', 'editor'])
collect(users).whereBetween('age', [20, 30])
collect(users).whereNotNull('email')
collect(users).reject(user => user.inactive)
collect(users).first(user => user.isAdmin)
collect(users).firstWhere('role', 'admin')

// Transforming
collect([1, 2, 3]).map(n => n * 2) // [2, 4, 6]
collect(users).pluck('name') // ['John', 'Jane', 'Bob']
collect(users).keyBy('id')
collect(users).groupBy('role')
collect([[1, 2], [3, 4]]).flatten() // [1, 2, 3, 4]
collect(users).mapToGroups(user => [user.role, user.name])

// Aggregation
collect([1, 2, 3]).sum() // 6
collect(users).sum('age') // 90
collect(users).avg('age') // 30
collect(users).min('age') // 25
collect(users).max('age') // 35
collect(users).count() // 3
collect(users).countBy('role') // { admin: 1, user: 2 }

// Sorting
collect([3, 1, 2]).sort() // [1, 2, 3]
collect(users).sortBy('name')
collect(users).sortByDesc('age')
collect(users).sortKeys()

// Combining
collect([1, 2]).concat([3, 4]) // [1, 2, 3, 4]
collect([1, 2]).merge([2, 3]) // [1, 2, 2, 3]
collect([1, 2, 2, 3]).unique() // [1, 2, 3]
collect(users).union(moreUsers)
collect([1, 2]).zip(['a', 'b']) // [[1, 'a'], [2, 'b']]

// Chunking
collect([1, 2, 3, 4, 5]).chunk(2) // [[1, 2], [3, 4], [5]]
collect(users).split(2)
collect(items).forPage(2, 10) // Page 2, 10 per page

// Checking
collect([1, 2, 3]).contains(2) // true
collect(users).contains('name', 'John') // true
collect([1, 2, 3]).every(n => n > 0) // true
collect([1, 2, 3]).some(n => n > 2) // true
collect([]).isEmpty() // true
collect([1]).isNotEmpty() // true

// Reducing
collect([1, 2, 3]).reduce((sum, n) => sum + n, 0) // 6
collect(users).pipe(users => users.count())
collect(users).tap(users => console.log(users.count()))

Lazy Collections

import { lazy } from 'ts-collect'

// Process large datasets efficiently
const result = lazy(hugeArray)
  .filter(item => item.active)
  .map(item => transform(item))
  .take(100)
  .all()

// Generator support
function* generateNumbers() {
  for (let i = 0; i < 1000000; i++) yield i
}

lazy(generateNumbers())
  .filter(n => n % 2 === 0)
  .take(10)
  .all()

ts-datetime

A modern, immutable date-time library with timezone support.

bun add ts-datetime

Basic Usage

import { DateTime } from 'ts-datetime'

// Create instances
const now = DateTime.now()
const date = DateTime.parse('2024-01-15')
const fromTimestamp = DateTime.fromTimestamp(1705276800)

// Fluent manipulation
const future = now
  .addDays(7)
  .addHours(3)
  .startOfDay()

// Formatting
now.format('YYYY-MM-DD') // '2024-01-15'
now.format('MMMM D, YYYY') // 'January 15, 2024'
now.toISOString() // '2024-01-15T10:30:00.000Z'
now.toRelative() // '2 hours ago'

Date Manipulation

// Adding/Subtracting
date.addYears(1)
date.addMonths(3)
date.addWeeks(2)
date.addDays(5)
date.addHours(12)
date.addMinutes(30)
date.addSeconds(45)

date.subDays(5)
date.subMonths(1)

// Start/End of periods
date.startOfDay()
date.endOfDay()
date.startOfWeek()
date.endOfWeek()
date.startOfMonth()
date.endOfMonth()
date.startOfYear()
date.endOfYear()

// Setting values
date.setYear(2025)
date.setMonth(6)
date.setDay(15)
date.setHour(14)
date.setMinute(30)

Comparisons

const date1 = DateTime.parse('2024-01-15')
const date2 = DateTime.parse('2024-01-20')

date1.isBefore(date2) // true
date1.isAfter(date2) // false
date1.isSame(date2) // false
date1.isSameDay(date2) // false
date1.isSameMonth(date2) // true

date1.isBetween('2024-01-01', '2024-01-31') // true
date1.isPast() // depends on current date
date1.isFuture() // depends on current date
date1.isToday() // false
date1.isWeekend() // false
date1.isWeekday() // true

Differences

const start = DateTime.parse('2024-01-01')
const end = DateTime.parse('2024-03-15')

start.diffInDays(end) // 74
start.diffInWeeks(end) // 10
start.diffInMonths(end) // 2
start.diffInYears(end) // 0
start.diffInHours(end) // 1776
start.diffForHumans(end) // '2 months'

Timezones

// Create in timezone
const tokyo = DateTime.now('Asia/Tokyo')
const newYork = DateTime.now('America/New_York')

// Convert timezones
tokyo.toTimezone('UTC')
tokyo.toTimezone('Europe/London')

// Get timezone info
tokyo.timezone // 'Asia/Tokyo'
tokyo.offset // '+09:00'
tokyo.offsetMinutes // 540

Formatting

const date = DateTime.parse('2024-01-15T14:30:00')

// Format tokens
date.format('YYYY') // '2024'
date.format('MM') // '01'
date.format('DD') // '15'
date.format('HH:mm') // '14:30'
date.format('dddd') // 'Monday'
date.format('MMMM') // 'January'
date.format('YYYY-MM-DD HH:mm:ss') // '2024-01-15 14:30:00'

// Relative time
date.fromNow() // '2 hours ago'
date.toNow() // 'in 2 hours'

// Localization
date.locale('de').format('MMMM D, YYYY') // '15. Januar 2024'
date.locale('ja').format('YYYY年MM月DD日') // '2024年01月15日'

rpx

A reverse proxy and local development tunnel solution.

bun add rpx

Basic Usage

import { startProxy, startTunnel } from 'rpx'

// Reverse proxy
const proxy = await startProxy({
  from: 'localhost:3000',
  to: 'app.localhost',
  https: true,
})

// Local tunnel (expose to internet)
const tunnel = await startTunnel({
  port: 3000,
  subdomain: 'my-app',
})

console.log(tunnel.url) // https://my-app.rpx.dev

SSL Certificates

// Auto-generate development certificates
const proxy = await startProxy({
  from: 'localhost:3000',
  to: 'myapp.localhost',
  https: {
    auto: true,
    trust: true, // Add to system trust store
  },
})

// Custom certificates
const proxy = await startProxy({
  from: 'localhost:3000',
  to: 'myapp.localhost',
  https: {
    cert: './certs/localhost.crt',
    key: './certs/localhost.key',
  },
})

Multiple Domains

// Route multiple domains
await startProxy({
  routes: {
    'api.localhost': 'localhost:3001',
    'app.localhost': 'localhost:3000',
    'admin.localhost': 'localhost:3002',
  },
  https: true,
})

tlsx

TLS/SSL certificate generation and management.

bun add tlsx

Generate Certificates

import { createCertificate, createCA } from 'tlsx'

// Create a Certificate Authority
const ca = await createCA({
  organization: 'My Dev CA',
  countryCode: 'US',
  state: 'California',
  locality: 'San Francisco',
  validity: 365 * 10, // 10 years
})

// Create certificate signed by CA
const cert = await createCertificate({
  ca,
  domains: ['localhost', '*.localhost', 'myapp.dev'],
  validity: 365,
})

// Save to files
await Bun.write('ca.crt', ca.certificate)
await Bun.write('cert.crt', cert.certificate)
await Bun.write('cert.key', cert.privateKey)

Trust System Store

import { trust, untrust } from 'tlsx'

// Add CA to system trust store
await trust(ca.certificate)

// Remove from trust store
await untrust(ca.certificate)

clarity

Structured logging with beautiful output.

bun add clarity

Basic Usage

import { log, createLogger } from 'clarity'

// Simple logging
log.info('Server started', { port: 3000 })
log.warning('High memory usage', { usage: '85%' })
log.error('Request failed', { error: error.message })
log.debug('Cache hit', { key: 'user:123' })

// Create named logger
const dbLog = createLogger('database')
dbLog.info('Query executed', { sql: '...', time: 45 })

Configuration

import { configure } from 'clarity'

configure({
  level: 'debug',
  format: 'pretty', // 'pretty' | 'json'
  colors: true,
  timestamp: true,
  context: {
    app: 'my-app',
    version: '1.0.0',
  },
})

Transports

import { addTransport, FileTransport, HttpTransport } from 'clarity'

// File transport
addTransport(new FileTransport({
  path: 'logs/app.log',
  rotate: 'daily',
}))

// HTTP transport (send to log service)
addTransport(new HttpTransport({
  url: 'https://logs.example.com/ingest',
  batchSize: 100,
}))

ts-mocker (Faker)

Fake data generation for testing and development.

bun add ts-mocker

Basic Usage

import { fake } from 'ts-mocker'

// Generate fake data
fake.name() // 'John Smith'
fake.email() // 'john.smith@example.com'
fake.phone() // '(555) 123-4567'
fake.address() // '123 Main St, New York, NY 10001'
fake.company() // 'Acme Corporation'
fake.paragraph() // 'Lorem ipsum...'

Available Generators

// Personal
fake.firstName() // 'John'
fake.lastName() // 'Smith'
fake.name() // 'John Smith'
fake.email() // 'john@example.com'
fake.phone() // '+1 555-123-4567'
fake.avatar() // 'https://...'
fake.username() // 'johnsmith42'
fake.password() // 'aB3$xY9z'

// Address
fake.address() // '123 Main St'
fake.city() // 'New York'
fake.state() // 'California'
fake.zipCode() // '90210'
fake.country() // 'United States'
fake.latitude() // 40.7128
fake.longitude() // -74.0060

// Business
fake.company() // 'Acme Inc.'
fake.jobTitle() // 'Software Engineer'
fake.department() // 'Engineering'

// Internet
fake.url() // 'https://example.com'
fake.domain() // 'example.com'
fake.ip() // '192.168.1.1'
fake.userAgent() // 'Mozilla/5.0...'

// Text
fake.word() // 'lorem'
fake.words(5) // 'lorem ipsum dolor sit amet'
fake.sentence() // 'Lorem ipsum dolor sit amet.'
fake.paragraph() // 'Lorem ipsum...'
fake.paragraphs(3) // '...'

// Numbers
fake.number(1, 100) // 42
fake.float(0, 1) // 0.7234
fake.boolean() // true
fake.uuid() // 'a1b2c3d4-...'

// Dates
fake.date() // Date object
fake.pastDate() // Date in the past
fake.futureDate() // Date in the future
fake.dateTime() // '2024-01-15T10:30:00Z'

// Commerce
fake.price() // 99.99
fake.productName() // 'Ergonomic Chair'
fake.color() // 'blue'
fake.currency() // 'USD'

// Images
fake.image() // 'https://picsum.photos/...'
fake.image(400, 300) // Specific dimensions
fake.avatar() // Profile image URL

Seeded Generation

import { seed, fake } from 'ts-mocker'

// Reproducible results
seed(12345)
fake.name() // Always 'John Smith' with this seed
fake.email() // Always same email

dnsx

DNS record management across providers.

bun add dnsx

Basic Usage

import { DNS } from 'dnsx'

// Configure provider
const dns = new DNS({
  provider: 'cloudflare',
  token: process.env.CLOUDFLARE_TOKEN,
  zone: 'example.com',
})

// Get records
const records = await dns.getRecords()
const aRecords = await dns.getRecords({ type: 'A' })

// Create record
await dns.createRecord({
  type: 'A',
  name: 'app',
  content: '192.168.1.1',
  ttl: 3600,
})

// Update record
await dns.updateRecord(recordId, {
  content: '192.168.1.2',
})

// Delete record
await dns.deleteRecord(recordId)

Supported Providers

// Cloudflare
new DNS({ provider: 'cloudflare', token: '...' })

// AWS Route 53
new DNS({ provider: 'route53', accessKeyId: '...', secretAccessKey: '...' })

// DigitalOcean
new DNS({ provider: 'digitalocean', token: '...' })

// Google Cloud DNS
new DNS({ provider: 'gcloud', credentials: {...} })

bunpress

Static site and documentation generator.

bun add bunpress

Configuration

// bunpress.config.ts
export default {
  title: 'My Documentation',
  description: 'Documentation for my project',
  docsDir: './docs',
  outDir: './dist',

  theme: 'vitepress',

  markdown: {
    toc: { enabled: true },
    syntaxHighlightTheme: 'github-dark',
  },

  nav: [
    { text: 'Guide', link: '/guide/' },
    { text: 'API', link: '/api/' },
  ],

  sidebar: {
    '/guide/': [
      { text: 'Introduction', link: '/guide/' },
      { text: 'Getting Started', link: '/guide/getting-started' },
    ],
  },
}

Build

bunpress build  # Build static site
bunpress dev    # Development server
bunpress serve  # Serve built site

More Libraries

LibraryDescriptionPackage
bun-reverse-proxyReverse proxy for Bunbun-reverse-proxy
localtunnelsExpose local serverslocaltunnels
bun-plugin-auto-importsAuto-import for Bunbun-plugin-auto-imports
bun-plugin-dtsxAuto-generate .d.tsbun-plugin-dtsx
bun-git-hooksGit hooks for Bunbun-git-hooks
bun-spreadsheetsExcel/CSV handlingbun-spreadsheets
ts-spreadsheetsTypeScript spreadsheetsts-spreadsheets
dtsxTypeScript to .d.tsdtsx
vite-plugin-stacksVite integrationvite-plugin-stacks

Using Libraries Standalone

Some companion libraries can be adopted outside Stacks.js. Verify the exact package version, dependencies, exports, and runtime support first:

// In any project, not just Stacks.js
import { collect } from 'ts-collect'
import { DateTime } from 'ts-datetime'
import { fake } from 'ts-mocker'
import { log } from 'clarity'

// Use them anywhere
const users = collect(data).where('active', true).sortBy('name')
const tomorrow = DateTime.now().addDays(1)
const testUser = { name: fake.name(), email: fake.email() }
log.info('Processing complete', { count: users.count() })