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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lenne.tech/nuxt-extensions

v1.5.4

Published

Reusable Nuxt 4 composables, components, and Better-Auth integration for lenne.tech projects

Downloads

1,123

Readme

@lenne.tech/nuxt-extensions

npm version npm downloads License Nuxt

Reusable Nuxt 4 composables, components, and Better-Auth integration for lenne.tech projects.

Quick Start

Want to start a new fullstack project?

Use the nuxt-base-starter (Frontend) together with the nest-server-starter (Backend) to initialize a complete fullstack project with this package pre-configured.

Both starters are designed to work seamlessly together and serve as reference implementations showing how to use all features in a real application.

Quick initialization:

npx @lenne.tech/cli fullstack init my-project

Installation

npm install @lenne.tech/nuxt-extensions better-auth
# Optional: For passkey support
npm install @better-auth/passkey
# Optional: For TUS file uploads
npm install tus-js-client

Features

  • Better-Auth Integration - Login, 2FA, Passkey/WebAuthn support
  • Cookie/JWT Dual-Mode - Automatic fallback from cookies to JWT
  • TUS File Upload - Resumable uploads with pause/resume
  • Transition Components - Ready-to-use Vue transition wrappers
  • i18n Support - English and German translations (works without i18n too)
  • Auto-imports - All composables and components are auto-imported

Environment Variables

| Variable | Context | Description | |----------|---------|-------------| | NUXT_PUBLIC_API_URL | Client + Server | Public API URL. Primary way to configure the API endpoint. Used for client-side requests and as SSR fallback. | | NUXT_API_URL | Server only | Internal API URL for SSR requests. Use when the backend has a private network address that should not be exposed to the client. | | NUXT_PUBLIC_API_PROXY | Client | Set to true to enable the Vite dev proxy. Routes client requests through /api/ for same-origin cookies. Only for local development. |

How URL Resolution Works

All environment variables are resolved at runtime (not build time). This means you can build a Docker image once and deploy it to different environments by changing env vars — no rebuild needed.

SSR fallback chain: NUXT_API_URLNUXT_PUBLIC_API_URLauth.baseURL (from nuxt.config.ts) → http://localhost:3000

Client fallback chain (no proxy): NUXT_PUBLIC_API_URLauth.baseURL (from nuxt.config.ts) → http://localhost:3000

Client with proxy (NUXT_PUBLIC_API_PROXY=true): All requests go to /api/{path} — the Vite dev proxy forwards them to the backend.

Security: NUXT_API_URL is never exposed to the client bundle. It stays in runtimeConfig.apiUrl (server only). This is important when using internal network addresses like http://api.svc.cluster.local.

Deployment Scenarios

Local development — Frontend and backend on different ports, proxy ensures same-origin cookies:

NUXT_PUBLIC_API_URL=http://localhost:3000
NUXT_PUBLIC_API_PROXY=true

Production (simple) — Backend reachable via public URL from both SSR and client:

NUXT_PUBLIC_API_URL=https://api.example.com

Production (internal network) — SSR uses fast internal route, client uses public URL:

NUXT_PUBLIC_API_URL=https://api.example.com
NUXT_API_URL=http://api-internal:3000

Legacy (nuxt.config.ts only) — Works but env vars are preferred for runtime flexibility:

// nuxt.config.ts
ltExtensions: {
  auth: {
    baseURL: 'https://api.example.com',
  },
}

Configuration

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@lenne.tech/nuxt-extensions'],

  ltExtensions: {
    // Auth configuration
    auth: {
      enabled: true,                // Enable auth features
      baseURL: '',                  // API base URL (empty = use env vars)
      basePath: '/iam',             // Better-Auth endpoint prefix
      loginPath: '/auth/login',     // Login redirect path
      twoFactorRedirectPath: '/auth/2fa',  // 2FA redirect path

      // Plugin options
      enableAdmin: true,            // Admin plugin
      enableTwoFactor: true,        // 2FA plugin
      enablePasskey: true,          // Passkey/WebAuthn plugin

      // Interceptor options
      interceptor: {
        enabled: true,              // 401 auto-handler
        publicPaths: ['/auth/login', '/auth/register'],
      },

      // System setup (first admin user creation)
      systemSetup: {
        enabled: false,             // Enable setup flow
        setupPath: '/auth/setup',   // Setup page path
      },
    },

    // Error translation configuration
    errorTranslation: {
      enabled: true,                // Translate backend error codes
      defaultLocale: 'de',          // Fallback locale
    },

    // TUS upload configuration
    tus: {
      defaultEndpoint: '/files/upload',
      defaultChunkSize: 5 * 1024 * 1024,  // 5MB
    },

    // i18n configuration (optional)
    i18n: {
      autoMerge: true,              // Auto-merge locales with @nuxtjs/i18n
    },
  },
});

Usage

Authentication

<script setup>
// Auth composable (auto-imported)
const {
  user,
  isAuthenticated,
  isLoading,
  signIn,
  signOut,
  authenticateWithPasskey,
  registerPasskey,
  twoFactor,
} = useLtAuth();

// Login with email/password
async function handleLogin(email: string, password: string) {
  const result = await signIn.email({ email, password });
  if (result.requiresTwoFactor) {
    navigateTo('/auth/2fa');
  }
}

// Passkey login
async function handlePasskeyLogin() {
  const result = await authenticateWithPasskey();
  if (result.success) {
    navigateTo('/dashboard');
  }
}
</script>

<template>
  <div v-if="isAuthenticated">
    Welcome, {{ user?.name }}!
    <button @click="signOut()">Logout</button>
  </div>
</template>

Custom Better Auth Plugins

You can extend the auth client with additional Better Auth plugins:

Option 1: Plugin Registration (recommended)

Create a Nuxt plugin to register plugins before the auth client is initialized:

// plugins/auth-plugins.client.ts
import { registerLtAuthPlugins } from '@lenne.tech/nuxt-extensions/lib';
import { organizationClient, magicLinkClient } from 'better-auth/client/plugins';

export default defineNuxtPlugin(() => {
  registerLtAuthPlugins([
    organizationClient(),
    magicLinkClient(),
  ]);
});

Note: In Vue components, registerLtAuthPlugins is auto-imported. In .ts files (like Nuxt plugins), import from @lenne.tech/nuxt-extensions/lib.

Option 2: Direct Factory Usage

For full control, create the auth client directly with your plugins:

import { createLtAuthClient } from '@lenne.tech/nuxt-extensions/lib';
import { organizationClient } from 'better-auth/client/plugins';

const authClient = createLtAuthClient({
  plugins: [organizationClient()],
});

// Use authClient.organization.* methods

Available Better Auth Plugins:

  • organizationClient - Organization/team management
  • magicLinkClient - Passwordless email login
  • oneTapClient - Google One Tap login
  • anonymousClient - Anonymous/guest sessions
  • See Better Auth Plugins for full list

TUS File Upload

<script setup>
const {
  addFiles,
  uploads,
  totalProgress,
  isUploading,
  pauseUpload,
  resumeUpload,
  cancelUpload,
} = useLtTusUpload({
  endpoint: '/api/files/upload',
  onSuccess: (item) => console.log('Uploaded:', item.url),
  onError: (item, error) => console.error('Failed:', error),
});

const { formatFileSize } = useLtFile();

function handleFileSelect(event: Event) {
  const input = event.target as HTMLInputElement;
  if (input.files) {
    addFiles(Array.from(input.files));
  }
}
</script>

<template>
  <div>
    <input type="file" multiple @change="handleFileSelect" />

    <div v-for="upload in uploads" :key="upload.id">
      <span>{{ upload.file.name }}</span>
      <span>{{ formatFileSize(upload.progress.bytesUploaded) }} / {{ formatFileSize(upload.progress.bytesTotal) }}</span>
      <span>{{ upload.progress.percentage }}%</span>

      <button v-if="upload.status === 'uploading'" @click="pauseUpload(upload.id)">
        Pause
      </button>
      <button v-if="upload.status === 'paused'" @click="resumeUpload(upload.id)">
        Resume
      </button>
    </div>

    <div v-if="isUploading">
      Total Progress: {{ totalProgress.percentage }}%
    </div>
  </div>
</template>

Transition Components

<template>
  <!-- Fade transition -->
  <LtTransitionFade>
    <div v-if="show">Content with fade</div>
  </LtTransitionFade>

  <!-- Fade with scale -->
  <LtTransitionFadeScale :start-duration="200" :leave-duration="150">
    <div v-if="show">Content with fade and scale</div>
  </LtTransitionFadeScale>

  <!-- Slide from right -->
  <LtTransitionSlide>
    <div v-if="show">Content slides from right</div>
  </LtTransitionSlide>

  <!-- Slide from bottom -->
  <LtTransitionSlideBottom>
    <div v-if="show">Content slides from bottom</div>
  </LtTransitionSlideBottom>

  <!-- Slide from left -->
  <LtTransitionSlideRevert>
    <div v-if="show">Content slides from left</div>
  </LtTransitionSlideRevert>
</template>

Web Share API

<script setup>
const { share } = useLtShare();

async function handleShare() {
  await share('Check this out!', 'Amazing content');
  // Uses native share on mobile, clipboard fallback on desktop
}
</script>

Utilities

// Tailwind TypeScript helper
const buttonClasses = tw`bg-blue-500 hover:bg-blue-700 text-white`;

// Crypto utilities (for WebAuthn)
const hash = await ltSha256('password');
const base64 = ltArrayBufferToBase64Url(buffer);
const uint8 = ltBase64UrlToUint8Array(base64String);

i18n Support

The package works with or without @nuxtjs/i18n:

| Setup | Language | Text Source | |-------|----------|-------------| | Without i18n | German | Hardcoded fallback texts | | With i18n, Locale: de | German | From de.json | | With i18n, Locale: en | English | From en.json | | With i18n, other Locale | English | Fallback to en.json |

API Reference

Composables

| Composable | Description | |------------|-------------| | useLtAuth() | Better-Auth integration with session, passkey, 2FA | | useLtAuthClient() | Direct access to the Better-Auth client singleton | | useLtErrorTranslation() | Translate backend error codes to user-friendly messages | | useLtTusUpload() | TUS protocol file uploads with pause/resume | | useLtFile() | File utilities (size formatting, URLs) | | useLtShare() | Web Share API with clipboard fallback | | useSystemSetup() | System setup flow for initial admin user creation |

Components

| Component | Description | |-----------|-------------| | <LtTransitionFade> | Opacity fade transition | | <LtTransitionFadeScale> | Fade with scale transition | | <LtTransitionSlide> | Slide from right transition | | <LtTransitionSlideBottom> | Slide from bottom transition | | <LtTransitionSlideRevert> | Slide from left transition |

Utilities

| Utility | Description | |---------|-------------| | tw | Tailwind TypeScript helper | | ltSha256() | SHA256 hash function | | ltArrayBufferToBase64Url() | ArrayBuffer to base64url conversion | | ltBase64UrlToUint8Array() | Base64url to Uint8Array conversion | | createLtAuthClient() | Auth client factory for custom configuration | | registerLtAuthPlugins() | Register custom Better Auth plugins |

Related Projects

| Project | Description | |---------|-------------| | nuxt-base-starter | Frontend starter template (uses this package) | | nest-server-starter | Backend starter template (Better-Auth backend) | | @lenne.tech/nest-server | Backend framework with Better-Auth support | | @lenne.tech/cli | CLI tool for fullstack project initialization |

Fullstack Architecture

+-------------------------------------------------------------+
|                     Your Fullstack App                       |
+-----------------------------+-------------------------------+
|         Frontend            |           Backend              |
|    (nuxt-base-starter)      |    (nest-server-starter)       |
+-----------------------------+-------------------------------+
|  @lenne.tech/nuxt-extensions|   @lenne.tech/nest-server     |
|  - useLtAuth()              |   - CoreBetterAuthModule      |
|  - useLtTusUpload()         |   - CoreFileModule            |
|  - <LtTransition*>          |   - CoreUserModule            |
+-----------------------------+-------------------------------+

Development

# Install dependencies
npm install

# Generate type stubs
npm run dev:prepare

# Develop with playground
npm run dev

# Build the module
npm run build

# Run tests
npm run test

License

MIT