Documentation
Node.js
SvelteKit

SvelteKit is the full-stack Svelte framework — SSR, form actions, API routes, and more. Tunnel it to test OAuth, webhooks, and share your work without deploying.

Quick Start

npm install -g mekong-cli
mekong auth YOUR_TOKEN
# Terminal 1
npm run dev        # SvelteKit starts on http://localhost:5173
 
# Terminal 2
mekong 5173
# → https://happy-tiger-a1b2c3d4.mekongtunnel.dev

Or together:

npx concurrently "vite dev" "mekong 5173"

package.json Scripts

{
  "scripts": {
    "dev": "vite dev",
    "tunnel": "mekong 5173",
    "dev:share": "concurrently \"vite dev\" \"mekong 5173\""
  }
}

Custom Port

// vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite'
import { defineConfig } from 'vite'
 
export default defineConfig({
  plugins: [sveltekit()],
  server: { port: 4000 },
})
mekong 4000

Auto-Tunnel Vite Plugin

// vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite'
import { defineConfig } from 'vite'
import { createTunnel } from 'mekong-cli'
 
export default defineConfig({
  plugins: [
    sveltekit(),
    {
      name: 'mekong-tunnel',
      configureServer(server) {
        server.httpServer?.once('listening', async () => {
          const port = (server.httpServer?.address() as any)?.port ?? 5173
          const tunnel = await createTunnel({ port })
          setTimeout(() => {
            console.log(`\n  ➜  Tunnel:  \x1b[36m${tunnel.url}\x1b[0m\n`)
          }, 100)
        })
      },
    },
  ],
})

Environment Variables

# .env
PUBLIC_APP_URL=https://happy-tiger-a1b2c3d4.mekongtunnel.dev
PRIVATE_STRIPE_SECRET=sk_test_...
// In Svelte components (public vars)
import { PUBLIC_APP_URL } from '$env/static/public'
 
// In server files (private vars)
import { PRIVATE_STRIPE_SECRET } from '$env/static/private'

Form Actions Via Tunnel

SvelteKit form actions work seamlessly through the tunnel:

<!-- src/routes/contact/+page.svelte -->
<script lang="ts">
  import type { ActionData } from './$types'
  export let form: ActionData
</script>
 
<form method="POST">
  <input name="email" type="email" required />
  <button type="submit">Subscribe</button>
  {#if form?.success}
    <p>Thank you!</p>
  {/if}
</form>
// src/routes/contact/+page.server.ts
import type { Actions } from './$types'
 
export const actions: Actions = {
  default: async ({ request }) => {
    const data = await request.formData()
    const email = data.get('email')
    // process...
    return { success: true }
  },
}

API Routes (Endpoints)

// src/routes/api/webhook/+server.ts
import type { RequestHandler } from './$types'
 
export const POST: RequestHandler = async ({ request }) => {
  const body = await request.json()
  console.log('Webhook:', body)
  return new Response(JSON.stringify({ ok: true }), {
    headers: { 'Content-Type': 'application/json' },
  })
}
mekong 5173
# POST https://your-tunnel.mekongtunnel.dev/api/webhook

OAuth with SvelteKit

Using @auth/sveltekit:

AUTH_SECRET=your-secret
GITHUB_ID=...
GITHUB_SECRET=...
AUTH_URL=https://happy-tiger-a1b2c3d4.mekongtunnel.dev
// src/auth.ts
import { SvelteKitAuth } from '@auth/sveltekit'
import GitHub from '@auth/sveltekit/providers/github'
 
export const { handle, signIn, signOut } = SvelteKitAuth({
  providers: [GitHub],
})

Add to your GitHub OAuth app:

https://happy-tiger-a1b2c3d4.mekongtunnel.dev/auth/callback/github

CORS for API Routes

// src/hooks.server.ts
import type { Handle } from '@sveltejs/kit'
 
export const handle: Handle = async ({ event, resolve }) => {
  const response = await resolve(event)
  response.headers.set('Access-Control-Allow-Origin', '*')
  return response
}

Tips

  • SvelteKit's live reload and HMR work locally; the tunnel shows the rendered output
  • +page.server.ts and +server.ts files run server-side — all requests hit your local machine
  • WebSocket support (+server.ts with upgrade handler) works through the MekongTunnel proxy