npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@linktr.ee/linkapp

v0.0.48

Published

Development, build, and deployment tooling for LinkApps

Downloads

1,714

Readme

@linktr.ee/linkapp

Development, build, and deployment tooling for LinkApps - custom interactive link experiences for Linktree profiles.

Installation

npm install @linktr.ee/linkapp

Or create a new LinkApp project:

npm create @linktr.ee/linkapp@latest

Commands

Development

Start the development server with hot reloading and theme preview UI:

linkapp dev [--port 3000]

The dev server provides:

  • Live preview of all layouts (expanded, featured, carousel)
  • Theme switcher with Linktree presets
  • Settings editor for testing configurations
  • Hot module replacement

Building

Build your LinkApp for production:

linkapp build [options]

Options:

  • --sourcemap - Generate source maps for debugging
  • --profile - Enable bundle profiling
  • --compress - Generate Brotli-compressed files (30-40% smaller)

Outputs to dist/ directory with:

  • Content-hashed filenames for cache busting
  • build-manifest.json with asset versions
  • Optimized React vendor chunks for better caching

Deployment

Deploy your LinkApp to Linktree:

linkapp deploy [--qa] [--skip-confirm]

Options:

  • --qa - Deploy to QA environment instead of production
  • --skip-confirm - Skip confirmation prompt

The deployment process:

  1. Validates project structure and configuration
  2. Builds if needed (runs linkapp build)
  3. Generates manifest files from linkapp.config.ts
  4. Packs project into tarball
  5. Uploads to Linktree API
  6. Returns build ID and admin URL

Authentication

Authenticate with Linktree using OAuth device flow:

linkapp login [--qa]     # Login
linkapp logout [--qa]    # Logout

Tokens are stored in ~/.config/linkapp/auth-token.json.

Components

Add UI components from the registry:

linkapp add <component>

Example: linkapp add button

URL Testing

Test URL matching rules from your config:

linkapp test-url-match-rules <url>

Example: linkapp test-url-match-rules https://google.com/search

Exports

CLI

{
  "bin": {
    "linkapp": "bin/cli.js"
  }
}

Types

import type { AppProps, LinkAppConfig, SettingsElement } from '@linktr.ee/linkapp/types'

// Layout component props
interface MySettings {
  title: string
  color: string
}

export default function ExpandedLayout({ settings, theme }: AppProps<MySettings>) {
  return <div>{settings.title}</div>
}

SDK

import { useExpandLinkApp } from '@linktr.ee/linkapp/sdk'

// In featured layout, trigger popup/modal
function FeaturedLayout() {
  const expandLinkApp = useExpandLinkApp()

  return (
    <button onClick={() => expandLinkApp({ itemId: '123' })}>
      Expand
    </button>
  )
}

Project Structure

A LinkApp project has this structure:

my-linkapp/
├── app/
│   ├── expanded.tsx                 # Required: default layout
│   ├── featured.tsx              # Optional: featured layout
│   ├── featured-carousel.tsx     # Optional: carousel variant
│   ├── layout.tsx                # Optional: wrapper component
│   ├── globals.css               # Global styles
│   └── icon.svg                  # LinkApp icon
├── components/                    # Your components
├── public/                        # Static assets (copied to dist/)
├── linkapp.config.ts             # Configuration
├── postcss.config.mjs            # PostCSS config (Tailwind v4)
├── components.json               # Component registry config
└── package.json

Configuration

The linkapp.config.ts file defines your LinkApp:

import { defineConfig } from '@linktr.ee/linkapp/types'

export default defineConfig({
  manifest: {
    name: 'My LinkApp',
    tagline: 'A custom link experience',
    category: 'share',
    author: {
      name: 'Your Name',
      website: 'https://example.com'
    },
    supporting_links: {
      terms_of_service: 'https://example.com/terms',
      privacy_policy: 'https://example.com/privacy'
    }
  },
  settings: {
    title: 'My LinkApp Settings',
    elements: []
  }
})

Important: The manifest.name becomes your LinkApp ID (kebab-cased) and cannot be changed after first deployment.

See the Configuration Reference for all available options.

Build System

Uses Rsbuild (Rspack) for fast, optimized builds:

  • Entry Point: .linkapp/main.tsx (auto-generated)
  • Alias: @/ points to project root
  • PostCSS: Supports Tailwind CSS v4
  • Asset Prefix: ./ for S3 subdirectory deployment
  • Code Splitting: React vendor chunks separated for caching
  • Compression: Optional Brotli compression with --compress flag

Layout Components

Expanded Layout (Required)

Compact layout for profile pages:

import type { AppProps } from '@linktr.ee/linkapp/types'

interface Settings {
  title: string
}

export default function Expanded({ settings, theme, __linkUrl }: AppProps<Settings>) {
  return (
    <div style={{ color: theme.textColor }}>
      <h1>{settings.title}</h1>
      <a href={__linkUrl}>Visit Link</a>
    </div>
  )
}

Featured Layout (Optional)

Hero-style layout for featured content:

import { useExpandLinkApp } from '@linktr.ee/linkapp/sdk'
import type { AppProps } from '@linktr.ee/linkapp/types'

export default function Featured({ settings }: AppProps<Settings>) {
  const expand = useExpandLinkApp()

  return (
    <div onClick={() => expand()}>
      <h1>{settings.title}</h1>
    </div>
  )
}

The featured layout can trigger a modal that displays the expanded layout.

Theme System

LinkApps receive theme data via props:

interface Theme {
  // Legacy properties (maintained for compatibility)
  textColor: string
  backgroundColor: string
  borderRadius: number

  // Modern CSS variables (preferred)
  cssVariables: Record<string, string>
}

Apply CSS variables for theming:

/* app/globals.css */
:root {
  --color-primary: var(--theme-primary, #000);
  --color-background: var(--theme-background, #fff);
}

PostMessage API

LinkApps run in iframes and communicate with the parent window:

import { useExpandLinkApp } from '@linktr.ee/linkapp/sdk'

function MyComponent() {
  const expand = useExpandLinkApp()

  return (
    <button onClick={() => expand()}>
      Open in Modal
    </button>
  )
}

Development

Local Development

npm run build       # Compile TypeScript
npm run dev         # Watch mode
npm run test        # Run tests
npm run lint        # Lint with Biome
npm run format      # Format with Biome

Testing Locally

Link the package globally to test CLI changes:

cd packages/linkapp
npm run build
npm link

cd ../../apps/my-test-app
linkapp dev

Package Scripts

  • build - Compile TypeScript to dist/
  • dev - Watch mode compilation
  • test - Run Vitest tests
  • test:watch - Watch mode for tests
  • lint - Lint with Biome
  • format - Format with Biome
  • clean - Remove build artifacts

Key Concepts

LinkApp ID

The LinkApp ID is derived from manifest.name using kebab-case:

  • "My Cool App""my-cool-app"
  • This ID is permanent and identifies your LinkApp across deployments
  • Cannot be changed after first deployment

Layout Detection

The supports_featured_layout setting is auto-detected based on the presence of app/featured.tsx. You don't need to manually configure it.

Settings Schema

Settings are defined as an array of elements:

elements: [
  {
    type: 'text',
    id: 'title',
    label: 'Title',
    defaultValue: 'Hello'
  },
  {
    type: 'select',
    id: 'style',
    label: 'Style',
    options: ['minimal', 'bold'],
    defaultValue: 'minimal'
  },
  {
    type: 'array',
    id: 'items',
    label: 'Items',
    element: {
      type: 'text',
      id: 'name',
      label: 'Name'
    }
  }
]

Supported types: text, select, file, switch, array, number, date, color

Requirements

  • Node.js >= 18.0.0
  • npm >= 10.0.0

Related Packages

  • @linktr.ee/create-linkapp - Scaffolding tool for new projects
  • @linktr.ee/registry - Component registry

License

See LICENSE file in repository root.