npm package: @linktr.ee/linkapp
Description: Development, build, and deployment tooling for LinkApps
Latest version: 0.0.56

# @linktr.ee/linkapp

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

## Installation

```bash
npm install @linktr.ee/linkapp
```

Or create a new LinkApp project:

```bash
npm create @linktr.ee/linkapp@latest
```

## Commands

### Development

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

```bash
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:

```bash
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:

```bash
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:

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

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

### Components

Add UI components from the registry:

```bash
linkapp add <component>
```

Example: `linkapp add button`

### URL Testing

Test URL matching rules from your config:

```bash
linkapp test-url-match-rules <url>
```

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

## Exports

### CLI

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

### Types

```typescript
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

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

// In featured layout, expand to overlay
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:

```typescript
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](https://linktree.mintlify.app/essentials/configuration) 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:

```typescript
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:

```typescript
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:

```typescript
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:

```css
/* 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:

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

function MyComponent() {
  const expand = useExpandLinkApp()

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

## Development

### Local Development

```bash
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:

```bash
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:

```typescript
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.