# code_chunks_vec_auxiliary

value00: AGENTS.md
value01:
## Error Handling

```javascript
try {
  const result = await api.fetchData();
  toastSuccess('Operation successful');
} catch (err) {
  const message = err.message || 'An unexpected error occurred';
  toastError(message);
  console.error('Operation failed:', err);
}
```

## Styling (DaisyUI + Tailwind)

- **Components**: `btn`, `card`, `alert`, `input`, `navbar`, `modal`, `dropdown`, `menu`
- **Colors**: `primary` (emerald), `secondary` (dark blue), `accent` (royal blue)
- **Sizes**: `btn-sm`, `input-sm`, `select-sm` for compact forms
- **Custom**: `.compact-y`, `.compact-p`, `.compact-input`, `.compact-btn`, `.compact-card`

### Input with Icons (DaisyUI Pattern)

**Correct way** - Use DaisyUI's built-in input with icon support:


value00: AGENTS.md
value01:
**No ESLint/Prettier configured yet.** When adding: configure in `vite.config.js` or separate config files.

## Code Style

- **ES Modules**: `import`/`export` (type: "module")
- **Semicolons**: Required
- **Quotes**: Single quotes
- **Indentation**: 2 spaces
- **Trailing commas**: In multi-line objects/arrays
- **JSDoc**: Document all exported functions with `@param` and `@returns`

### Imports Order

1. Svelte (`svelte`, `$app/*`)
2. `$lib/*` (stores, api, components, utils)
3. External libraries (`lucide-svelte`)
4. Relative imports (minimize, prefer `$lib`)


value00: AGENTS.md
value01:
# AGENTS.md - Coding Guidelines for CLQMS Frontend

SvelteKit frontend for Clinical Laboratory Quality Management System. Uses Svelte 5 runes, TailwindCSS 4, DaisyUI, and Lucide icons.

## Commands

```bash
# Development
pnpm run dev        # Start development server
pnpm run build      # Production build (outputs to build/)
pnpm run preview    # Preview production build
pnpm run prepare    # Sync SvelteKit (runs on install)

# Package management
pnpm install        # Install dependencies (use pnpm, not npm/yarn)

# Testing (not configured yet - add when needed)
# vitest run src/path/to/test.js  # Run single test
# vitest                          # Run tests in watch mode
# npx playwright test             # E2E tests
```


value00: AGENTS.md
value01:
### Form with Validation

```javascript
let formLoading = $state(false);
let formError = $state('');
let formData = $state({ username: '', password: '' });

function validateForm() {
  formError = '';
  if (!formData.username.trim()) {
    formError = 'Username is required';
    return false;
  }
  return true;
}

async function handleSubmit() {
  if (!validateForm()) return;
  formLoading = true;
  try {
    await api.submit(formData);
    toastSuccess('Success');
  } catch (err) {
    formError = err.message;
  } finally {
    formLoading = false;
  }
}
```


value00: AGENTS.md
value01:
## Project Structure

```
src/
  lib/
    api/          # API clients per feature
    stores/       # Svelte stores (auth, config, valuesets)
    components/   # Reusable components (Modal, DataTable, Sidebar)
    utils/        # Utilities (toast, helpers)
    types/        # TypeScript type definitions
  routes/         # SvelteKit routes
    (app)/        # Route groups (protected)
      dashboard/
      patients/
      master-data/
    login/        # Public routes
```

## Authentication

- Check `$auth.isAuthenticated` in layout `onMount`
- Redirect to `/login` if unauthenticated using `goto('/login')`
- API client auto-redirects on 401


value00: AGENTS.md
value01:
## TypeScript Types

```typescript
// src/lib/types/ - Type definitions
export type TestType = 'TEST' | 'PARAM' | 'CALC' | 'GROUP' | 'TITLE';

export interface TestSummary {
  TestSiteID: number;
  TestSiteCode: string;
  TestSiteName: string;
  TestType: TestType;
}

// Use JSDoc for type imports in JS files
/** @typedef {import('$lib/types/test.types.js').TestSummary} TestSummary */
```


value00: AGENTS.md
value01:
## LocalStorage

- Only access in browser: check `browser` from `$app/environment`
- Use descriptive keys: `clqms_username`, `clqms_remember`, `auth_token`

## Important Notes

- Uses Svelte 5: `$props`, `$state`, `$derived`, `$effect`, `$bindable`
- Static adapter configured for static export
- Runtime config allows API URL changes without rebuild
- API proxy: `/api` → `http://localhost:8000` (dev)
- API Docs: https://clqms01-api.services-summit.my.id/swagger/


value00: AGENTS.md
value01:
## Store Patterns

```javascript
import { writable } from 'svelte/store';
import { browser } from '$app/environment';

function createStore() {
  const getInitialState = () => {
    if (!browser) return { data: null };
    return JSON.parse(localStorage.getItem('key'));
  };

  const { subscribe, set, update } = writable(getInitialState());

  return {
    subscribe,
    setData: (data) => {
      if (browser) localStorage.setItem('key', JSON.stringify(data));
      set({ data });
    }
  };
}
```


value00: AGENTS.md
value01:
## Svelte 5 Component Structure

```svelte
<script>
  // 1. Imports
  import { onMount } from 'svelte';
  import { goto } from '$app/navigation';
  import { auth } from '$lib/stores/auth.js';
  import { User } from 'lucide-svelte';

  // 2. Props with $bindable
  let { open = $bindable(false), title = '', children, footer } = $props();

  // 3. State
  let loading = $state(false);
  let formData = $state({ name: '' });

  // 4. Derived
  let isValid = $derived(formData.name.length > 0);

  // 5. Effects
  $effect(() => { /* side effects */ });

  // 6. Handlers
  function handleSubmit() { /* impl */ }
</script>
```


value00: AGENTS.md
value01:
## API Patterns

```javascript
// src/lib/api/client.js - Use these helpers
import { get, post, put, patch, del } from '$lib/api/client.js';

// Feature endpoints (with JSDoc)
/** @param {Object} params - Query parameters */
export async function fetchItems(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/items?${query}` : '/api/items');
}

export async function createItem(data) {
  return post('/api/items', data);
}

export async function updateItem(id, data) {
  return patch(`/api/items/${id}`, data);
}

export async function deleteItem(id) {
  return del(`/api/items/${id}`);
}
```


value00: AGENTS.md
value01:
### Input with Icons (DaisyUI Pattern)

**Correct way** - Use DaisyUI's built-in input with icon support:

```svelte
<!-- WRONG: Absolute positioning (icons may not render) -->
<div class="relative">
  <span class="absolute left-3 top-1/2 -translate-y-1/2">
    <User class="w-4 h-4" />
  </span>
  <input class="input input-sm input-bordered pl-9" />
</div>

<!-- CORRECT: DaisyUI input with flex layout -->
<label class="input input-sm input-bordered flex items-center gap-2 w-full focus-within:input-primary">
  <User class="w-4 h-4 text-gray-400" />
  <input
    type="text"
    class="grow bg-transparent outline-none"
    placeholder="Enter value..."
    bind:value={someValue}
  />
</label>
```

**Key points:**


value00: AGENTS.md
value01:
## Component Patterns

### Modal with Snippets

```svelte
<Modal bind:open={showModal} title="Edit Item" size="lg">
  {#snippet children()}
    <form onsubmit={handleSubmit}>
      <input class="input input-bordered" bind:value={formData.name} />
    </form>
  {/snippet}
  {#snippet footer()}
    <button class="btn btn-ghost" onclick={() => showModal = false}>Cancel</button>
    <button class="btn btn-primary" onclick={handleSubmit}>Save</button>
  {/snippet}
</Modal>
```


value00: AGENTS.md
value01:
**Key points:**
- Use `<label>` element as the input container with `input input-bordered` classes
- Add `flex items-center gap-2` for layout
- Icon is a **sibling** of the input, not absolutely positioned
- Input uses `class="grow bg-transparent outline-none"` to fill space
- Use `focus-within:input-primary` for focus state on the container
- Always add `text-gray-400` or similar color to the icon for visibility


value00: AGENTS.md
value01:
## Naming Conventions

- **Components**: PascalCase (`LoginForm.svelte`, `PatientFormModal.svelte`)
- **Files/Routes**: lowercase with hyphens (`+page.svelte`, `user-profile/`)
- **Variables**: camelCase (`isLoading`, `userName`)
- **Constants**: UPPER_SNAKE_CASE (`API_URL`, `STORAGE_KEY`)
- **Stores**: camelCase, descriptive (`auth`, `config`, `userStore`)
- **Event handlers**: prefix with `handle` (`handleSubmit`, `handleClick`)
- **Form state**: `formLoading`, `formError`, `deleteConfirmOpen`


value00: build.sh
value01:
#!/bin/bash
# Build script for different environments

# Usage: ./build.sh [dev|prod]

ENV=${1:-dev}

case $ENV in
  dev)
    echo "Building for development..."
    cp static/config.json.dev static/config.json 2>/dev/null || echo "Using env variable VITE_API_URL"
    vite build
    ;;
  prod)
    echo "Building for production..."
    # Production uses env variable, no config.json needed
    rm -f static/config.json
    vite build
    ;;
  *)
    echo "Usage: ./build.sh [dev|prod]"
    exit 1
    ;;
esac


value00: svelte.config.js
value01:
import adapter from '@sveltejs/adapter-static';

/** @type {import('@sveltejs/kit').Config} */
const config = {
	kit: {
		adapter: adapter({
			pages: 'build',
			assets: 'build',
			fallback: 'index.html',
			precompress: false,
			strict: true
		})
	}
};

export default config;


value00: cookies.txt
value01:
# Netscape HTTP Cookie File
# https://curl.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

#HttpOnly_localhost	FALSE	/	FALSE	1773480246	token	eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOiIxIiwicm9sZWlkIjoiMSIsInVzZXJuYW1lIjoibGlzZnNlIiwiZXhwIjoxNzczNDgwMjQ2fQ.EvHSR_Gp86vlK3swjVU8KNv2EjWgwnSUhkeZM3_4Rhs


value00: vite.config.js
value01:
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
	plugins: [tailwindcss(), sveltekit()],
	server: {
		proxy: {
			'/api': {
				target: 'http://localhost:8000',
				changeOrigin: true
			}
		}
	}
});


value00: TODO.md
value01:
# TODO

- Investigate why calculated tests in `ResultEntryModal.svelte` are failing to run: confirm formula loading (FormulaCode vs testdefcal), member detection, and local compute validation rules.
- Support `{CODE}` tokens and backend formula formats in the temporary `computeLocally` logic, then wire refresh button to compute the target calc directly.


value00: src/lib/api/auth.js
value01:
import { post, get } from './client.js';

/**
 * Authentication API endpoints
 */

/**
 * Login user
 * @param {string} email
 * @param {string} password
 * @returns {Promise<{token: string, user: Object}>}
 */
export async function login(username, password) {
  return post('/api/auth/login', { username, password });
}

/**
 * Logout user (client-side only, server may also invalidate token)
 * @returns {Promise<void>}
 */


value00: src/lib/api/auth.js
value01:
/**
 * Logout user (client-side only, server may also invalidate token)
 * @returns {Promise<void>}
 */
export async function logout() {
  // Optionally notify server to invalidate token
  try {
    await post('/api/auth/logout', {});
  } catch (error) {
    // Ignore server errors on logout
    console.log('Server logout error (ignored):', error);
  }
}

/**
 * Get current user profile
 * @returns {Promise<Object>}
 */
export async function getCurrentUser() {
  return get('/api/auth/check');
}


value00: src/lib/api/calculator.js
value01:
import { post } from './client.js';

/**
 * Evaluate a configured calculation for a test site by forwarding the captured variables.
 * @param {number} testSiteId - Identifier of the test site (TestSiteID) whose calculation definition should be used.
 * @param {Record<string, number|string>} [variables={}] - Input values required by the configured formula.
 * @returns {Promise<any>} API response from `/api/calc/testsite/{testSiteId}`.
 */
export async function calculateByTestSite(testSiteId, variables = {}) {
  return post(`/api/calc/testsite/${testSiteId}`, variables);
}


value00: src/lib/api/client.js
value01:
/**
 * GET request helper
 * @param {string} endpoint
 * @param {Object} options
 */
export function get(endpoint, options = {}) {
  return apiClient(endpoint, { ...options, method: 'GET' });
}

/**
 * POST request helper
 * @param {string} endpoint
 * @param {Object} body
 * @param {Object} options
 */
export function post(endpoint, body, options = {}) {
  return apiClient(endpoint, {
    ...options,
    method: 'POST',
    body: JSON.stringify(body),
  });
}

/**
 * PUT request helper
 * @param {string} endpoint
 * @param {Object} body
 * @param {Object} options
 */


value00: src/lib/api/client.js
value01:
function getApiUrl() {
  const runtimeUrl = config.getApiUrl();
  return runtimeUrl || import.meta.env.VITE_API_URL || '';
}

/**
 * Base API client with cookie-based authentication
 * @param {string} endpoint - API endpoint (without base URL)
 * @param {Object} options - Fetch options
 * @returns {Promise<any>} - JSON response
 */
export async function apiClient(endpoint, options = {}) {
  // Build headers
  const headers = {
    'Content-Type': 'application/json',
    ...options.headers,
  };

  // Build full URL using runtime config
  const url = `${getApiUrl()}${endpoint}`;

  try {
    const response = await fetch(url, {
      ...options,
      headers,
      credentials: 'include',
    });


value00: src/lib/api/client.js
value01:
import { goto } from '$app/navigation';
import { auth } from '$lib/stores/auth.js';
import { config } from '$lib/stores/config.js';

/**
 * Get the API URL from runtime config
 * Falls back to build-time env var if runtime config not available
 * @returns {string}
 */
function getApiUrl() {
  const runtimeUrl = config.getApiUrl();
  return runtimeUrl || import.meta.env.VITE_API_URL || '';
}


value00: src/lib/api/client.js
value01:
/**
 * PUT request helper
 * @param {string} endpoint
 * @param {Object} body
 * @param {Object} options
 */
export function put(endpoint, body, options = {}) {
  return apiClient(endpoint, {
    ...options,
    method: 'PUT',
    body: JSON.stringify(body),
  });
}

/**
 * PATCH request helper
 * @param {string} endpoint
 * @param {Object} body
 * @param {Object} options
 */
export function patch(endpoint, body, options = {}) {
  return apiClient(endpoint, {
    ...options,
    method: 'PATCH',
    body: JSON.stringify(body),
  });
}

/**
 * DELETE request helper
 * @param {string} endpoint
 * @param {Object} options
 */
export function del(endpoint, options = {}) {
  return apiClient(endpoint, { ...options, method: 'DELETE' });
}


value00: src/lib/api/client.js
value01:
    const response = await fetch(url, {
      ...options,
      headers,
      credentials: 'include',
    });

    // Handle 401 Unauthorized
    if (response.status === 401) {
      auth.logout();
      goto('/login');
      throw new Error('Unauthorized');
    }


value00: src/lib/api/client.js
value01:
    if (response.status === 401) {
      auth.logout();
      goto('/login');
      throw new Error('Unauthorized');
    }

    // Handle other errors
    if (!response.ok) {
      const error = await response.json().catch(() => ({ message: 'An error occurred' }));
      // Create error object with full response data for field-specific errors
      const err = new Error(error.message || `HTTP error! status: ${response.status}`);
      err.status = response.status;
      if (error.messages) {
        err.messages = error.messages;
      }
      throw err;
    }

    // Parse JSON response
    return await response.json();
  } catch (error) {
    console.error('API Error:', error);
    throw error;
  }
}


value00: src/lib/api/contacts.js
value01:
import { get, post, patch, del } from './client.js';

export async function fetchContacts(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/contact?${query}` : '/api/contact');
}

export async function fetchContact(id) {
  return get(`/api/contact/${id}`);
}

export async function createContact(data) {
  return post('/api/contact', data);
}

export async function updateContact(id, data) {
  return patch(`/api/contact/${id}`, data);
}

export async function deleteContact(id) {
  return del('/api/contact', { body: JSON.stringify({ ContactID: id }) });
}


value00: src/lib/api/containers.js
value01:
import { get, post, patch, del } from './client.js';

export async function fetchContainers(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/specimen/container?${query}` : '/api/specimen/container');
}

export async function fetchContainer(id) {
  return get(`/api/specimen/container/${id}`);
}

export async function createContainer(data) {
  const payload = {
    ConCode: data.ConCode,
    ConName: data.ConName,
    ConDesc: data.ConDesc,
    ConClass: data.ConClass,
    Additive: data.Additive,
    Color: data.Color,
  };
  return post('/api/specimen/container', payload);
}


value00: src/lib/api/containers.js
value01:
export async function updateContainer(id, data) {
  const payload = {
    ConCode: data.ConCode,
    ConName: data.ConName,
    ConDesc: data.ConDesc,
    ConClass: data.ConClass,
    Additive: data.Additive,
    Color: data.Color,
  };
  return patch(`/api/specimen/container/${id}`, payload);
}

export async function deleteContainer(id) {
  return del('/api/specimen/container', { body: JSON.stringify({ ConDefID: id }) });
}


value00: src/lib/api/counters.js
value01:
import { get, post, patch, del } from './client.js';

export async function fetchCounters(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/counter?${query}` : '/api/counter');
}

export async function fetchCounter(id) {
  return get(`/api/counter/${id}`);
}

export async function createCounter(data) {
  return post('/api/counter', data);
}

export async function updateCounter(id, data) {
  return patch(`/api/counter/${id}`, data);
}

export async function deleteCounter(id) {
  return del('/api/counter', { body: JSON.stringify({ CounterID: id }) });
}


value00: src/lib/api/equipment.js
value01:
/**
 * Update existing equipment
 * @param {Object} data - Equipment data
 * @param {number} data.EID - Equipment ID (required)
 * @param {string} [data.IEID] - Internal Equipment ID
 * @param {number} [data.DepartmentID] - Department ID
 * @param {number} [data.Enable] - Enable status 0 or 1
 * @param {string} [data.EquipmentRole] - Equipment role code
 * @param {string} [data.InstrumentID] - Instrument identifier
 * @param {string} [data.InstrumentName] - Instrument display name
 * @param {number} [data.WorkstationID] - Workstation ID
 * @returns {Promise<Object>} Updated equipment ID
 */


value00: src/lib/api/equipment.js
value01:
export async function updateEquipment(id, data) {
  const payload = {
    IEID: data.IEID,
    DepartmentID: data.DepartmentID,
    Enable: data.Enable,
    EquipmentRole: data.EquipmentRole,
    InstrumentID: data.InstrumentID || null,
    InstrumentName: data.InstrumentName || null,
    WorkstationID: data.WorkstationID || null,
  };
  return patch(`/api/equipmentlist/${id}`, payload);
}

/**
 * Delete equipment (soft delete)
 * @param {number} eid - Equipment ID
 * @returns {Promise<Object>} Delete result
 */
export async function deleteEquipment(eid) {
  return del('/api/equipmentlist', { EID: eid });
}


value00: DEPLOY.md
value01:
## File Structure After Deployment

```
/var/www/html/clqms/
├── index.html
├── .htaccess
├── _app/
│   ├── immutable/
│   └── ...
├── favicon.png
└── ...
```

## Production Checklist

- [ ] Set production API URL
- [ ] Enable HTTPS/SSL
- [ ] Configure firewall (allow 80/443)
- [ ] Set up log rotation
- [ ] Configure backup strategy
- [ ] Test all routes work after refresh


value00: src/lib/api/equipment.js
value01:
/**
 * Fetch single equipment by ID
 * @param {number} id - Equipment ID (EID)
 * @returns {Promise<Object>} Equipment details
 */
export async function fetchEquipment(id) {
  return get(`/api/equipmentlist/${id}`);
}

/**
 * Create new equipment
 * @param {Object} data - Equipment data
 * @param {string} data.IEID - Internal Equipment ID (required)
 * @param {number} data.DepartmentID - Department ID (required)
 * @param {number} data.Enable - Enable status 0 or 1 (required)
 * @param {string} data.EquipmentRole - Equipment role code (required)
 * @param {string} [data.InstrumentID] - Instrument identifier
 * @param {string} [data.InstrumentName] - Instrument display name
 * @param {number} [data.WorkstationID] - Workstation ID
 * @returns {Promise<Object>} Created equipment ID
 */


value00: DEPLOY.md
value01:
## 5. Subdirectory Deployment

If deploying to a subdirectory (e.g., `/clqms/`):

1. Update `svelte.config.js`:
```javascript
adapter: adapter({
  pages: 'build',
  assets: 'build',
  fallback: 'index.html'
}),
paths: {
  base: '/clqms'
}
```

2. Rebuild and deploy to `/var/www/html/clqms/`

3. Update `.htaccess` RewriteBase:
```apache
RewriteBase /clqms/
```

## Troubleshooting

### 404 on refresh
- Ensure `mod_rewrite` is enabled
- Check `.htaccess` is in the build folder
- Verify `AllowOverride All` in Apache config

### API not working
- Check browser console for CORS errors
- Verify `VITE_API_URL` is set correctly
- Test API endpoint directly

### Blank page
- Check browser console for errors
- Verify all assets loaded (check Network tab)
- Ensure `fallback: 'index.html'` is set


value00: src/lib/api/equipment.js
value01:
export async function createEquipment(data) {
  const payload = {
    IEID: data.IEID,
    DepartmentID: data.DepartmentID,
    Enable: data.Enable,
    EquipmentRole: data.EquipmentRole,
    InstrumentID: data.InstrumentID || null,
    InstrumentName: data.InstrumentName || null,
    WorkstationID: data.WorkstationID || null,
  };
  return post('/api/equipmentlist', payload);
}


value00: DEPLOY.md
value01:
# Apache Deployment Guide for CLQMS

## Quick Start

The app is now configured for static hosting. Follow these steps to deploy:

## 1. Build the Application

```bash
pnpm run build
```

This creates static files in the `build/` folder.


value00: DEPLOY.md
value01:
## 3. API Configuration

**Important**: The dev proxy (`/api` → `localhost:8000`) doesn't work in production.

### Option 1: Configure API URL

Create a `.env.production` file:
```
VITE_API_URL=https://your-api-server.com/api
```

Then rebuild:
```bash
pnpm run build
```

### Option 2: Apache Reverse Proxy

Add to your VirtualHost:
```apache
ProxyPass /api http://localhost:8000/api
ProxyPassReverse /api http://localhost:8000/api
```

Enable proxy module:
```bash
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo systemctl restart apache2
```

## 4. SSL/HTTPS (Recommended)

Use Let's Encrypt:
```bash
sudo apt install certbot python3-certbot-apache
sudo certbot --apache -d clqms.example.com
```


value00: src/lib/api/equipment.js
value01:
import { get, post, patch, del } from './client.js';

/**
 * Fetch list of equipment with optional filters
 * @param {Object} params - Filter parameters
 * @param {string} [params.IEID] - Filter by IEID
 * @param {string} [params.InstrumentName] - Filter by instrument name
 * @param {number} [params.DepartmentID] - Filter by department ID
 * @param {number} [params.WorkstationID] - Filter by workstation ID
 * @param {number} [params.Enable] - Filter by enable status (0 or 1)
 * @returns {Promise<Object>} List of equipment
 */
export async function fetchEquipmentList(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/equipmentlist?${query}` : '/api/equipmentlist');
}


value00: DEPLOY.md
value01:
## 2. Deploy to Apache

### Option A: Copy to DocumentRoot

```bash
# Create directory
sudo mkdir -p /var/www/html/clqms

# Copy build files
sudo cp -r build/* /var/www/html/clqms/

# Set permissions
sudo chown -R www-data:www-data /var/www/html/clqms
sudo chmod -R 755 /var/www/html/clqms
```

### Option B: Using VirtualHost (Recommended)

1. Copy the build files:
```bash
sudo mkdir -p /var/www/html/clqms
sudo cp -r build/* /var/www/html/clqms/
sudo chown -R www-data:www-data /var/www/html/clqms
```

2. Copy the Apache config:
```bash
sudo cp apache-config/clqms.conf /etc/apache2/sites-available/
sudo a2ensite clqms
```

3. Enable required modules:
```bash
sudo a2enmod rewrite
sudo a2enmod deflate
sudo a2enmod expires
sudo a2enmod headers
sudo systemctl restart apache2
```


value00: src/lib/api/locations.js
value01:
import { get, post, patch, del } from './client.js';

export async function fetchLocations(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/location?${query}` : '/api/location');
}

export async function fetchLocation(id) {
  return get(`/api/location/${id}`);
}


value00: src/lib/api/geography.js
value01:
import { get } from './client.js';

export async function fetchGeographicalAreas() {
  return get('/api/areageo');
}

export async function fetchProvinces() {
  return get('/api/areageo/provinces');
}

 export async function fetchCities(provinceId = null) {
  const query = provinceId ? `?ProvinceID=${encodeURIComponent(provinceId)}` : '';
  return get(`/api/areageo/cities${query}`);
 }


value00: src/lib/api/locations.js
value01:
export async function fetchLocation(id) {
  return get(`/api/location/${id}`);
}

export async function createLocation(data) {
  const payload = {
    LocCode: data.Code,
    LocFull: data.Name,
    LocType: data.Type,
    Parent: data.ParentID,
  };
  return post('/api/location', payload);
}

export async function updateLocation(id, data) {
  const payload = {
    LocCode: data.Code,
    LocFull: data.Name,
    LocType: data.Type,
    Parent: data.ParentID,
  };
  return patch(`/api/location/${id}`, payload);
}

export async function deleteLocation(id) {
  return del('/api/location', { body: JSON.stringify({ LocationID: id }) });
}


value00: src/lib/api/occupations.js
value01:
import { get, post, patch } from './client.js';

export async function fetchOccupations(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/occupation?${query}` : '/api/occupation');
}

export async function fetchOccupation(id) {
  return get(`/api/occupation/${id}`);
}

export async function createOccupation(data) {
  const payload = {
    OccCode: data.OccCode,
    OccText: data.OccText,
    Description: data.Description,
  };
  return post('/api/occupation', payload);
}

export async function updateOccupation(id, data) {
  const payload = {
    OccCode: data.OccCode,
    OccText: data.OccText,
    Description: data.Description,
  };
  return patch(`/api/occupation/${id}`, payload);
}


value00: src/lib/api/orders.js
value01:
/**
 * Create a new order with specimens and tests
 * @param {Object} data - Order data
 * @param {number} data.InternalPID - Patient internal ID (required)
 * @param {Array<Object>} data.Tests - Array of test objects with TestSiteID (required)
 * @param {string} [data.OrderID] - Optional custom order ID (auto-generated if not provided)
 * @param {number} [data.PatVisitID] - Visit ID
 * @param {number} [data.SiteID=1] - Site ID
 * @param {string} [data.PlacerID] - Placer ID
 * @param {string} [data.Priority='R'] - Priority (R: Routine, S: Stat, U: Urgent)
 * @param {string} [data.ReqApp] - Requesting application
 * @param {string} [data.Comment] - Order comment
 * @returns {Promise<Object>} API response with created order data
 */


value00: src/lib/api/orders.js
value01:
import { get, post, patch, del } from './client.js';

/**
 * Fetch orders list with optional filters and pagination
 * @param {Object} params - Query parameters
 * @param {number} [params.page=1] - Page number
 * @param {number} [params.perPage=20] - Items per page
 * @param {number} [params.InternalPID] - Filter by internal patient ID
 * @param {string} [params.OrderStatus] - Filter by order status (ORD, SCH, ANA, VER, REV, REP)
 * @param {string} [params.include] - Include details (set to 'details' to include specimens and tests)
 * @returns {Promise<Object>} API response with orders data and pagination
 */


value00: src/lib/api/orders.js
value01:
/**
 * Delete an order
 * @param {string} orderId - Order ID to delete
 * @returns {Promise<Object>} API response
 */
export async function deleteOrder(orderId) {
  return del('/api/ordertest', { body: JSON.stringify({ OrderID: orderId }) });
}

/**
 * Update order status
 * @param {Object} data - Status update data
 * @param {string} data.OrderID - Order ID (required)
 * @param {string} data.OrderStatus - New status (ORD, SCH, ANA, VER, REV, REP)
 * @returns {Promise<Object>} API response with updated order data
 */
export async function updateOrderStatus(data) {
  return post('/api/ordertest/status', data);
}

/**
 * Order status mapping for display
 */


value00: src/lib/api/orders.js
value01:
export async function createOrder(data) {
  return post('/api/ordertest', data);
}

/**
 * Update an existing order
 * @param {Object} data - Order data
 * @param {string} data.OrderID - Order ID (required)
 * @param {string} [data.Priority] - Priority (R, S, U)
 * @param {string} [data.OrderStatus] - Order status (ORD, SCH, ANA, VER, REV, REP)
 * @param {string} [data.OrderingProvider] - Ordering provider
 * @param {number} [data.DepartmentID] - Department ID
 * @param {number} [data.WorkstationID] - Workstation ID
 * @returns {Promise<Object>} API response with updated order data
 */
export async function updateOrder(id, data) {
  return patch(`/api/ordertest/${id}`, data);
}


value00: src/lib/api/orders.js
value01:
/**
 * Order priority mapping for display
 */
export const ORDER_PRIORITY = {
  R: { code: 'R', label: 'Routine', color: 'badge-neutral' },
  S: { code: 'S', label: 'Stat', color: 'badge-error' },
  U: { code: 'U', label: 'Urgent', color: 'badge-warning' }
};

/**
 * Get status display info
 * @param {string} statusCode - Status code
 * @returns {Object} Status display info
 */
export function getStatusInfo(statusCode) {
  return ORDER_STATUS[statusCode] || { code: statusCode, label: statusCode, color: 'badge-ghost' };
}

/**
 * Get priority display info
 * @param {string} priorityCode - Priority code
 * @returns {Object} Priority display info
 */


value00: src/lib/api/orders.js
value01:
export async function fetchOrders(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/ordertest?${query}` : '/api/ordertest');
}

/**
 * Fetch a single order by ID with details
 * @param {string} id - Order ID (e.g., 0025030300001)
 * @returns {Promise<Object>} API response with order details including specimens and tests
 */
export async function fetchOrderById(id) {
  return get(`/api/ordertest/${id}`);
}


value00: src/lib/api/orders.js
value01:
export async function updateOrderStatus(data) {
  return post('/api/ordertest/status', data);
}

/**
 * Order status mapping for display
 */
export const ORDER_STATUS = {
  ORD: { code: 'ORD', label: 'Ordered', color: 'badge-neutral', description: 'Order has been placed' },
  SCH: { code: 'SCH', label: 'Scheduled', color: 'badge-info', description: 'Order is scheduled' },
  ANA: { code: 'ANA', label: 'Analysis', color: 'badge-warning', description: 'Analysis in progress' },
  VER: { code: 'VER', label: 'Verified', color: 'badge-success', description: 'Results verified' },
  REV: { code: 'REV', label: 'Reviewed', color: 'badge-primary', description: 'Results reviewed' },
  REP: { code: 'REP', label: 'Reported', color: 'badge-secondary', description: 'Report generated' }
};


value00: src/lib/api/orders.js
value01:
/**
 * Get priority display info
 * @param {string} priorityCode - Priority code
 * @returns {Object} Priority display info
 */
export function getPriorityInfo(priorityCode) {
  return ORDER_PRIORITY[priorityCode] || { code: priorityCode, label: priorityCode, color: 'badge-ghost' };
}


value00: src/lib/api/organization.js
value01:
export async function fetchDepartment(id) {
  return get(`/api/organization/department/${id}`);
}

export async function createDepartment(data) {
  const payload = {
    DeptCode: data.DeptCode,
    DeptName: data.DeptName,
    SiteID: data.SiteID,
  };
  return post('/api/organization/department', payload);
}

export async function updateDepartment(id, data) {
  const payload = {
    DeptCode: data.DeptCode,
    DeptName: data.DeptName,
    SiteID: data.SiteID,
  };
  return patch(`/api/organization/department/${id}`, payload);
}

export async function deleteDepartment(id) {
  return del('/api/organization/department', { id });
}

// Sites


value00: src/lib/api/organization.js
value01:
export async function fetchSite(id) {
  return get(`/api/organization/site/${id}`);
}

export async function createSite(data) {
  const payload = {
    SiteCode: data.SiteCode,
    SiteName: data.SiteName,
    AccountID: data.AccountID,
  };
  return post('/api/organization/site', payload);
}

export async function updateSite(id, data) {
  const payload = {
    SiteCode: data.SiteCode,
    SiteName: data.SiteName,
    AccountID: data.AccountID,
  };
  return patch(`/api/organization/site/${id}`, payload);
}

export async function deleteSite(id) {
  return del('/api/organization/site', { id });
}

// Workstations


value00: src/lib/api/organization.js
value01:
export async function deleteDepartment(id) {
  return del('/api/organization/department', { id });
}

// Sites
export async function fetchSites(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/organization/site?${query}` : '/api/organization/site');
}

export async function fetchSite(id) {
  return get(`/api/organization/site/${id}`);
}


value00: src/lib/api/organization.js
value01:
import { get, post, patch, del } from './client.js';

// Disciplines
export async function fetchDisciplines(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/organization/discipline?${query}` : '/api/organization/discipline');
}

export async function fetchDiscipline(id) {
  return get(`/api/organization/discipline/${id}`);
}

export async function createDiscipline(data) {
  const payload = {
    DisciplineCode: data.DisciplineCode,
    DisciplineName: data.DisciplineName,
    Parent: data.Parent || null,
    SeqScr: data.SeqScr,
    SeqRpt: data.SeqRpt,
  };
  return post('/api/organization/discipline', payload);
}


value00: src/lib/api/organization.js
value01:
export async function fetchHostApp(id) {
  return get(`/api/organization/hostapp/${id}`);
}

export async function createHostApp(data) {
  const payload = {
    HostAppName: data.HostAppName,
    SiteID: data.SiteID,
  };
  return post('/api/organization/hostapp', payload);
}

export async function updateHostApp(id, data) {
  const payload = {
    HostAppName: data.HostAppName,
    SiteID: data.SiteID,
  };
  return patch(`/api/organization/hostapp/${id}`, payload);
}

export async function deleteHostApp(id) {
  return del('/api/organization/hostapp', { id });
}

// HostComParas


value00: src/lib/api/organization.js
value01:
export async function fetchHostComPara(id) {
  return get(`/api/organization/hostcompara/${id}`);
}

export async function createHostComPara(data) {
  const payload = {
    HostAppID: data.HostAppID,
    HostIP: data.HostIP,
    HostPort: data.HostPort,
    HostPwd: data.HostPwd,
  };
  return post('/api/organization/hostcompara', payload);
}

export async function updateHostComPara(id, data) {
  const payload = {
    HostAppID: data.HostAppID,
    HostIP: data.HostIP,
    HostPort: data.HostPort,
    HostPwd: data.HostPwd,
  };
  return patch(`/api/organization/hostcompara/${id}`, payload);
}

export async function deleteHostComPara(id) {
  return del('/api/organization/hostcompara', { id });
}

// CodingSystems


value00: src/lib/api/organization.js
value01:
export async function fetchCodingSystem(id) {
  return get(`/api/organization/codingsys/${id}`);
}

export async function createCodingSystem(data) {
  const payload = {
    CodingSysAbb: data.CodingSysAbb,
    FullText: data.FullText,
    Description: data.Description,
  };
  return post('/api/organization/codingsys', payload);
}

export async function updateCodingSystem(id, data) {
  const payload = {
    CodingSysAbb: data.CodingSysAbb,
    FullText: data.FullText,
    Description: data.Description,
  };
  return patch(`/api/organization/codingsys/${id}`, payload);
}

export async function deleteCodingSystem(id) {
  return del('/api/organization/codingsys', { id });
}


// Accounts


value00: src/lib/api/organization.js
value01:
export async function deleteCodingSystem(id) {
  return del('/api/organization/codingsys', { id });
}


// Accounts
export async function fetchAccounts(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/organization/account?${query}` : '/api/organization/account');
}

export async function fetchAccount(id) {
  return get(`/api/organization/account/${id}`);
}


value00: src/lib/api/organization.js
value01:
export async function deleteHostComPara(id) {
  return del('/api/organization/hostcompara', { id });
}

// CodingSystems
export async function fetchCodingSystems(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/organization/codingsys?${query}` : '/api/organization/codingsys');
}

export async function fetchCodingSystem(id) {
  return get(`/api/organization/codingsys/${id}`);
}


value00: src/lib/api/organization.js
value01:
export async function fetchAccount(id) {
  return get(`/api/organization/account/${id}`);
}

export async function createAccount(data) {
  const payload = {
    AccountName: data.AccountName,
    Initial: data.Initial,
    Parent: data.Parent,
  };
  return post('/api/organization/account', payload);
}

export async function updateAccount(id, data) {
  const payload = {
    AccountName: data.AccountName,
    Initial: data.Initial,
    Parent: data.Parent,
  };
  return patch(`/api/organization/account/${id}`, payload);
}

export async function deleteAccount(id) {
  return del('/api/organization/account', { id });
}

// Workstations


value00: src/lib/api/organization.js
value01:
// Workstations
export async function createWorkstation(data) {
  const payload = {
    WorkstationCode: data.WorkstationCode,
    WorkstationName: data.WorkstationName,
    SiteID: data.SiteID,
    DepartmentID: data.DepartmentID,
  };
  return post('/api/organization/workstation', payload);
}

export async function updateWorkstation(id, data) {
  const payload = {
    WorkstationCode: data.WorkstationCode,
    WorkstationName: data.WorkstationName,
    SiteID: data.SiteID,
    DepartmentID: data.DepartmentID,
  };
  return patch(`/api/organization/workstation/${id}`, payload);
}

export async function deleteWorkstation(id) {
  return del('/api/organization/workstation', { id });
}


value00: src/lib/api/organization.js
value01:
export async function deleteHostApp(id) {
  return del('/api/organization/hostapp', { id });
}

// HostComParas
export async function fetchHostComParas(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/organization/hostcompara?${query}` : '/api/organization/hostcompara');
}

export async function fetchHostComPara(id) {
  return get(`/api/organization/hostcompara/${id}`);
}


value00: src/lib/api/organization.js
value01:
export async function deleteSite(id) {
  return del('/api/organization/site', { id });
}

// Workstations
export async function fetchWorkstations(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/organization/workstation?${query}` : '/api/organization/workstation');
}

export async function fetchWorkstation(id) {
  return get(`/api/organization/workstation/${id}`);
}

// HostApps
export async function fetchHostApps(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/organization/hostapp?${query}` : '/api/organization/hostapp');
}

export async function fetchHostApp(id) {
  return get(`/api/organization/hostapp/${id}`);
}


value00: src/lib/api/organization.js
value01:
export async function updateDiscipline(id, data) {
  const payload = {
    DisciplineCode: data.DisciplineCode,
    DisciplineName: data.DisciplineName,
    Parent: data.Parent || null,
    SeqScr: data.SeqScr,
    SeqRpt: data.SeqRpt,
  };
  return patch(`/api/organization/discipline/${id}`, payload);
}

export async function deleteDiscipline(id) {
  return del('/api/organization/discipline', { id });
}

// Departments
export async function fetchDepartments(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/organization/department?${query}` : '/api/organization/department');
}

export async function fetchDepartment(id) {
  return get(`/api/organization/department/${id}`);
}


value00: src/lib/api/patients.js
value01:
 * @param {string} [data.EmailAddress1] - Primary email
 * @param {string} [data.EmailAddress2] - Secondary email
 * @param {Object} [data.PatIdt] - Patient identifier object
 * @param {string} [data.PatIdt.IdentifierType] - Identifier type (KTP, PASS, SSN, SIM, KTAS)
 * @param {string} [data.PatIdt.Identifier] - Identifier value
 * @param {string} [data.Race] - Race
 * @param {string} [data.MaritalStatus] - Marital status (A, B, D, M, S, W)
 * @param {string} [data.Religion] - Religion
 * @param {string} [data.Ethnic] - Ethnicity
 * @param {string} [data.DeathIndicator] - Death indicator (Y/N)
 * @param {string} [data.TimeOfDeath] - Time of death
 * @param {string} [data.PatCom] - Patient comments
 * @returns {Promise<Object>} API response
 */


value00: README.md
value01:
## Project Structure

```
src/
  lib/
    api/          # API client and endpoints
    stores/       # Svelte stores (auth, valuesets)
    components/   # Reusable components
    utils/        # Utility functions
  routes/         # SvelteKit routes
    (app)/        # Authenticated routes
      dashboard/
      patients/
      master-data/
    login/        # Public routes
```

## API Configuration

API requests to `/api` are proxied to `http://localhost:8000` in development (configured in `vite.config.js`).

## Authentication

JWT-based authentication with automatic redirect to `/login` on 401 responses.

## Code Style

See [AGENTS.md](./AGENTS.md) for detailed coding guidelines.


value00: src/lib/api/patients.js
value01:
/**
 * Create a new patient
 * @param {Object} data - Patient data
 * @param {string} data.PatientID - Patient identifier (required)
 * @param {string} data.NameFirst - First name (required)
 * @param {string} data.Sex - Sex code: '1' (Female) or '2' (Male) (required)
 * @param {string} data.Birthdate - Birthdate in ISO 8601 format (required)
 * @param {string} [data.AlternatePID] - Alternate patient ID
 * @param {string} [data.Prefix] - Title prefix (Mr, Mrs, Ms, Dr, Prof)
 * @param {string} [data.NameMiddle] - Middle name
 * @param {string} [data.NameLast] - Last name
 * @param {string} [data.NameMaiden] - Maiden name


value00: src/lib/api/patients.js
value01:
 * @param {string} [data.NameLast] - Last name
 * @param {string} [data.NameMaiden] - Maiden name
 * @param {string} [data.Suffix] - Name suffix
 * @param {string} [data.PlaceOfBirth] - Place of birth
 * @param {string} [data.Citizenship] - Citizenship
 * @param {string} [data.Street_1] - Street address line 1
 * @param {string} [data.Street_2] - Street address line 2
 * @param {string} [data.Street_3] - Street address line 3
 * @param {string} [data.ZIP] - ZIP code
 * @param {string} [data.Province] - Province area code
 * @param {string} [data.City] - City area code
 * @param {string} [data.Country] - Country
 * @param {string} [data.Phone] - Phone number
 * @param {string} [data.MobilePhone] - Mobile phone number
 * @param {string} [data.EmailAddress1] - Primary email


value00: README.md
value01:
# CLQMS Frontend

Clinical Laboratory Quality Management System (CLQMS) - SvelteKit frontend application.

## Tech Stack

- **Framework**: SvelteKit 2.50.2 with Svelte 5 (runes)
- **Styling**: Tailwind CSS 4 + DaisyUI 5
- **Icons**: Lucide Svelte
- **Build Tool**: Vite 7.3.1
- **Package Manager**: pnpm

## Prerequisites

- Node.js 18+ 
- pnpm (`npm install -g pnpm`)
- Backend API running on `http://localhost:8000`

## Setup

```bash
# Install dependencies
pnpm install

# Create environment file
cp .env.example .env
```

## Development Commands

```bash
# Start development server
pnpm run dev

# Build for production
pnpm run build

# Preview production build
pnpm run preview

# Sync SvelteKit (runs automatically on install)
pnpm run prepare
```


value00: src/lib/api/patients.js
value01:
/**
 * Fetch a single patient by ID
 * @param {number} id - Internal patient ID
 * @returns {Promise<Object>} API response with patient details
 */
export async function fetchPatient(id) {
  return get(`/api/patient/${id}`);
}

/**
 * Check if a patient exists by PatientID or Email
 * @param {Object} params - Check parameters
 * @param {string} [params.PatientID] - Patient ID to check
 * @param {string} [params.EmailAddress1] - Email to check
 * @returns {Promise<Object>} API response with exists flag
 */
export async function checkPatientExists(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/patient/check?${query}` : '/api/patient/check');
}


value00: src/lib/api/patients.js
value01:
export async function createPatient(data) {
  return post('/api/patient', data);
}

/**
 * Update an existing patient
 * @param {Object} data - Patient data (must include PatientID)
 * @returns {Promise<Object>} API response
 */
export async function updatePatient(id, data) {
  return patch(`/api/patient/${id}`, data);
}

/**
 * Delete a patient (soft delete)
 * @param {number} internalPid - Internal patient ID
 * @returns {Promise<Object>} API response
 */
export async function deletePatient(internalPid) {
  return del('/api/patient', { body: JSON.stringify({ InternalPID: internalPid }) });
}


value00: src/lib/api/patients.js
value01:
import { get, post, patch, del } from './client.js';

/**
 * Fetch patients list with optional filters and pagination
 * @param {Object} params - Query parameters
 * @param {number} [params.page=1] - Page number
 * @param {number} [params.perPage=20] - Items per page
 * @param {number} [params.InternalPID] - Filter by internal patient ID
 * @param {string} [params.PatientID] - Filter by patient ID
 * @param {string} [params.Name] - Search by patient name
 * @param {string} [params.Birthdate] - Filter by birthdate (YYYY-MM-DD)
 * @returns {Promise<Object>} API response with patient data and pagination
 */
export async function fetchPatients(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/patient?${query}` : '/api/patient');
}


value00: src/lib/api/reports.js
value01:
export function getReportUrl(orderId) {
  return `${getApiUrl()}/api/reports/${orderId}`;
}

/**
 * Open report in new window
 * @param {string|number} orderId - Order ID
 * @param {string} [target='_blank'] - Window target
 * @returns {Window|null} Window reference
 */
export function openReport(orderId, target = '_blank') {
  const url = getReportUrl(orderId);
  return window.open(url, target);
}

/**
 * Print report for an order
 * @param {string|number} orderId - Order ID
 */
export function printReport(orderId) {
  const url = getReportUrl(orderId);
  const printWindow = window.open(url, '_blank');
  if (printWindow) {
    printWindow.onload = () => {
      printWindow.print();
    };
  }
}


value00: src/lib/api/reports.js
value01:
import { config } from '$lib/stores/config.js';

/**
 * Get the API URL from runtime config
 * @returns {string}
 */
function getApiUrl() {
  const runtimeUrl = config.getApiUrl();
  return runtimeUrl || import.meta.env.VITE_API_URL || '';
}

/**
 * Generate lab report URL for an order
 * @param {string|number} orderId - Order ID
 * @returns {string} Report URL
 */
export function getReportUrl(orderId) {
  return `${getApiUrl()}/api/reports/${orderId}`;
}


value00: src/lib/api/results.js
value01:
export async function fetchResults(params = {}) {
  const query = new URLSearchParams();
  
  if (params.order_id) query.append('order_id', params.order_id);
  if (params.patient_id) query.append('patient_id', params.patient_id);
  if (params.page) query.append('page', params.page);
  if (params.per_page) query.append('per_page', params.per_page);
  
  const queryString = query.toString();
  return get(queryString ? `/api/results?${queryString}` : '/api/results');
}

/**
 * Fetch a single result by ID
 * @param {number} id - Result ID
 * @returns {Promise<Object>} Result details
 */
export async function fetchResultById(id) {
  return get(`/api/results/${id}`);
}


value00: src/lib/api/results.js
value01:
export async function fetchResultById(id) {
  return get(`/api/results/${id}`);
}

/**
 * Update a result value with auto-validation
 * @param {number} id - Result ID
 * @param {Object} data - Result data
 * @param {string} data.Result - The result value
 * @param {number} [data.RefNumID] - Reference range ID
 * @param {string} [data.SampleType] - Sample type
 * @param {number} [data.WorkstationID] - Workstation ID
 * @param {number} [data.EquipmentID] - Equipment ID
 * @returns {Promise<Object>} Updated result with flag
 */
export async function updateResult(id, data) {
  return patch(`/api/results/${id}`, data);
}

/**
 * Delete a result (soft delete)
 * @param {number} id - Result ID
 * @returns {Promise<Object>} Success response
 */


value00: src/lib/api/results.js
value01:
import { get, patch, del } from './client.js';

/**
 * Fetch results with optional filters
 * @param {Object} params - Query parameters
 * @param {number} [params.order_id] - Filter by order ID
 * @param {number} [params.patient_id] - Filter by patient ID
 * @param {number} [params.page] - Page number
 * @param {number} [params.per_page] - Items per page
 * @returns {Promise<Object>} Results list response
 */


value00: src/lib/api/results.js
value01:
export async function deleteResult(id) {
  return del(`/api/results/${id}`);
}

/**
 * Fetch results by order ID
 * @param {number} orderId - Order ID
 * @returns {Promise<Object>} Results list for order
 */
export async function fetchResultsByOrder(orderId) {
  return fetchResults({ order_id: orderId });
}

/**
 * Fetch cumulative results by patient ID
 * @param {number} patientId - Patient ID
 * @param {number} [page] - Page number
 * @param {number} [perPage] - Items per page
 * @returns {Promise<Object>} Patient results history
 */
export async function fetchResultsByPatient(patientId, page = 1, perPage = 20) {
  return fetchResults({ patient_id: patientId, page, per_page: perPage });
}


value00: src/lib/api/rules.js
value01:
 * @typedef {import('$lib/types/rules.types.js').RuleActionsListResponse} RuleActionsListResponse
 * @typedef {import('$lib/types/rules.types.js').ValidateExprResponse} ValidateExprResponse
 * @typedef {import('$lib/types/rules.types.js').TestRuleMapping} TestRuleMapping
 */


value00: src/lib/api/rules.js
value01:
export async function deleteRule(id) {
  return del(`/api/rules/${id}`);
}

/**
 * Link a test to a rule (many-to-many mapping)
 * @param {number} ruleId
 * @param {number} testSiteId
 * @returns {Promise<any>}
 */
export async function linkTestToRule(ruleId, testSiteId) {
  return post(`/api/rules/${ruleId}/link`, { TestSiteID: testSiteId });
}

/**
 * Unlink a test from a rule
 * @param {number} ruleId
 * @param {number} testSiteId
 * @returns {Promise<any>}
 */
export async function unlinkTestFromRule(ruleId, testSiteId) {
  return post(`/api/rules/${ruleId}/unlink`, { TestSiteID: testSiteId });
}


value00: src/lib/api/rules.js
value01:
export async function fetchRule(id) {
  return get(`/api/rules/${id}`);
}

/**
 * Create a rule with test mappings and optional initial actions
 * @param {Partial<RuleDef> & { TestSiteIDs: number[], actions?: Array<Partial<RuleAction>> }} payload
 * @returns {Promise<any>}
 */
export async function createRule(payload) {
  return post('/api/rules', payload);
}

/**
 * Update a rule and its test mappings
 * @param {number} id
 * @param {Partial<RuleDef> & { TestSiteIDs?: number[] }} payload
 * @returns {Promise<any>}
 */
export async function updateRule(id, payload) {
  return patch(`/api/rules/${id}`, payload);
}

/**
 * Soft delete a rule
 * @param {number} id
 * @returns {Promise<any>}
 */


value00: src/lib/api/rules.js
value01:
/**
 * List rules
 * Filter by TestSiteID to see rules linked to a specific test
 * @param {{ EventCode?: string, Active?: 0|1|number, TestSiteID?: number, search?: string }} [params]
 * @returns {Promise<RulesListResponse>}
 */
export async function fetchRules(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/rules?${query}` : '/api/rules');
}

/**
 * Get rule (with actions and linked tests)
 * @param {number} id
 * @returns {Promise<RuleDetailResponse>}
 */
export async function fetchRule(id) {
  return get(`/api/rules/${id}`);
}


value00: src/lib/api/rules.js
value01:
import { get, post, patch, del } from './client.js';

/**
 * @typedef {import('$lib/types/rules.types.js').RuleDef} RuleDef
 * @typedef {import('$lib/types/rules.types.js').RuleAction} RuleAction
 * @typedef {import('$lib/types/rules.types.js').RuleWithActions} RuleWithActions
 * @typedef {import('$lib/types/rules.types.js').RuleWithLinks} RuleWithLinks
 * @typedef {import('$lib/types/rules.types.js').LinkedTestSummary} LinkedTestSummary
 * @typedef {import('$lib/types/rules.types.js').RulesListResponse} RulesListResponse
 * @typedef {import('$lib/types/rules.types.js').RuleDetailResponse} RuleDetailResponse


value00: src/lib/api/rules.js
value01:
export async function validateExpression(expr, context = {}) {
  return post('/api/rules/validate', { expr, context });
}

/**
 * Compile a DSL expression into compiled payload
 * @param {string} expr
 * @returns {Promise<{ compiled: any; conditionExprCompiled: string }>}
 */
export async function compileRuleExpr(expr) {
  return post('/api/rules/compile', { expr });
}

/**
 * List actions for a rule
 * @param {number} id
 * @returns {Promise<RuleActionsListResponse>}
 */
export async function fetchRuleActions(id) {
  return get(`/api/rules/${id}/actions`);
}

/**
 * Create action for a rule
 * @param {number} id
 * @param {Partial<RuleAction>} payload
 * @returns {Promise<any>}
 */


value00: src/lib/api/rules.js
value01:
export async function createRuleAction(id, payload) {
  return post(`/api/rules/${id}/actions`, payload);
}

/**
 * Update action
 * @param {number} id
 * @param {number} actionId
 * @param {Partial<RuleAction>} payload
 * @returns {Promise<any>}
 */
export async function updateRuleAction(id, actionId, payload) {
  return patch(`/api/rules/${id}/actions/${actionId}`, payload);
}

/**
 * Soft delete action
 * @param {number} id
 * @param {number} actionId
 * @returns {Promise<any>}
 */
export async function deleteRuleAction(id, actionId) {
  return del(`/api/rules/${id}/actions/${actionId}`);
}


value00: src/lib/api/rules.js
value01:
export async function unlinkTestFromRule(ruleId, testSiteId) {
  return post(`/api/rules/${ruleId}/unlink`, { TestSiteID: testSiteId });
}

/**
 * Validate/evaluate an expression
 * @param {string} expr
 * @param {Record<string, any>} [context]
 * @returns {Promise<ValidateExprResponse>}
 */
export async function validateExpression(expr, context = {}) {
  return post('/api/rules/validate', { expr, context });
}


value00: src/lib/api/specialties.js
value01:
import { get, post, patch, del } from './client.js';

export async function fetchSpecialties(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/medicalspecialty?${query}` : '/api/medicalspecialty');
}

export async function fetchSpecialty(id) {
  return get(`/api/medicalspecialty/${id}`);
}

export async function createSpecialty(data) {
  return post('/api/medicalspecialty', data);
}

export async function updateSpecialty(id, data) {
  return patch(`/api/medicalspecialty/${id}`, data);
}

export async function deleteSpecialty(id) {
  return del('/api/medicalspecialty', { body: JSON.stringify({ id }) });
}


value00: src/lib/api/specimens.js
value01:
/**
 * Create a new specimen
 * @param {Object} data - Specimen data
 * @param {string} data.SpecimenID - Specimen identifier (required)
 * @param {string} data.SpecimenType - Type of specimen (required)
 * @param {string} [data.OrderID] - Associated order ID
 * @param {string} [data.Status] - Specimen status
 * @param {string} [data.CollectionDate] - Collection date/time
 * @param {string} [data.CollectedBy] - Collector identifier
 * @param {string} [data.ContainerType] - Container type
 * @param {string} [data.Volume] - Volume collected
 * @param {string} [data.Units] - Volume units
 * @param {string} [data.Comment] - Comments
 * @returns {Promise<Object>} API response
 */
export async function createSpecimen(data) {
  return post('/api/specimen', data);
}


value00: src/lib/api/specimens.js
value01:
export async function fetchSpecimenType(id) {
  return get(`/api/specimen/type/${id}`);
}

/**
 * Fetch specimen collections for dropdown
 * @param {Object} params - Query parameters
 * @returns {Promise<Object>} API response with collection methods
 */
export async function fetchSpecimenCollections(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/specimen/collection?${query}` : '/api/specimen/collection');
}


value00: src/lib/api/specimens.js
value01:
import { get, post, patch, del } from './client.js';

/**
 * Fetch specimens list with optional filters and pagination
 * @param {Object} params - Query parameters
 * @param {number} [params.page=1] - Page number
 * @param {number} [params.perPage=20] - Items per page
 * @param {string} [params.SpecimenID] - Filter by specimen ID
 * @param {string} [params.SpecimenType] - Filter by specimen type
 * @param {string} [params.Status] - Filter by status
 * @param {string} [params.OrderID] - Filter by order ID
 * @returns {Promise<Object>} API response with specimen data and pagination
 */


value00: src/lib/api/specimens.js
value01:
export async function deleteSpecimen(id) {
  return del(`/api/specimen/${id}`);
}

/**
 * Fetch specimen types for dropdown
 * @param {Object} params - Query parameters
 * @returns {Promise<Object>} API response with specimen types
 */
export async function fetchSpecimenTypes(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/specimen/type?${query}` : '/api/specimen/type');
}

/**
 * Fetch a single specimen type by ID
 * @param {number} id - Specimen type ID
 * @returns {Promise<Object>} API response with specimen type details
 */
export async function fetchSpecimenType(id) {
  return get(`/api/specimen/type/${id}`);
}


value00: src/lib/api/specimens.js
value01:
export async function createSpecimen(data) {
  return post('/api/specimen', data);
}

/**
 * Update an existing specimen
 * @param {number} id - Specimen ID
 * @param {Object} data - Specimen data to update
 * @returns {Promise<Object>} API response
 */
export async function updateSpecimen(id, data) {
  return patch(`/api/specimen/${id}`, data);
}

/**
 * Delete a specimen
 * @param {number} id - Specimen ID
 * @returns {Promise<Object>} API response
 */
export async function deleteSpecimen(id) {
  return del(`/api/specimen/${id}`);
}


value00: src/lib/api/specimens.js
value01:
export async function fetchSpecimens(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/specimen?${query}` : '/api/specimen');
}

/**
 * Fetch a single specimen by ID
 * @param {number} id - Specimen ID
 * @returns {Promise<Object>} API response with specimen details
 */
export async function fetchSpecimen(id) {
  return get(`/api/specimen/${id}`);
}


value00: src/lib/api/testmap.js
value01:
import { get, post, patch, del } from './client.js';

/**
 * @typedef {Object} TestMapHeader
 * @property {number} TestMapID - Mapping ID
 * @property {string} HostType - Host Type (HIS, SITE, WST, INST)
 * @property {string} HostID - Host ID
 * @property {string} HostName - Host Name
 * @property {string} ClientType - Client Type (HIS, SITE, WST, INST)
 * @property {string} ClientID - Client ID
 * @property {string} ClientName - Client Name
 * @property {string} IsActive - Active status ('1' or '0')
 */


value00: src/lib/api/testmap.js
value01:
// ==================== BATCH DETAIL ENDPOINTS ====================

/**
 * Batch create test mapping details
 * @param {CreateTestMapDetailPayload[]} details - Array of detail records to create
 * @returns {Promise<{success: boolean, message?: string}>} API response
 */
export async function batchCreateTestMapDetails(details) {
  return post('/api/test/testmap/detail/batch', details);
}

/**
 * Batch update test mapping details
 * @param {UpdateTestMapDetailPayload[]} details - Array of detail records to update
 * @returns {Promise<{success: boolean, message?: string}>} API response
 */
export async function batchUpdateTestMapDetails(details) {
  return patch('/api/test/testmap/detail/batch', details);
}


value00: src/lib/api/testmap.js
value01:
export async function batchUpdateTestMapDetails(details) {
  return patch('/api/test/testmap/detail/batch', details);
}

/**
 * Batch delete test mapping details
 * @param {number[]} detailIDs - Array of TestMapDetailID to delete
 * @returns {Promise<{success: boolean, message?: string}>} API response
 */
export async function batchDeleteTestMapDetails(detailIDs) {
  return del('/api/test/testmap/detail/batch', { body: JSON.stringify(detailIDs) });
}

// ==================== VALIDATION ====================

/**
 * Validate mapping form data
 * @param {Object} data - Form data to validate
 * @returns {{valid: boolean, errors: Object}}
 */


value00: src/lib/api/testmap.js
value01:
/**
 * @typedef {Object} TestMapDetail
 * @property {number} TestMapDetailID - Detail ID
 * @property {number} TestMapID - Test Map ID (header)
 * @property {number} TestSiteID - Test Site ID
 * @property {string} TestSiteCode - Test Code
 * @property {string} TestSiteName - Test Name
 * @property {string} HostTestCode - Host Test Code
 * @property {string} HostTestName - Host Test Name
 * @property {number} ConDefID - Container Definition ID
 * @property {string} ClientTestCode - Client Test Code
 * @property {string} ClientTestName - Client Test Name
 * @property {string} IsActive - Active status ('1' or '0')
 */


value00: src/lib/api/testmap.js
value01:
/**
 * @typedef {Object} TestMapWithDetails
 * @property {number} TestMapID - Mapping ID
 * @property {number} TestSiteID - Test Site ID
 * @property {string} TestSiteCode - Test Code
 * @property {string} TestSiteName - Test Name
 * @property {string} HostType - Host Type
 * @property {string} HostID - Host ID
 * @property {string} HostTestCode - Host Test Code
 * @property {string} HostTestName - Host Test Name


value00: src/lib/api/testmap.js
value01:
/**
 * @typedef {Object} TestMapListResponse
 * @property {boolean} success
 * @property {TestMapHeader[]} data
 * @property {string} [message]
 */

/**
 * @typedef {Object} TestMapResponse
 * @property {boolean} success
 * @property {TestMapWithDetails} data
 * @property {string} [message]
 */

/**
 * @typedef {Object} TestMapDetailResponse
 * @property {boolean} success
 * @property {TestMapDetail} data
 * @property {string} [message]
 */

/**
 * @typedef {Object} CreateTestMapPayload
 * @property {number} TestSiteID - Test Site ID
 * @property {string} HostType - Host Type
 * @property {string} HostID - Host ID
 * @property {string} ClientType - Client Type
 * @property {string} ClientID - Client ID
 * @property {Object[]} [details] - Optional detail records to create
 */


value00: src/lib/api/testmap.js
value01:
export async function fetchTestMaps() {
  return get('/api/test/testmap');
}

/**
 * Fetch a single test mapping header by ID with details
 * @param {number} id - Test Map ID
 * @returns {Promise<TestMapResponse>} API response with header and details
 */
export async function fetchTestMap(id) {
  return get(`/api/test/testmap/${id}`);
}

/**
 * Fetch test mappings by test site ID with details
 * @param {number} testSiteID - Test Site ID
 * @returns {Promise<TestMapListResponse>} API response with mappings list
 */
export async function fetchTestMapsByTestSite(testSiteID) {
  return get(`/api/test/testmap/by-testsite/${testSiteID}`);
}


value00: src/lib/api/testmap.js
value01:
/**
 * @typedef {Object} UpdateTestMapDetailPayload
 * @property {number} TestMapDetailID - Detail ID
 * @property {number} [TestMapID] - Test Map ID
 * @property {string} [HostTestCode] - Host Test Code
 * @property {string} [HostTestName] - Host Test Name
 * @property {number} [ConDefID] - Container Definition ID
 * @property {string} [ClientTestCode] - Client Test Code
 * @property {string} [ClientTestName] - Client Test Name
 */

// ==================== HEADER ENDPOINTS ====================

/**
 * Fetch all test mapping headers (grouped by host/client)
 * @returns {Promise<TestMapListResponse>} API response with headers list
 */
export async function fetchTestMaps() {
  return get('/api/test/testmap');
}


value00: src/lib/api/testmap.js
value01:
/**
 * @typedef {Object} UpdateTestMapPayload
 * @property {number} TestMapID - Mapping ID
 * @property {number} [TestSiteID] - Test Site ID
 * @property {string} [HostType] - Host Type
 * @property {string} [HostID] - Host ID
 * @property {string} [ClientType] - Client Type
 * @property {string} [ClientID] - Client ID
 */

/**
 * @typedef {Object} CreateTestMapDetailPayload
 * @property {number} TestMapID - Test Map ID
 * @property {string} HostTestCode - Host Test Code
 * @property {string} HostTestName - Host Test Name
 * @property {number} ConDefID - Container Definition ID
 * @property {string} ClientTestCode - Client Test Code
 * @property {string} ClientTestName - Client Test Name
 */


value00: src/lib/api/testmap.js
value01:
/**
 * Validate detail form data
 * @param {Object} data - Form data to validate
 * @returns {{valid: boolean, errors: Object}}
 */
export function validateTestMapDetail(data) {
  const errors = {};

  if (!data.TestMapID) {
    errors.TestMapID = 'Test Map ID is required';
  }

  const hasAnyField = data.HostTestCode || data.HostTestName || data.ClientTestCode || data.ClientTestName;
  if (!hasAnyField) {
    errors.empty = 'At least one field must be filled';
  }

  return {
    valid: Object.keys(errors).length === 0,
    errors
  };
}


value00: src/lib/api/testmap.js
value01:
 * @property {string} HostTestCode - Host Test Code
 * @property {string} HostTestName - Host Test Name
 * @property {string} ClientType - Client Type
 * @property {string} ClientID - Client ID
 * @property {number} ConDefID - Container Definition ID
 * @property {string} ClientTestCode - Client Test Code
 * @property {string} ClientTestName - Client Test Name
 * @property {string} IsActive - Active status ('1' or '0')
 * @property {TestMapDetail[]} details - Array of detail records
 */


value00: src/lib/api/testmap.js
value01:
export async function fetchTestMapsByTestSite(testSiteID) {
  return get(`/api/test/testmap/by-testsite/${testSiteID}`);
}

/**
 * Create a new test mapping header
 * @param {CreateTestMapPayload} data - Header data
 * @returns {Promise<{success: boolean, data: number, message?: string}>} API response with created TestMapID
 */
export async function createTestMap(data) {
  return post('/api/test/testmap', data);
}

/**
 * Update an existing test mapping header
 * @param {UpdateTestMapPayload} data - Header data
 * @returns {Promise<{success: boolean, data: number, message?: string}>} API response
 */
export async function updateTestMap(id, data) {
  return patch(`/api/test/testmap/${id}`, data);
}


value00: src/lib/api/testmap.js
value01:
export async function createTestMapDetail(data) {
  return post('/api/test/testmap/detail', data);
}

/**
 * Update an existing test mapping detail
 * @param {UpdateTestMapDetailPayload} data - Detail data
 * @returns {Promise<{success: boolean, message?: string}>} API response
 */
export async function updateTestMapDetail(id, data) {
  return patch(`/api/test/testmap/detail/${id}`, data);
}

/**
 * Soft delete a test mapping detail
 * @param {number} id - Test Map Detail ID
 * @returns {Promise<{success: boolean, message?: string}>} API response
 */
export async function deleteTestMapDetail(id) {
  return del('/api/test/testmap/detail', { body: JSON.stringify({ TestMapDetailID: id }) });
}

// ==================== BATCH DETAIL ENDPOINTS ====================


value00: src/lib/api/testmap.js
value01:
/**
 * Validate mapping form data
 * @param {Object} data - Form data to validate
 * @returns {{valid: boolean, errors: Object}}
 */
export function validateTestMap(data) {
  const errors = {};

  if (!data.TestSiteID) {
    errors.TestSiteID = 'Test is required';
  }

  if (!data.HostType) {
    errors.HostType = 'Host Type is required';
  }

  if (!data.HostID) {
    errors.HostID = 'Host ID is required';
  }

  if (!data.ClientType) {
    errors.ClientType = 'Client Type is required';
  }

  if (!data.ClientID) {
    errors.ClientID = 'Client ID is required';
  }

  return {
    valid: Object.keys(errors).length === 0,
    errors
  };
}

/**
 * Validate detail form data
 * @param {Object} data - Form data to validate
 * @returns {{valid: boolean, errors: Object}}
 */


value00: src/lib/api/testmap.js
value01:
export async function updateTestMap(id, data) {
  return patch(`/api/test/testmap/${id}`, data);
}

/**
 * Soft delete a test mapping header (cascades to details)
 * @param {number} id - Test Map ID
 * @returns {Promise<{success: boolean, data: number, message?: string}>} API response
 */
export async function deleteTestMap(id) {
  return del('/api/test/testmap', { body: JSON.stringify({ TestMapID: id }) });
}

// ==================== DETAIL ENDPOINTS ====================

/**
 * Fetch all test mapping details (optionally filtered by TestMapID)
 * @param {Object} params - Query parameters
 * @param {number} [params.TestMapID] - Filter by TestMapID
 * @returns {Promise<{success: boolean, data: TestMapDetail[], message?: string}>} API response
 */


value00: src/lib/api/testmap.js
value01:
export async function fetchTestMapDetails(params = {}) {
  const query = new URLSearchParams();
  if (params.TestMapID) query.append('TestMapID', params.TestMapID.toString());
  const queryString = query.toString();
  return get(queryString ? `/api/test/testmap/detail?${queryString}` : '/api/test/testmap/detail');
}

/**
 * Fetch a single test mapping detail by ID
 * @param {number} id - Test Map Detail ID
 * @returns {Promise<TestMapDetailResponse>} API response with detail
 */
export async function fetchTestMapDetail(id) {
  return get(`/api/test/testmap/detail/${id}`);
}


value00: src/lib/api/testmap.js
value01:
export async function fetchTestMapDetail(id) {
  return get(`/api/test/testmap/detail/${id}`);
}

/**
 * Fetch test mapping details by test map ID
 * @param {number} testMapID - Test Map ID
 * @returns {Promise<{success: boolean, data: TestMapDetail[], message?: string}>} API response
 */
export async function fetchTestMapDetailsByTestMap(testMapID) {
  return get(`/api/test/testmap/detail/by-testmap/${testMapID}`);
}

/**
 * Create a new test mapping detail
 * @param {CreateTestMapDetailPayload} data - Detail data
 * @returns {Promise<{success: boolean, data: number, message?: string}>} API response with created TestMapDetailID
 */
export async function createTestMapDetail(data) {
  return post('/api/test/testmap/detail', data);
}


value00: src/lib/api/tests.js
value01:
export async function fetchTest(id) {
  return get(`/api/test/${id}`);
}

/**
 * Build payload from form state for API submission
 * Follows the specification: nested details object for technical fields
 * @param {any} formData - The form state
 * @param {boolean} isUpdate - Whether this is an update operation
 * @returns {CreateTestPayload | UpdateTestPayload}
 */
function buildPayload(formData, isUpdate = false)


value00: src/lib/api/tests.js
value01:
  // Add members for GROUP type
  if (type === 'GROUP') {
    const groupMembers = formData.testdefgrp || formData.details?.members || [];
    payload.details = {
      members: groupMembers.map(m => ({
        TestSiteID: m.TestSiteID,
        Member: m.Member || m.TestSiteID
      }))
    };
  }

  // Add reference ranges (TEST and PARAM only)


value00: src/lib/api/tests.js
value01:
import { get, post, patch } from './client.js';

/**
 * @typedef {import('$lib/types/test.types.js').TestSummary} TestSummary
 * @typedef {import('$lib/types/test.types.js').TestDetail} TestDetail
 * @typedef {import('$lib/types/test.types.js').CreateTestPayload} CreateTestPayload
 * @typedef {import('$lib/types/test.types.js').UpdateTestPayload} UpdateTestPayload
 * @typedef {import('$lib/types/test.types.js').TestListResponse} TestListResponse
 * @typedef {import('$lib/types/test.types.js').TestDetailResponse} TestDetailResponse
 * @typedef {import('$lib/types/test.types.js').CreateTestResponse} CreateTestResponse


value00: src/lib/api/tests.js
value01:
  if (isUpdate && formData.TestSiteID) {
    payload.TestSiteID = formData.TestSiteID;
  }

  // Build details object based on TestType
  const type = formData.TestType;

  // Common fields for TEST, PARAM, CALC
  if (['TEST', 'PARAM', 'CALC'].includes(type))


value00: src/lib/api/tests.js
value01:
  if (!resultType) {
    return { valid: true }; // ResultType might be optional
  }

  const validRefTypes = validResultTypes[resultType];
  if (!validRefTypes) {
    return { valid: false, error: `Result type '${resultType}' is not valid for '${testType}'` };
  }

  if (refType && !validRefTypes.includes(refType)) {
    return { valid: false, error: `Reference type '${refType}' is not valid for '${testType}' + '${resultType}'` };
  }

  return { valid: true };
}


value00: src/lib/api/tests.js
value01:
{
    payload.details = {
      DisciplineID: formData.details?.DisciplineID || null,
      DepartmentID: formData.details?.DepartmentID || null,
      ResultType: formData.details?.ResultType || '',
      RefType: formData.details?.RefType || '',
      VSet: formData.details?.VSet || '',
      Unit1: formData.details?.Unit1 || '',
      Factor: formData.details?.Factor || null,
      Unit2: formData.details?.Unit2 || '',
      Decimal: formData.details?.Decimal || 2,
      ReqQty: formData.details?.ReqQty || null,
      ReqQtyUnit: formData.details?.ReqQtyUnit || '',
      CollReq: formData.details?.CollReq || '',
      Method: formData.details?.Method || '',
      ExpectedTAT: formData.details?.ExpectedTAT || null
    };

    // Add formula fields for CALC type


value00: src/lib/api/tests.js
value01:
 * @typedef {import('$lib/types/test.types.js').UpdateTestResponse} UpdateTestResponse
 * @typedef {import('$lib/types/test.types.js').DeleteTestResponse} DeleteTestResponse
 * @typedef {import('$lib/types/test.types.js').TestFilterOptions} TestFilterOptions
 */


value00: src/lib/api/tests.js
value01:
/**
 * Get valid result types for a test type
 * @param {string} testType - The test type
 * @returns {Array<{value: string, label: string}>}
 */
export function getResultTypeOptions(testType) {
  switch (testType) {
    case 'CALC':
      return [{ value: 'NMRIC', label: 'Numeric' }];
    case 'GROUP':
    case 'TITLE':
      return [{ value: 'NORES', label: 'No Result' }];
    default:
      return [
        { value: 'NMRIC', label: 'Numeric' },
        { value: 'RANGE', label: 'Range' },
        { value: 'TEXT', label: 'Text' },
        { value: 'VSET', label: 'Value Set' }
      ];
  }
}

/**
 * Get valid reference types for a result type
 * @param {string} resultType - The result type
 * @returns {Array<{value: string, label: string}>}
 */


value00: src/lib/api/tests.js
value01:
{
  /** @type {CreateTestPayload} */
  const payload = {
    SiteID: formData.SiteID || 1,
    TestSiteCode: formData.TestSiteCode,
    TestSiteName: formData.TestSiteName,
    TestType: formData.TestType,
    Description: formData.Description,
    SeqScr: parseInt(formData.SeqScr) || 0,
    SeqRpt: parseInt(formData.SeqRpt) || 0,
    VisibleScr: formData.VisibleScr ? 1 : 0,
    VisibleRpt: formData.VisibleRpt ? 1 : 0,
    CountStat: formData.CountStat ? 1 : 0,
    Requestable: formData.Requestable ? 1 : 0,
    // StartDate is auto-set by backend (created_at)
    details: {},
    refnum: [],
    reftxt: [],
    testmap: []
  };

  // Add TestSiteID for updates
  if (isUpdate && formData.TestSiteID) {
    payload.TestSiteID = formData.TestSiteID;
  }


value00: src/lib/api/tests.js
value01:
  if (['TEST', 'PARAM'].includes(type)) {
    if (formData.refnum && Array.isArray(formData.refnum)) {
      payload.refnum = formData.refnum.map(r => ({
        NumRefType: r.NumRefType,
        RangeType: r.RangeType,
        Sex: r.Sex,
        AgeStart: parseInt(r.AgeStart) || 0,
        AgeEnd: parseInt(r.AgeEnd) || 54750, // 150 years in days
        LowSign: r.LowSign || null,
        Low: r.Low !== null && r.Low !== undefined ? parseFloat(r.Low) : null,
        HighSign: r.HighSign || null,
        High: r.High !== null && r.High !== undefined ? parseFloat(r.High) : null,
        Flag: r.Flag || null,
        Interpretation: r.Interpretation || null
      }));
    }


value00: src/lib/api/tests.js
value01:
  // Add mappings (all types)
  if (formData.testmap && Array.isArray(formData.testmap)) {
    payload.testmap = formData.testmap.map(m => ({
      HostType: m.HostType || null,
      HostID: m.HostID || null,
      HostDataSource: m.HostDataSource || null,
      HostTestCode: m.HostTestCode || null,
      HostTestName: m.HostTestName || null,
      ClientType: m.ClientType || null,
      ClientID: m.ClientID || null,
      ClientDataSource: m.ClientDataSource || null,
      ConDefID: m.ConDefID || null,
      ClientTestCode: m.ClientTestCode || null,
      ClientTestName: m.ClientTestName || null
    }));
  }

  return payload;
}


value00: src/lib/api/tests.js
value01:
export function validateTestCode(code) {
  if (!code || code.trim() === '') {
    return { valid: false, error: 'Test code is required' };
  }

  const trimmed = code.trim();

  const regex = /^[A-Z0-9]+$/;
  if (!regex.test(trimmed)) {
    return { valid: false, error: 'Test code must be uppercase alphanumeric' };
  }

  return { valid: true };
}

/**
 * Validate test name according to specification
 * - Required
 * - 3-255 characters
 * - Alphanumeric with hyphen, space, and parentheses allowed
 * - Regex: ^[a-zA-Z0-9\s\-\(\)]{3,255}$
 * @param {string} name - The test name
 * @returns {{ valid: boolean, error?: string }}
 */


value00: src/lib/api/tests.js
value01:
/**
 * Fetch tests list with optional filters, pagination, and search
 * @param {TestFilterOptions & { page?: number, perPage?: number }} [params] - Query parameters
 * @returns {Promise<TestListResponse>} API response with test data and pagination
 */
export async function fetchTests(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/test?${query}` : '/api/test');
}

/**
 * Fetch a single test by ID
 * @param {number} id - Test Site ID
 * @returns {Promise<TestDetailResponse>} API response with test detail
 */
export async function fetchTest(id) {
  return get(`/api/test/${id}`);
}


value00: src/lib/api/tests.js
value01:
export function getRefTypeOptions(resultType) {
  switch (resultType) {
    case 'NMRIC':
    case 'RANGE':
      return [
        { value: 'RANGE', label: 'Range' },
        { value: 'THOLD', label: 'Threshold' }
      ];
    case 'VSET':
      return [{ value: 'VSET', label: 'Value Set' }];
    case 'TEXT':
      return [{ value: 'TEXT', label: 'Text' }];
    case 'NORES':
      return [{ value: 'NOREF', label: 'No Reference' }];
    default:
      return [];
  }
}

/**
 * Validate test code according to specification
 * - Required
 * - 3-6 characters
 * - Uppercase alphanumeric only
 * - Regex: ^[A-Z0-9]{3,6}$
 * @param {string} code - The test code
 * @returns {{ valid: boolean, error?: string }}
 */


value00: src/lib/api/tests.js
value01:
export async function deleteTest(id) {
return patch('/api/test', {
    TestSiteID: id,
    IsActive: '0',
  });
}

/**
 * Validate test type combination
 * According to business rules: TestType + ResultType + RefType must be valid
 * @param {string} testType - The test type
 * @param {string} resultType - The result type
 * @param {string} refType - The reference type
 * @returns {{ valid: boolean, error?: string }}
 */
export function validateTypeCombination(testType, resultType, refType) {
  // Valid combinations based on specification


value00: src/lib/api/tests.js
value01:
  // Valid combinations based on specification
  const validCombinations = {
    TEST: {
      NMRIC: ['RANGE', 'THOLD'],
      RANGE: ['RANGE', 'THOLD'],
      TEXT: ['TEXT'],
      VSET: ['VSET']
    },
    PARAM: {
      NMRIC: ['RANGE', 'THOLD'],
      RANGE: ['RANGE', 'THOLD'],
      TEXT: ['TEXT'],
      VSET: ['VSET']
    },
    CALC: {
      NMRIC: ['RANGE', 'THOLD']
    },
    GROUP: {
      NORES: ['NOREF']
    },
    TITLE: {
      NORES: ['NOREF']
    }
  };

  const validResultTypes = validCombinations[testType];
  if (!validResultTypes) {
    return { valid: false, error: 'Invalid test type' };
  }

  if (!resultType) {
    return { valid: true }; // ResultType might be optional
  }


value00: src/lib/api/tests.js
value01:
export function validateTestName(name) {
  if (!name || name.trim() === '') {
    return { valid: false, error: 'Test name is required' };
  }

  const trimmed = name.trim();
  if (trimmed.length < 3) {
    return { valid: false, error: 'Test name must be at least 3 characters' };
  }
  if (trimmed.length > 255) {
    return { valid: false, error: 'Test name must be at most 255 characters' };
  }

  const regex = /^[a-zA-Z0-9\s\-\(\)]{3,255}$/;
  if (!regex.test(trimmed)) {
    return { valid: false, error: 'Test name can only contain letters, numbers, spaces, hyphens, and parentheses' };
  }

  return { valid: true };
}


value00: src/lib/api/tests.js
value01:
    if (formData.reftxt && Array.isArray(formData.reftxt)) {
      payload.reftxt = formData.reftxt.map(r => ({
        TxtRefType: r.TxtRefType,
        Sex: r.Sex,
        AgeStart: parseInt(r.AgeStart) || 0,
        AgeEnd: parseInt(r.AgeEnd) || 54750, // 150 years in days
        RefTxt: r.RefTxt || '',
        Flag: r.Flag || null
      }));
    }
  }


value00: src/lib/api/tests.js
value01:
    // Add formula fields for CALC type
    if (type === 'CALC') {
      payload.details.FormulaCode = formData.details?.FormulaCode || '';

      const calcMembers = formData.testdefgrp || formData.details?.members || [];
      if (calcMembers.length > 0) {
        payload.details.members = calcMembers.map(m => ({
          TestSiteID: m.TestSiteID,
          Member: m.Member || m.TestSiteID
        }));
      }
    }
  }


value00: src/lib/api/tests.js
value01:
/**
 * Create a new test
 * @param {any} formData - The form state
 * @returns {Promise<CreateTestResponse>} API response
 */
export async function createTest(formData) {
  const payload = buildPayload(formData, false);
  return post('/api/test', payload);
}

/**
 * Update an existing test
 * @param {any} formData - The form state
 * @returns {Promise<UpdateTestResponse>} API response
 */
export async function updateTest(id, formData) {
  const payload = buildPayload(formData, true);
  return patch(`/api/test/${id}`, payload);
}

/**
 * Soft delete a test (set IsActive to '0')
 * @param {number} id - Test Site ID
 * @returns {Promise<DeleteTestResponse>} API response
 */


value00: src/lib/api/users.js
value01:
export async function createUser(data) {
  return post('/api/users', data);
}

/**
 * Update an existing user
 * @param {number} id - User ID
 * @param {Object} data - User data to update
 * @returns {Promise<Object>} API response
 */
export async function updateUser(id, data) {
  return patch(`/api/users/${id}`, data);
}

/**
 * Delete a user
 * @param {number} id - User ID
 * @returns {Promise<Object>} API response
 */
export async function deleteUser(id) {
  return del(`/api/users/${id}`);
}


value00: src/lib/api/users.js
value01:
export async function fetchUser(id) {
  return get(`/api/users/${id}`);
}

/**
 * Create a new user
 * @param {Object} data - User data
 * @param {string} data.Username - Username (required)
 * @param {string} data.Email - Email address (required)
 * @param {string} data.Password - Password (required)
 * @param {string} [data.NameFirst] - First name
 * @param {string} [data.NameLast] - Last name
 * @param {string} [data.Role] - User role
 * @param {string} [data.Department] - Department
 * @param {string} [data.Status] - User status (active/inactive)
 * @returns {Promise<Object>} API response
 */
export async function createUser(data) {
  return post('/api/users', data);
}


value00: src/lib/api/users.js
value01:
export async function fetchUsers(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/users?${query}` : '/api/users');
}

/**
 * Fetch a single user by ID
 * @param {number} id - User ID
 * @returns {Promise<Object>} API response with user details
 */
export async function fetchUser(id) {
  return get(`/api/users/${id}`);
}


value00: src/lib/api/users.js
value01:
import { get, post, patch, del } from './client.js';

/**
 * Fetch users list with optional filters and pagination
 * @param {Object} params - Query parameters
 * @param {number} [params.page=1] - Page number
 * @param {number} [params.perPage=20] - Items per page
 * @param {string} [params.search] - Search by username, email, or name
 * @param {string} [params.role] - Filter by role
 * @param {string} [params.status] - Filter by status
 * @returns {Promise<Object>} API response with user data and pagination
 */


value00: src/lib/api/valuesets.js
value01:
export async function fetchValueSetByKey(key) {
  return get(`/api/valueset/${encodeURIComponent(key)}`);
}

/**
 * Fetch value set items
 * @param {Object} params - Query parameters
 * @param {string} [params.key] - Filter by value set key
 * @returns {Promise<{status: string, data: Array}>}
 */
export async function fetchValueSetItems(params = {}) {
  const queryParams = new URLSearchParams();
  
  if (params.key) {
    queryParams.append('key', params.key);
  }
  
  const query = queryParams.toString();
  const endpoint = query ? `/api/valueset/items?${query}` : '/api/valueset/items';
  
  return get(endpoint);
}


value00: src/lib/api/valuesets.js
value01:
/**
 * Refresh value sets cache on the server
 * @param {Object} params - Request parameters
 * @param {string} [params.key] - Specific value set key to refresh (optional)
 * @returns {Promise<{status: string, message: string}>}
 */
export async function refreshValueSets(params = {}) {
  const { post } = await import('./client.js');
  return post('/api/valueset', params);
}

/**
 * Fetch a single value set item by ID
 * @param {number} itemId - Item ID
 * @returns {Promise<{status: string, data: Object}>}
 */
export async function fetchValueSetItemById(itemId) {
  return get(`/api/valueset/items/${itemId}`);
}


value00: src/lib/api/valuesets.js
value01:
/**
 * Fetch a single value set by its key (includes items)
 * @param {string} key - Value set key (e.g., 'GENDER', 'MARITAL_STATUS')
 * @returns {Promise<{status: string, data: Object}>}
 */
export async function fetchValueSetByKey(key) {
  return get(`/api/valueset/${encodeURIComponent(key)}`);
}


value00: src/lib/api/valuesets.js
value01:
import { get } from './client.js';

/**
 * ValueSets API endpoints
 * System ValueSets are read-only lookup values used throughout the application
 */

/**
 * Fetch list of value set definitions
 * @param {Object} params - Query parameters
 * @param {string} [params.key] - Filter by value set key
 * @returns {Promise<{status: string, data: Array}>}
 */
export async function fetchValueSets(params = {}) {
  const queryParams = new URLSearchParams();
  
  if (params.key) {
    queryParams.append('key', params.key);
  }
  
  const query = queryParams.toString();
  const endpoint = query ? `/api/valueset?${query}` : '/api/valueset';
  
  return get(endpoint);
}


value00: src/lib/api/visits.js
value01:
import { get, post, patch, del } from './client.js';

export async function fetchVisits(params = {}) {
  const query = new URLSearchParams(params).toString();
  return get(query ? `/api/patvisit?${query}` : '/api/patvisit');
}

export async function fetchVisit(id) {
  return get(`/api/patvisit/${encodeURIComponent(id)}`);
}

export async function fetchVisitsByPatient(patientId) {
  return get(`/api/patvisit/patient/${encodeURIComponent(patientId)}`);
}

export async function createVisit(data) {
  return post('/api/patvisit', data);
}

export async function updateVisit(id, data) {
  return patch(`/api/patvisit/${encodeURIComponent(id)}`, data);
}

export async function deleteVisit(id) {
  return del('/api/patvisit', { body: JSON.stringify({ InternalPVID: id }) });
}


value00: src/lib/api/visits.js
value01:
export async function createADT(data) {
  return post('/api/patvisitadt', data);
}

export async function updateADT(id, data) {
  return patch(`/api/patvisitadt/${encodeURIComponent(id)}`, data);
}

export async function fetchVisitADTHistory(visitId) {
  return get(`/api/patvisitadt/visit/${encodeURIComponent(visitId)}`);
}


value00: src/lib/stores/auth.js
value01:
    logout: () => {
      set({ user: null, isAuthenticated: false, loading: false });
    },

    /**
     * Update user data without changing auth status
     * @param {Object} user - Updated user object
     */
    setUser: (user) => {
      update((state) => ({ ...state, user }));
    },

    /**
     * Check if user is authenticated via cookie
     * @returns {Promise<boolean>}
     */
    checkAuth: async () => {
      if (!browser) return false;
      
      try {
        const response = await get('/api/auth/check');
        
        // Backend returns user data nested under response.data
        const userData = response.data || response;


value00: src/lib/stores/auth.js
value01:
        // Backend returns user data nested under response.data
        const userData = response.data || response;
        if (response.status === 'success' && userData.userid) {
          const user = {
            id: userData.userid,
            username: userData.username,
            name: userData.NameFirst && userData.NameLast 
              ? `${userData.NameFirst} ${userData.NameLast}` 
              : userData.username,
            ...userData
          };
          set({ user, isAuthenticated: true, loading: false });
          return true;
        } else {
          set({ user: null, isAuthenticated: false, loading: false });
          return false;
        }


value00: src/lib/stores/auth.js
value01:
        } else {
          set({ user: null, isAuthenticated: false, loading: false });
          return false;
        }
      } catch (error) {
        console.error('Auth check failed:', error.message);
        set({ user: null, isAuthenticated: false, loading: false });
        return false;
      }
    },

    /**
     * Set loading state
     * @param {boolean} loading
     */
    setLoading: (loading) => {
      update((state) => ({ ...state, loading }));
    },
  };
}

export const auth = createAuthStore();


value00: src/lib/stores/auth.js
value01:
import { writable } from 'svelte/store';
import { browser } from '$app/environment';
import { get } from '$lib/api/client.js';

/**
 * Create auth store with cookie-based authentication
 */
function createAuthStore() {
  const { subscribe, set, update } = writable({
    user: null,
    isAuthenticated: false,
    loading: true,
  });

  return {
    subscribe,

    /**
     * Set user data after successful login
     * Token is stored in HTTP-only cookie by backend
     * @param {Object} user - User object
     */
    login: (user) => {
      set({ user, isAuthenticated: true, loading: false });
    },

    /**
     * Clear authentication data on logout
     */
    logout: () => {
      set({ user: null, isAuthenticated: false, loading: false });
    }


value00: src/lib/stores/config.js
value01:
import { writable } from 'svelte/store';
import { browser } from '$app/environment';

/**
 * Create config store with runtime configuration
 */
function createConfigStore() {
  const { subscribe, set, update } = writable({
    apiUrl: '',
    loaded: false,
    error: null,
  });

  return {
    subscribe,

    /**
     * Load configuration from config.json or env variables
     */
    load: async () => {
      if (!browser) return;

      try {
        const response = await fetch('/config.json');
        if (!response.ok) {
          throw new Error(`Failed to load config: ${response.status}`);
        }
        const config = await response.json();
        set({
          apiUrl: config.apiUrl || '',
          loaded: true,
          error: null,
        });
      }


value00: src/lib/stores/config.js
value01:
      } catch (err) {
        // Fallback to env variable if config.json not found
        const envApiUrl = import.meta.env.VITE_API_URL;
        if (envApiUrl) {
          set({
            apiUrl: envApiUrl,
            loaded: true,
            error: null,
          });
        } else {
          console.error('Failed to load config:', err);
          set({
            apiUrl: '',
            loaded: true,
            error: err.message,
          });
        }
      }
    },

    /**
     * Get current API URL
     * @returns {string}
     */
    getApiUrl: () => {
      let url = '';
      subscribe((config) => {
        url = config.apiUrl;
      })();
      return url;
    },
  };
}

export const config = createConfigStore();


value00: src/lib/stores/valuesets.js
value01:
            return items;
          } else {
            throw new Error(response.message || 'Failed to load value set');
          }
        } catch (err) {
          const errorMessage = err.message || `Failed to load value set: ${key}`;
          console.error('valuesets: error for', key, ':', err);
          
          update((cache) => ({
            ...cache,
            [key]: { items: [], loaded: false, loading: false, error: errorMessage },
          }));
          
          toastError(errorMessage);
          return [];
        } finally {
          inflightRequests.delete(key);
        }
      })();

      inflightRequests.set(key, fetchPromise);
      return fetchPromise;
    },


value00: src/lib/stores/valuesets.js
value01:
      if (inflightRequests.has(key)) {
        return inflightRequests.get(key);
      }

      // Check if already loaded in cache
      let cacheState = null;
      subscribe((state) => { cacheState = state; })();
      
      if (cacheState?.[key]?.loaded) {
        return cacheState[key].items;
      }

      // Create the fetch promise
      const fetchPromise = (async () => {
        // Mark as loading
        update((cache) => ({
          ...cache,
          [key]: { items: [], loaded: false, loading: true, error: null },
        }));

        try {
          const response = await fetchValueSetByKey(key);
          
          if (response.status === 'success' && response.data)


value00: src/lib/stores/valuesets.js
value01:
          const response = await fetchValueSetByKey(key);
          
          if (response.status === 'success' && response.data) {
            // Handle both response.data being an array or having an Items property
            let items = Array.isArray(response.data) ? response.data : (response.data.Items || []);
            
            // Sort by Sequence if available
            items.sort((a, b) => (a.Sequence || 0) - (b.Sequence || 0));
            
            update((cache) => ({
              ...cache,
              [key]: { items, loaded: true, loading: false, error: null },
            }));
            
            return items;
          } else {
            throw new Error(response.message || 'Failed to load value set');
          }


value00: src/lib/stores/valuesets.js
value01:
    /**
     * Get value set items (load if needed)
     * @param {string} key - Value set key
     * @returns {Promise<Array>}
     */
    async get(key) {
      return this.load(key);
    },

    /**
     * Get value set items synchronously (returns cached data or empty array)
     * @param {string} key - Value set key
     * @returns {Array}
     */
    getSync(key) {
      let items = [];
      subscribe((cache) => {
        items = cache[key]?.items || [];
      })();
      return items;
    },

    /**
     * Check if value set is loaded
     * @param {string} key - Value set key
     * @returns {boolean}
     */


value00: src/lib/stores/valuesets.js
value01:
    async reload(key) {
      this.clearKey(key);
      return this.load(key);
    },
  };
}

export const valueSets = createValueSetsStore();

/**
 * Derived store to get all loaded value set keys
 */
export const loadedValueSetKeys = derived(valueSets, ($valueSets) => {
  return Object.keys($valueSets).filter((key) => $valueSets[key].loaded);
});

/**
 * Create a derived store for a specific value set
 * @param {string} key - Value set key
 * @returns {import('svelte/store').Readable}
 */
export function getValueSetStore(key) {
  return derived(valueSets, ($valueSets) => {
    return $valueSets[key] || { items: [], loaded: false, loading: false, error: null };
  });
}


value00: src/lib/stores/valuesets.js
value01:
    /**
     * Check if value set is loaded
     * @param {string} key - Value set key
     * @returns {boolean}
     */
    isLoaded(key) {
      let loaded = false;
      subscribe((cache) => {
        loaded = cache[key]?.loaded || false;
      })();
      return loaded;
    },

    /**
     * Check if value set is loading
     * @param {string} key - Value set key
     * @returns {boolean}
     */
    isLoading(key) {
      let loading = false;
      subscribe((cache) => {
        loading = cache[key]?.loading || false;
      })();
      return loading;
    },

    /**
     * Clear all cached value sets
     */
    clear() {
      set({});
    },

    /**
     * Clear a specific value set from cache
     * @param {string} key - Value set key
     */


value00: src/lib/stores/valuesets.js
value01:
    /**
     * Clear a specific value set from cache
     * @param {string} key - Value set key
     */
    clearKey(key) {
      update((cache) => {
        const newCache = { ...cache };
        delete newCache[key];
        return newCache;
      });
    },

    /**
     * Reload a value set (clear cache and fetch fresh)
     * @param {string} key - Value set key
     * @returns {Promise<Array>}
     */
    async reload(key) {
      this.clearKey(key);
      return this.load(key);
    },


value00: src/lib/stores/valuesets.js
value01:
// Store structure: { [key]: { items: [], loaded: boolean, loading: boolean, error: string|null } }
function createValueSetsStore() {
  const { subscribe, set, update } = writable({});
  
  // Keep track of in-flight requests to prevent duplicates
  const inflightRequests = new Map();

  return {
    subscribe,

    /**
     * Load a value set by key (fetch if not in cache)
     * @param {string} key - Value set key
     * @returns {Promise<Array>} - Array of value set items
     */
    async load(key) {
      // If there's already an in-flight request, return its promise
      if (inflightRequests.has(key)) {
        return inflightRequests.get(key);
      }


value00: src/lib/stores/valuesets.js
value01:
import { writable, derived } from 'svelte/store';
import { fetchValueSetByKey } from '$lib/api/valuesets.js';
import { error as toastError } from '$lib/utils/toast.js';

/**
 * ValueSets store - in-memory cache for system ValueSets
 * Note: Backend handles caching, this is just for reducing API calls during session
 */

// Store structure: { [key]: { items: [], loaded: boolean, loading: boolean, error: string|null } }


value00: docs/calculator-operators.md
value01:
## API Endpoints

All endpoints live under `/api` and accept JSON. Responses use the standard `{ status, message, data }` envelope unless stated otherwise.

### Calculate By Test Site

Uses the `testdefcal` definition for a test site. The incoming JSON body supplies the variables required by the formula.

```http
POST /api/calc/testsite/123
Content-Type: application/json

{
  "result": 85,
  "gender": "female",
  "age": 30
}
```

Response:

```json
{
  "status": "success",
  "data": {
    "result": 92.4,
    "testSiteID": 123,
    "formula": "{result} * {factor} + {age}",
    "variables": {
      "result": 85,
      "gender": "female",
      "age": 30
    }
  }
}
```


value00: docs/calculator-operators.md
value01:
## Supported Operators

### Arithmetic Operators

| Operator | Description | Example | Result |
|----------|-------------|---------|--------|
| `+` | Addition | `5 + 3` | `8` |
| `-` | Subtraction | `10 - 4` | `6` |
| `*` | Multiplication | `6 * 7` | `42` |
| `/` | Division | `20 / 4` | `5` |
| `^` | Exponentiation (power) | `2 ^ 3` | `8` |
| `!` | Factorial | `5!` | `120` |
| `!!` | Semi-factorial (double factorial) | `5!!` | `15` |

### Parentheses

Use parentheses to control operation precedence:

```
(2 + 3) * 4   // Result: 20
2 + 3 * 4     // Result: 14
```

---


value00: docs/calculator-operators.md
value01:
## Implicit Multiplication

The parser supports implicit multiplication (no explicit `*` operator needed):

| Expression | Parsed As | Result (x=2, y=3) |
|------------|-----------|-------------------|
| `2x` | `2 * x` | `4` |
| `x sin(x)` | `x * sin(x)` | `1.818...` |
| `2xy` | `2 * x * y` | `12` |
| `x^2y` | `x^2 * y` | `12` |

**Note:** Implicit multiplication has the same precedence as explicit multiplication. `xy^2z` is parsed as `x*y^2*z`, NOT as `x*y^(2*z)`.

---


value00: docs/calculator-operators.md
value01:
### Inverse Trigonometric Functions

| Function | Aliases | Description | Example |
|----------|---------|-------------|---------|
| `arcsin(x)` | `asin(x)` | Inverse sine | `arcsin(0.5)` → `0.523...` |
| `arccos(x)` | `acos(x)` | Inverse cosine | `arccos(0.5)` → `1.047...` |
| `arctan(x)` | `atan(x)` | Inverse tangent | `arctan(1)` → `0.785...` |
| `arccot(x)` | `acot(x)` | Inverse cotangent | `arccot(1)` → `0.785...` |


value00: docs/calculator-operators.md
value01:
### Trigonometric Functions (Degrees)

| Function | Description | Example |
|----------|-------------|---------|
| `sind(x)` | Sine (degrees) | `sind(90)` → `1` |
| `cosd(x)` | Cosine (degrees) | `cosd(0)` → `1` |
| `tand(x)` | Tangent (degrees) | `tand(45)` → `1` |
| `cotd(x)` | Cotangent (degrees) | `cotd(45)` → `1` |

### Hyperbolic Functions

| Function | Description | Example |
|----------|-------------|---------|
| `sinh(x)` | Hyperbolic sine | `sinh(1)` → `1.175...` |
| `cosh(x)` | Hyperbolic cosine | `cosh(1)` → `1.543...` |
| `tanh(x)` | Hyperbolic tangent | `tanh(1)` → `0.761...` |
| `coth(x)` | Hyperbolic cotangent | `coth(2)` → `1.037...` |


value00: docs/calculator-operators.md
value01:
### Logarithmic & Exponential Functions

| Function | Aliases | Description | Example |
|----------|---------|-------------|---------|
| `exp(x)` | - | Exponential (e^x) | `exp(2)` → `7.389...` |
| `log(x)` | `ln(x)` | Natural logarithm (base e) | `log(e)` → `1` |
| `log10(x)` | `lg(x)` | Logarithm base 10 | `log10(100)` → `2` |

---


value00: docs/calculator-operators.md
value01:
## Error Handling

The service throws exceptions for invalid formulas or missing variables:

```php
try {
    $result = $calculator->calculate("{result} / 0");
} catch (\Exception $e) {
    // Handle division by zero or other errors
    log_message('error', $e->getMessage());
}
```

Common errors:

- **Invalid formula syntax**: Malformed expressions
- **Missing variable**: Variable placeholder not provided in data array
- **Non-numeric value**: Variables must be numeric
- **Division by zero**: Mathematical error

---


value00: docs/calculator-operators.md
value01:
# Calculator Service Operators Reference

## Overview

The `CalculatorService` (`app/Services/CalculatorService.php`) uses the [mossadal/math-parser](https://github.com/mossadal/math-parser) library to safely evaluate mathematical expressions. This document lists all available operators, functions, and constants.

---


value00: docs/calculator-operators.md
value01:
## Formula Validation

Validate formulas before storing them:

```php
$validation = $calculator->validate("{result} / {factor}");
// Returns: ['valid' => true, 'error' => null]

$validation = $calculator->validate("{result} /");
// Returns: ['valid' => false, 'error' => 'Error message']
```

### Extract Variables

Get a list of variables used in a formula:

```php
$variables = $calculator->extractVariables("{result} * {factor} + {age}");
// Returns: ['result', 'factor', 'age']
```

---


value00: docs/calculator-operators.md
value01:
## Constants

| Constant | Value | Description | Example |
|----------|-------|-------------|---------|
| `pi` | 3.14159265... | Ratio of circle circumference to diameter | `pi * r ^ 2` |
| `e` | 2.71828182... | Euler's number | `e ^ x` |
| `NAN` | Not a Number | Invalid mathematical result | - |
| `INF` | Infinity | Positive infinity | - |

---


value00: docs/calculator-operators.md
value01:
### BMI Calculation

```php
$formula = "{weight} / ({height} ^ 2)";
$variables = [
    'weight' => 70,   // kg
    'height' => 1.75  // meters
];

$result = $calculator->calculate($formula, $variables);
// Result: 22.86
```

### Gender-Based Calculation

```php
// Apply different multipliers based on gender
$formula = "{result} * (1 + 0.1 * {gender})";
$variables = [
    'result' => 100,
    'gender' => 1  // Female = 1
];

$result = $calculator->calculate($formula, $variables);
// Result: 110
```

### Complex Formula

```php
// Pythagorean theorem with rounding
$formula = "round(sqrt({a} ^ 2 + {b} ^ 2))";
$variables = [
    'a' => 3,
    'b' => 4
];

$result = $calculator->calculate($formula, $variables);
// Result: 5
```


value00: docs/calculator-operators.md
value01:
## Usage Examples

### Basic Calculation

```php
use App\Services\CalculatorService;

$calculator = new CalculatorService();

// Simple arithmetic
$result = $calculator->calculate("5 + 3 * 2");
// Result: 11

// Using functions
$result = $calculator->calculate("sqrt(16) + abs(-5)");
// Result: 9

// Using constants
$result = $calculator->calculate("2 * pi * r", ['r' => 5]);
// Result: 31.415...
```

### With Variables

```php
$formula = "{result} * {factor} + 10";
$variables = [
    'result' => 5.2,
    'factor' => 2
];

$result = $calculator->calculate($formula, $variables);
// Result: 20.4
```


value00: docs/calculator-operators.md
value01:
### Calculate By Code Or Name

Evaluates a configured calculation by `TestSiteCode` or `TestSiteName`. Returns a compact map with a single key/value or `{}` on failure.

```http
POST /api/calc/testcode/GLU
Content-Type: application/json

{
  "result": 110,
  "factor": 1.1
}
```

Response:

```json
{
  "GLU": 121
}
```

---


value00: docs/calculator-operators.md
value01:
### Inverse Hyperbolic Functions

| Function | Aliases | Description | Example |
|----------|---------|-------------|---------|
| `arsinh(x)` | `asinh(x)`, `arcsinh(x)` | Inverse hyperbolic sine | `arsinh(1)` → `0.881...` |
| `arcosh(x)` | `acosh(x)`, `arccosh(x)` | Inverse hyperbolic cosine | `arcosh(2)` → `1.316...` |
| `artanh(x)` | `atanh(x)`, `arctanh(x)` | Inverse hyperbolic tangent | `artanh(0.5)` → `0.549...` |
| `arcoth(x)` | `acoth(x)`, `arccoth(x)` | Inverse hyperbolic cotangent | `arcoth(2)` → `0.549...` |


value00: src/lib/utils/patients.js
value01:
/**
 * Format sex display
 * @param {Object} patient - Patient object
 * @param {string} [patient.SexLabel] - Sex label
 * @param {string} [patient.Sex] - Sex code (1=Female, 2=Male)
 * @returns {string} Formatted sex
 */
export function formatSex(patient) {
  if (!patient) return '-';
  if (patient.SexLabel) return patient.SexLabel;
  if (patient.Sex === '1') return 'Female';
  if (patient.Sex === '2') return 'Male';
  return '-';
}

/**
 * Format date for display
 * @param {string} dateStr - ISO date string
 * @returns {string} Formatted date
 */


value00: src/lib/utils/barcode.js
value01:
            justify-content: center;
            font-size: 10px;
            color: #666;
            margin-bottom: 2mm;
          }
          .order-info { font-size: 11px; margin-bottom: 1mm; }
          .patient-info { font-size: 10px; color: #333; margin-bottom: 1mm; }
          .test-codes { 
            font-size: 9px; 
            color: #666; 
            border-top: 1px solid #ddd;
            padding-top: 1mm;
            margin-top: 2mm;
          }
          .date-info { font-size: 9px; color: #999; margin-top: 2mm; }
        }
        @media screen {
          body { background: #f5f5f5; padding: 20px; }
          .label { background: white; margin: 20px auto; }


value00: src/lib/utils/barcode.js
value01:
/**
 * Barcode printing utility functions
 * Provides structure for patient wristbands and specimen labels
 * Note: Full barcode generation to be implemented with library integration
 */

/**
 * Print patient wristband with barcode
 * @param {Object} patient - Patient data
 * @param {string} patient.PatientID - Patient identifier
 * @param {string} patient.NameFirst - First name
 * @param {string} patient.NameLast - Last name
 * @param {string} patient.Birthdate - Birthdate
 * @param {string} patient.Sex - Sex (1=Female, 2=Male)
 */


value00: src/lib/utils/patients.js
value01:
/**
 * Patient and Order utility functions for LIS
 * @module $lib/utils/patients
 */

/**
 * Format patient name from components
 * @param {Object} patient - Patient object
 * @param {string} [patient.Prefix] - Name prefix
 * @param {string} [patient.NameFirst] - First name
 * @param {string} [patient.NameMiddle] - Middle name
 * @param {string} [patient.NameLast] - Last name
 * @param {string} [patient.FullName] - Pre-formatted full name
 * @returns {string} Formatted full name
 */
export function formatPatientName(patient) {
  if (!patient) return '-';
  if (patient.FullName) return patient.FullName;
  return [
    patient.Prefix,
    patient.NameFirst,
    patient.NameMiddle,
    patient.NameLast
  ].filter(Boolean).join(' ') || '-';
}


value00: src/lib/utils/barcode.js
value01:
</title>
      <style>
        @media print {
          body { margin: 0; padding: 10mm; font-family: Arial, sans-serif; }
          .wristband { 
            width: 250mm; 
            height: 25mm; 
            border: 2px solid #000; 
            padding: 3mm;
            box-sizing: border-box;
            display: flex;
            align-items: center;
            gap: 5mm;
          }
          .barcode-placeholder {
            width: 80mm;
            height: 18mm;
            background: #f0f0f0;
            border: 1px dashed #999;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 10px;
            color: #666;


value00: docs/llms_daisyui.txt
value01:
7. Ideally, you won't need to write any custom CSS. Using daisyUI class names or Tailwind CSS utility classes is preferred.
8. suggested - if you need placeholder images, use https://picsum.photos/200/300 with the size you want
9. suggested - when designing , don't add a custom font unless it's necessary
10. don't add `bg-base-100 text-base-content` to body unless it's necessary
11. For design decisions, use Refactoring UI book best practices


value00: src/lib/utils/barcode.js
value01:
            align-items: center;
            justify-content: center;
            font-size: 10px;
            color: #666;
          }
          .patient-info { flex: 1; }
          .patient-id { font-size: 14px; font-weight: bold; }
          .patient-name { font-size: 12px; margin-top: 2mm; }
          .patient-details { font-size: 10px; color: #666; margin-top: 1mm; }
        }
        @media screen {
          body { background: #f5f5f5; padding: 20px; }
          .wristband { background: white; margin: 20px auto; }
        }
      </style>
    </head>
    <body>
      <div class="wristband">
        <div class="barcode-placeholder">
          [BARCODE]<br>


value00: src/lib/utils/barcode.js
value01:
</title>
      <style>
        @media print {
          body { margin: 0; padding: 5mm; font-family: Arial, sans-serif; }
          .label { 
            width: 100mm; 
            height: 60mm; 
            border: 1px solid #000; 
            padding: 3mm;
            box-sizing: border-box;
          }
          .barcode-placeholder {
            width: 94mm;
            height: 20mm;
            background: #f0f0f0;
            border: 1px dashed #999;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 10px;
            color: #666;
            margin-bottom: 2mm;


value00: src/lib/utils/barcode.js
value01:
${patient.PatientID}
        </div>
        <div class="patient-info">
          <div class="patient-id">${patient.PatientID}</div>
          <div class="patient-name">${patientName}</div>
          <div class="patient-details">DOB: ${birthdate} | Sex: ${sexLabel}</div>
        </div>
      </div>
      <script>
        window.onload = function() { window.print(); };
      <\/script>
    </body>
    </html>
  `;

  const printWindow = window.open('', '_blank', 'width=800,height=400');
  if (printWindow) {
    printWindow.document.write(printContent);
    printWindow.document.close();
  } else {
    console.error('Failed to open print window - popup blocker may be enabled');
  }
}


value00: src/lib/utils/barcode.js
value01:
export function printSpecimenLabel(order) {
  if (!order?.OrderID) {
    console.warn('Cannot print label: Missing order ID');
    return;
  }

  const orderDate = order.OrderDate 
    ? new Date(order.OrderDate).toLocaleDateString('en-US')
    : new Date().toLocaleDateString('en-US');
  
  const testCodes = order.Tests?.map(t => t.TestSiteID || t.TestID).join(', ') || 'N/A';
  const patientName = order.PatientName || 'Unknown';
  const patientId = order.PatientID || order.InternalPID || 'N/A';

  const printContent = `
    <!DOCTYPE html>
    <html>
    <head>
      <title>Specimen Label - ${order.OrderNumber || order.OrderID}</title>
      <style>
        @media print {
          body { margin: 0; padding: 5mm; font-family: Arial, sans-serif; }


value00: src/lib/utils/barcode.js
value01:
        @media screen {
          body { background: #f5f5f5; padding: 20px; }
          .label { background: white; margin: 20px auto; }
        }
      </style>
    </head>
    <body>
      <div class="label">
        <div class="barcode-placeholder">
          [BARCODE]<br>


value00: docs/llms_daisyui.txt
value01:
[fab docs](https://daisyui.com/components/fab/)

#### Class names
- component: `fab`
- part: `fab-close`, `fab-main-action`
- modifier: `fab-flower`

#### Syntax
A single FAB in the corder of screen
```html
<div class="fab">
  <button class="btn btn-lg btn-circle">{IconOriginal}</button>
</div>
```
A FAB that opens a 3 other buttons in the corner of page vertically
```html
<div class="fab">
  <div tabindex="0" role="button" class="btn btn-lg btn-circle btn-primary">{IconOriginal}</div>
  <button class="btn btn-lg btn-circle">{Icon1}</button>
  <button class="btn btn-lg btn-circle">{Icon2}</button>
  <button class="btn btn-lg btn-circle">{Icon3}</button>
</div>


value00: docs/llms_daisyui.txt
value01:
### modal
Modal is used to show a dialog or a box when you click a button

[modal docs](https://daisyui.com/components/modal/)

#### Class names
- component: `modal`
- part: `modal-box`, `modal-action`, `modal-backdrop`, `modal-toggle`
- modifier: `modal-open`
- placement: `modal-top`, `modal-middle`, `modal-bottom`, `modal-start`, `modal-end`

#### Syntax
Using HTML dialog element
```html
<button onclick="my_modal.showModal()">Open modal</button>
<dialog id="my_modal" class="modal">
  <div class="modal-box">{CONTENT}</div>
  <form method="dialog" class="modal-backdrop"><button>close</button></form>
</dialog>
```


value00: docs/llms_daisyui.txt
value01:
daisyUI 5 class names are one of the following categories. These type names are only for reference and are not used in the actual code
- `component`: the required component class
- `part`: a child part of a component
- `style`: sets a specific style to component or part
- `behavior`: changes the behavior of component or part
- `color`: sets a specific color to component or part
- `size`: sets a specific size to component or part
- `placement`: sets a specific placement to component or part
- `direction`: sets a specific direction to component or part
- `modifier`: modifies the component or part in a specific way
- `variant`: prefixes for utility classes that conditionally apply styles. syntax is `variant:utility-class`


value00: docs/calculator-operators.md
value01:
## Best Practices

1. **Always validate formulas** before storing in database
2. **Use placeholder syntax** `{variable_name}` for clarity
3. **Handle exceptions** in production code
4. **Test edge cases** like zero values and boundary conditions
5. **Document formulas** with comments in your code

---

## References

- [math-parser GitHub](https://github.com/mossadal/math-parser)
- [math-parser Documentation](http://mossadal.github.io/math-parser/)
- `app/Services/CalculatorService.php`


value00: docs/llms_daisyui.txt
value01:
  --radius-selector: 1rem; /* border radius of selectors (checkbox, toggle, badge) */
  --radius-field: 0.25rem; /* border radius of fields (button, input, select, tab) */
  --radius-box: 0.5rem; /* border radius of boxes (card, modal, alert) */
  /* preferred values for --radius-* : 0rem, 0.25rem, 0.5rem, 1rem, 2rem */


value00: docs/llms_daisyui.txt
value01:
### footer
Footer can contain logo, copyright notice, and links to other pages

[footer docs](https://daisyui.com/components/footer/)

#### Class names
- component: `footer`
- part: `footer-title`
- placement: `footer-center`
- direction: `footer-horizontal`, `footer-vertical`

#### Syntax
```html
<footer class="footer {MODIFIER}">{CONTENT}</footer>
```
where content can contain several `<nav>` tags with `footer-title` and links inside

#### Rules
- {MODIFIER} is optional and can have one of each placement/direction class names
- try to use `sm:footer-horizontal` to make footer responsive
- suggestion - use `base-200` for background color

### hero
Hero is a component for displaying a large box or image with a title and description


value00: docs/llms_daisyui.txt
value01:
  </div>
  <div class="tooltip tooltip-left" data-tip="{Label3}">
    <button class="btn btn-lg btn-circle">{Icon3}</button>
  </div>
</div>
```
#### Rules
- {Icon*} should be replaced with the appropriate icon for each button. SVG icons are recommended
- {IconOriginal} is the icon that we see before opening the FAB
- {IconMainAction} is the icon we see after opening the FAB
- {Icon1}, {Icon2}, {Icon3} are the icons for the additional buttons
- {Label*} is the label text for each button


value00: docs/llms_daisyui.txt
value01:
daisyUI without config:
```css
@plugin "daisyui";
```
daisyUI config with `light` theme only:
```css
@plugin "daisyui" {
  themes: light --default;
}
```
daisyUI with all the default configs:
```css
@plugin "daisyui" {
  themes: light --default, dark --prefersdark;
  root: ":root";
  include: ;
  exclude: ;
  prefix: ;
  logs: true;
}
```
An example config:
In below config, all the built-in themes are enabled while bumblebee is the default theme and synthwave is the prefersdark theme (default dark mode)
All the other themes are enabled and can be used by adding `data-theme="THEME_NAME"` to the `<html>` element
root scrollbar gutter is excluded. `daisy-` prefix is used for all daisyUI classes and console.log is disabled
```css
@plugin "daisyui" {


value00: docs/llms_daisyui.txt
value01:
### collapse
Collapse is used for showing and hiding content

[collapse docs](https://daisyui.com/components/collapse/)

#### Class names
- component: `collapse`
- part: `collapse-title`, `collapse-content`
- modifier: `collapse-arrow`, `collapse-plus`, `collapse-open`, `collapse-close`

#### Syntax
```html
<div tabindex="0" class="collapse {MODIFIER}">
  <div class="collapse-title">{title}</div>
  <div class="collapse-content">{CONTENT}</div>
</div>
```

#### Rules
- {MODIFIER} is optional and can have one of the modifier class names
- instead of `tabindex="0"`, you can use  `<input type="checkbox">` as a first child
- Can also be a details/summary tag

### countdown
Countdown gives you a transition effect when you change a number between 0 to 999


value00: docs/calculator-operators.md
value01:
## Variables in CalculatorService

When using `calculateFromDefinition()`, the following variables are automatically available:

| Variable | Description | Type |
|----------|-------------|------|
| `{result}` | The test result value | Float |
| `{factor}` | Calculation factor (default: 1) | Float |
| `{gender}` | Gender value (0=Unknown, 1=Female, 2=Male) | Integer |
| `{age}` | Patient age | Float |
| `{ref_low}` | Reference range low value | Float |
| `{ref_high}` | Reference range high value | Float |

### Gender Mapping

The `gender` variable accepts the following values:

| Value | Description |
|-------|-------------|
| `0` | Unknown |
| `1` | Female |
| `2` | Male |

Or use string values: `'unknown'`, `'female'`, `'male'`

---


value00: docs/llms_daisyui.txt
value01:
`hover-3d` works by placing 8 hover zones on top of the content. Each zone detects mouse movement and applies a slight rotation to the content based on the mouse position within that zone. The combined effect of all 8 zones creates a smooth and responsive 3D tilt effect as the user moves their mouse over the component.

Only use non-interactive content inside the `hover-3d` wrapper. If you want to make the entire card clickable, use a link for the whole `hover-3d` component instead of putting interactive elements like buttons or links inside it.

[hover-3d docs](https://daisyui.com/components/hover-3d/)

#### Class names
- component: `hover-3d`


value00: docs/calculator-operators.md
value01:
## Mathematical Functions

### Rounding Functions

| Function | Description | Example |
|----------|-------------|---------|
| `sqrt(x)` | Square root | `sqrt(16)` → `4` |
| `round(x)` | Round to nearest integer | `round(3.7)` → `4` |
| `ceil(x)` | Round up to integer | `ceil(3.2)` → `4` |
| `floor(x)` | Round down to integer | `floor(3.9)` → `3` |
| `abs(x)` | Absolute value | `abs(-5)` → `5` |
| `sgn(x)` | Sign function | `sgn(-10)` → `-1` |

### Trigonometric Functions (Radians)

| Function | Description | Example |
|----------|-------------|---------|
| `sin(x)` | Sine | `sin(pi/2)` → `1` |
| `cos(x)` | Cosine | `cos(0)` → `1` |
| `tan(x)` | Tangent | `tan(pi/4)` → `1` |
| `cot(x)` | Cotangent | `cot(pi/4)` → `1` |


value00: src/lib/utils/barcode.js
value01:
</div>
      </div>
      <script>
        window.onload = function() { window.print(); };
      <\/script>
    </body>
    </html>
  `;

  const printWindow = window.open('', '_blank', 'width=600,height=400');
  if (printWindow) {
    printWindow.document.write(printContent);
    printWindow.document.close();
  } else {
    console.error('Failed to open print window - popup blocker may be enabled');
  }
}

/**
 * Show coming soon message for barcode features
 * @param {string} feature - Feature name
 */
export function showBarcodeComingSoon(feature = 'Barcode printing') {
  // This is a placeholder for when full barcode library is integrated
  console.log(`${feature} - Full barcode generation coming soon`);
}


value00: docs/llms_daisyui.txt
value01:
### hero
Hero is a component for displaying a large box or image with a title and description

[hero docs](https://daisyui.com/components/hero/)

#### Class names
- component: `hero`
- part: `hero-content`, `hero-overlay`

#### Syntax
```html
<div class="hero {MODIFIER}">{CONTENT}</div>
```

#### Rules
- {MODIFIER} is optional
- Use `hero-content` for the text content
- Use `hero-overlay` inside the hero to overlay the background image with a color
- Content can contain a figure

### hover-3d
Hover 3D is a wrapper component that adds a 3D hover effect to its content. When we hover over the component, it tilts and rotates based on the mouse position, creating an interactive 3D effect


value00: docs/llms_daisyui.txt
value01:
### navbar
Navbar is used to show a navigation bar on the top of the page

[navbar docs](https://daisyui.com/components/navbar/)

#### Class names
- component: `navbar`
- part: `navbar-start`, `navbar-center`, `navbar-end`

#### Syntax
```html
<div class="navbar">{CONTENT}</div>
```

#### Rules
- use `navbar-start`, `navbar-center`, `navbar-end` to position content horizontally
- put anything inside each section
- suggestion - use `base-200` for background color

### pagination
Pagination is a group of buttons


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<input type="{type}" placeholder="Type here" class="input {MODIFIER}" />
```

#### Rules
- {MODIFIER} is optional and can have one of each style/color/size class names
- Can be used with any input field type (text, password, email, etc.)
- Use `input` class for the parent when you have more than one element inside input

### join
Join is a container for grouping multiple items, it can be used to group buttons, inputs, etc. Join applies border radius to the first and last item. Join can be used to create a horizontal or vertical list of items

[join docs](https://daisyui.com/components/join/)

#### Class names
- component: `join`, `join-item`
- direction: `join-vertical`, `join-horizontal`

#### Syntax
```html
<div class="join {MODIFIER}">{CONTENT}</div>
```


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<div class="join {MODIFIER}">{CONTENT}</div>
```

#### Rules
- {MODIFIER} is optional and can have one of the direction class names
- Any direct child of the join element will get joined together
- Any element with `join-item` will be affected
- Use `lg:join-horizontal` for responsive layouts

### kbd
Kbd is used to display keyboard shortcuts

[kbd docs](https://daisyui.com/components/kbd/)

#### Class names
- component: `kbd`
- size: `kbd-xs`, `kbd-sm`, `kbd-md`, `kbd-lg`, `kbd-xl`

#### Syntax
```html
<kbd class="kbd {MODIFIER}">K</kbd>
```


value00: src/lib/utils/barcode.js
value01:
${order.OrderNumber || order.OrderID}
        </div>
        <div class="order-info"><strong>Order:</strong> ${order.OrderNumber || order.OrderID}</div>
        <div class="patient-info"><strong>Patient:</strong> ${patientName} (${patientId})</div>
        <div class="test-codes"><strong>Tests:</strong> ${testCodes}</div>
        <div class="date-info">Collected: ${orderDate}</div>
      </div>
      <script>
        window.onload = function() { window.print(); };
      <\/script>
    </body>
    </html>


value00: docs/calculator-operators.md
value01:
### Using calculateFromDefinition

```php
$calcDef = [
    'FormulaCode' => '{result} * {factor} + {gender}',
    'Factor' => 2
];

$testValues = [
    'result' => 10,
    'gender' => 1  // Female
];

$result = $calculator->calculateFromDefinition($calcDef, $testValues);
// Result: 21 (10 * 2 + 1)
```

---


value00: docs/llms_daisyui.txt
value01:
    <!-- Page content here -->
    <label for="my-drawer-3" class="btn drawer-button lg:hidden">
      Open drawer
    </label>
  </div>
  <div class="drawer-side">
    <label for="my-drawer-3" aria-label="close sidebar" class="drawer-overlay"></label>
    <ul class="menu bg-base-200 min-h-full w-80 p-4">
      <!-- Sidebar content here -->
      <li><button>Sidebar Item 1</button></li>
      <li><button>Sidebar Item 2</button></li>
    </ul>
  </div>
</div>
```


value00: src/lib/utils/barcode.js
value01:
/**
 * Print specimen label with barcode
 * @param {Object} order - Order data
 * @param {string} order.OrderID - Order identifier
 * @param {string} order.OrderNumber - Order number
 * @param {string} order.PatientID - Patient ID
 * @param {string} order.PatientName - Patient name
 * @param {Array} order.Tests - Array of tests
 * @param {string} order.OrderDate - Order date
 */


value00: docs/llms_daisyui.txt
value01:
## Config
daisyUI 5 config docs: https://daisyui.com/docs/config/
daisyUI without config:
```css
@plugin "daisyui";
```
daisyUI config with `light` theme only:
```css
@plugin "daisyui" {
  themes: light --default;


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<ul class="list">
  <li class="list-row">{CONTENT}</li>
</ul>
```

#### Rules
- Use `list-row` for each item inside the list
- By default, the second child of the `list-row` will fill the remaining space. You can use `list-col-grow` on another child to make it fill the remaining space instead
- Use `list-col-wrap` to force an item to wrap to the next line

### loading
Loading shows an animation to indicate that something is loading


value00: docs/llms_daisyui.txt
value01:
#### Syntax
Vertical menu:
```html
<ul class="menu">
  <li><button>Item</button></li>
</ul>
```
Horizontal menu:
```html
<ul class="menu menu-horizontal">
  <li><button>Item</button></li>
</ul>
```

#### Rules
- {MODIFIER} is optional and can have one of the modifier/size/direction class names
- Use `lg:menu-horizontal` for responsive layouts
- Use `menu-title` for list item title
- Use `<details>` tag to make submenus collapsible
- Use `menu-dropdown` and `menu-dropdown-toggle` to toggle the dropdown using JS

### mockup-browser
Browser mockup shows a box that looks like a browser window

[mockup-browser docs](https://daisyui.com/components/mockup-browser/)

#### Class names
- component: `mockup-browser`
- part: `mockup-browser-toolbar`


value00: docs/llms_daisyui.txt
value01:
### button
Buttons allow the user to take actions

[button docs](https://daisyui.com/components/button/)

#### Class names
- component: `btn`
- color: `btn-neutral`, `btn-primary`, `btn-secondary`, `btn-accent`, `btn-info`, `btn-success`, `btn-warning`, `btn-error`
- style: `btn-outline`, `btn-dash`, `btn-soft`, `btn-ghost`, `btn-link`
- behavior: `btn-active`, `btn-disabled`
- size: `btn-xs`, `btn-sm`, `btn-md`, `btn-lg`, `btn-xl`
- modifier: `btn-wide`, `btn-block`, `btn-square`, `btn-circle`


value00: docs/llms_daisyui.txt
value01:
  <button class="btn btn-lg btn-circle">{Icon2}</button>
  <button class="btn btn-lg btn-circle">{Icon3}</button>
</div>
```
A FAB that opens a 3 other buttons in the corner of page vertically and they have label text
```html
<div class="fab">
  <div tabindex="0" role="button" class="btn btn-lg btn-circle btn-primary">{IconOriginal}</div>
  <div>{Label1}<button class="btn btn-lg btn-circle">{Icon1}</button></div>
  <div>{Label2}<button class="btn btn-lg btn-circle">{Icon2}</button></div>
  <div>{Label3}<button class="btn btn-lg btn-circle">{Icon3}</button></div>
</div>
```
FAB with rectangle buttons. These are not circular buttons so they can have more content.
```html


value00: docs/llms_daisyui.txt
value01:
#### Class names
- component: `mockup-phone`
- part: `mockup-phone-camera`, `mockup-phone-display`

#### Syntax
```html
<div class="mockup-phone">
  <div class="mockup-phone-camera"></div>
  <div class="mockup-phone-display">{CONTENT}</div>
</div>
```

#### Rules
- Inside `mockup-phone-display` you can add anything

### mockup-window
Window mockup shows a box that looks like an operating system window

[mockup-window docs](https://daisyui.com/components/mockup-window/)

#### Class names
- component: `mockup-window`

#### Syntax
```html
<div class="mockup-window">
  <div>{CONTENT}</div>
</div>
```

### modal
Modal is used to show a dialog or a box when you click a button

[modal docs](https://daisyui.com/components/modal/)


value00: docs/llms_daisyui.txt
value01:
[countdown docs](https://daisyui.com/components/countdown/)

#### Class names
- component: `countdown`

#### Syntax
```html
<span class="countdown">
  <span style="--value:{number};">number</span>
</span>
```

#### Rules
- The `--value` CSS variable and text must be a number between 0 and 999
- you need to change the span text and the `--value` CSS variable using JS
- you need to add `aria-live="polite"` and `aria-label="{number}"` so screen readers can properly read changes

### diff
Diff component shows a side-by-side comparison of two items

[diff docs](https://daisyui.com/components/diff/)

#### Class names
- component: `diff`
- part: `diff-item-1`, `diff-item-2`, `diff-resizer`


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<div class="stats {MODIFIER}">
  <div class="stat">{CONTENT}</div>
</div>
```

#### Rules
- {MODIFIER} is optional and can have one of the direction class names
- It's horizontal by default but you can make it vertical with the `stats-vertical` class
- Content includes `stat-title`, `stat-value`, `stat-desc` inside a `stat`

### status
Status is a really small icon to visually show the current status of an element, like online, offline, error, etc

[status docs](https://daisyui.com/components/status/)


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<div class="stack {MODIFIER}">{CONTENT}</div>
```

#### Rules
- {MODIFIER} is optional and can have one of the modifier class names
- You can use `w-*` and `h-*` classes to set the width and height of the stack, making all items the same size

### stat
Stat is used to show numbers and data in a block

[stat docs](https://daisyui.com/components/stat/)

#### Class names
- Component: `stats`
- Part: `stat`, `stat-title`, `stat-value`, `stat-desc`, `stat-figure`, `stat-actions`
- Direction: `stats-horizontal`, `stats-vertical`

#### Syntax
```html
<div class="stats {MODIFIER}">
  <div class="stat">{CONTENT}</div>
</div>
```


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<ul class="steps {MODIFIER}">
  <li class="step">{step content}</li>
</ul>
```

#### Rules
- {MODIFIER} is optional and can have one of each direction/color class names
- To make a step active, add the `step-primary` class
- You can add an icon in each step using `step-icon` class
- To display data in `data-content` ,use `data-content="{value}"` at the `<li>`

### swap
Swap allows you to toggle the visibility of two elements using a checkbox or a class name

[swap docs](https://daisyui.com/components/swap/)

#### Class Names:
- Component: `swap`
- Part: `swap-on`, `swap-off`, `swap-indeterminate`
- Modifier: `swap-active`
- Style: `swap-rotate`, `swap-flip`


value00: docs/llms_daisyui.txt
value01:
### select
Select is used to pick a value from a list of options

[select docs](https://daisyui.com/components/select/)

#### Class names
- component: `select`
- style: `select-ghost`
- color: `select-neutral`, `select-primary`, `select-secondary`, `select-accent`, `select-info`, `select-success`, `select-warning`, `select-error`
- size: `select-xs`, `select-sm`, `select-md`, `select-lg`, `select-xl`

#### Syntax
```html
<select class="select {MODIFIER}">
  <option>Option</option>
</select>
```

#### Rules
- {MODIFIER} is optional and can have one of each style/color/size class names

### skeleton
Skeleton is a component that can be used to show a loading state


value00: docs/llms_daisyui.txt
value01:
### fieldset
Fieldset is a container for grouping related form elements. It includes fieldset-legend as a title and label as a description

[fieldset docs](https://daisyui.com/components/fieldset/)

#### Class names
- Component: `fieldset`, `label`
- Parts: `fieldset-legend`

#### Syntax
```html
<fieldset class="fieldset">
  <legend class="fieldset-legend">{title}</legend>
  {CONTENT}
  <p class="label">{description}</p>
</fieldset>
```

#### Rules
- You can use any element as a direct child of fieldset to add form elements

### file-input
File Input is a an input field for uploading files

[file-input docs](https://daisyui.com/components/file-input/)


value00: docs/llms_daisyui.txt
value01:
  --size-selector: 0.25rem; /* base size of selectors (checkbox, toggle, badge). Value must be 0.25rem unless we intentionally want bigger selectors. In so it can be 0.28125 or 0.3125. If we intentionally want smaller selectors, it can be 0.21875 or 0.1875 */
  --size-field: 0.25rem; /* base size of fields (button, input, select, tab). Value must be 0.25rem unless we intentionally want bigger fields. In so it can be 0.28125 or 0.3125. If we intentionally want smaller fields, it can be 0.21875 or 0.1875 */

  --border: 1px; /* border size. Value must be 1px unless we intentionally want thicker borders. In so it can be 1.5px or 2px. If we intentionally want thinner borders, it can be 0.5px */


value00: docs/llms_daisyui.txt
value01:
### daisyUI color names
- `primary`: Primary brand color, The main color of your brand
- `primary-content`: Foreground content color to use on primary color
- `secondary`: Secondary brand color, The optional, secondary color of your brand
- `secondary-content`: Foreground content color to use on secondary color
- `accent`: Accent brand color, The optional, accent color of your brand
- `accent-content`: Foreground content color to use on accent color
- `neutral`: Neutral dark color, For not-saturated parts of UI
- `neutral-content`: Foreground content color to use on neutral color
- `base-100`:-100 Base surface color of page, used for blank backgrounds
- `base-200`:-200 Base color, darker shade, to create elevations
- `base-300`:-300 Base color, even more darker shade, to create elevations


value00: docs/llms_daisyui.txt
value01:
[status docs](https://daisyui.com/components/status/)

#### Class Names:
- Component: `status`
- Color: `status-neutral`, `status-primary`, `status-secondary`, `status-accent`, `status-info`, `status-success`, `status-warning`, `status-error`
- Size: `status-xs`, `status-sm`, `status-md`, `status-lg`, `status-xl`

#### Syntax
```html
<span class="status {MODIFIER}"></span>
```

#### Rules
- {MODIFIER} is optional and can have one of the color/size class names
- This component does not render anything visible

### steps
Steps can be used to show a list of steps in a process

[steps docs](https://daisyui.com/components/steps/)


value00: src/lib/utils/patients.js
value01:
/**
 * Format date for display
 * @param {string} dateStr - ISO date string
 * @returns {string} Formatted date
 */
export function formatDate(dateStr) {
  if (!dateStr) return '-';
  try {
    return new Date(dateStr).toLocaleDateString();
  } catch {
    return '-';
  }
}

/**
 * Format datetime for display
 * @param {string} dateStr - ISO datetime string
 * @returns {string} Formatted datetime
 */


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<div class="mockup-code">
  <pre data-prefix="$"><code>npm i daisyui</code></pre>
</div>
```

#### Rules
- Use `<pre data-prefix="{prefix}">` to show a prefix before each line
- Use `<code>` tag to add code syntax highlighting (requires additional library)
- To highlight a line, add background/text color

### mockup-phone
Phone mockup shows a mockup of an iPhone

[mockup-phone docs](https://daisyui.com/components/mockup-phone/)

#### Class names
- component: `mockup-phone`
- part: `mockup-phone-camera`, `mockup-phone-display`


value00: docs/llms_daisyui.txt
value01:
Example: This sidebar is always visible. When it's close we only see iocns, when it's open we see icons and text
```html
<div class="drawer lg:drawer-open">
  <input id="my-drawer-4" type="checkbox" class="drawer-toggle" />
  <div class="drawer-content">
    <!-- Page content here -->


value00: src/lib/utils/barcode.js
value01:
export function printPatientWristband(patient) {
  if (!patient?.PatientID) {
    console.warn('Cannot print wristband: Missing patient ID');
    return;
  }

  const sexLabel = patient.Sex === '1' ? 'F' : patient.Sex === '2' ? 'M' : 'U';
  const birthdate = patient.Birthdate 
    ? new Date(patient.Birthdate).toLocaleDateString('en-US')
    : '-';
  
  const patientName = [patient.NameFirst, patient.NameLast]
    .filter(Boolean)
    .join(' ') || 'Unknown';

  const printContent = `
    <!DOCTYPE html>
    <html>
    <head>
      <title>Patient Wristband - ${patient.PatientID}</title>
      <style>
        @media print {
          body { margin: 0; padding: 10mm; font-family: Arial, sans-serif; }


value00: docs/llms_daisyui.txt
value01:
### input
Text Input is a simple input field

[input docs](https://daisyui.com/components/input/)

#### Class names
- component: `input`
- style: `input-ghost`
- color: `input-neutral`, `input-primary`, `input-secondary`, `input-accent`, `input-info`, `input-success`, `input-warning`, `input-error`
- size: `input-xs`, `input-sm`, `input-md`, `input-lg`, `input-xl`

#### Syntax
```html
<input type="{type}" placeholder="Type here" class="input {MODIFIER}" />
```


value00: docs/llms_daisyui.txt
value01:
            <span class="is-drawer-close:hidden">Homepage</span>
          </button>
        </li>
        <!-- list item -->
        <li>
          <button class="is-drawer-close:tooltip is-drawer-close:tooltip-right" data-tip="Settings">
            ⚙️
            <span class="is-drawer-close:hidden">Settings</span>
          </button>
        </li>
      </ul>
      <!-- button to open/close drawer -->
      <div class="m-2 is-drawer-close:tooltip is-drawer-close:tooltip-right" data-tip="Open">
        <label for="my-drawer-4" class="btn btn-ghost btn-circle drawer-button is-drawer-open:rotate-y-180">
          ↔️
        </label>
      </div>
    </div>
  </div>
</div>
```


value00: docs/llms_daisyui.txt
value01:
#### Rules
- {MODIFIER} is optional and can have one of the modifier/placement class names
- `id` is required for the `drawer-toggle` input. change `my-drawer` to a unique id according to your needs
- `lg:drawer-open` can be used to make sidebar visible on larger screens
- `drawer-toggle` is a hidden checkbox. Use label with "for" attribute to toggle state
- if you want to open the drawer when a button is clicked, use `<label for="my-drawer" class="btn drawer-button">Open drawer</label>` where `my-drawer` is the id of the `drawer-toggle` input
- when using drawer, every page content must be inside `drawer-content` element. for example navbar, footer, etc should not be outside of `drawer`

### dropdown
Dropdown can open a menu or any other element when the button is clicked


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<div class="rating {MODIFIER}">
  <input type="radio" name="rating-1" class="mask mask-star" />
</div>
```

#### Rules
- {MODIFIER} is optional and can have one of the modifier/size class names
- Each set of rating inputs should have unique `name` attributes to avoid conflicts with other ratings on the same page
- Add `rating-hidden` for the first radio to make it hidden so user can clear the rating

### select
Select is used to pick a value from a list of options

[select docs](https://daisyui.com/components/select/)


value00: docs/llms_daisyui.txt
value01:
Using checkbox (legacy)
```html
<label for="my-modal" class="btn">Open modal</label>
<input type="checkbox" id="my-modal" class="modal-toggle" />
<div class="modal">
  <div class="modal-box">{CONTENT}</div>
  <label class="modal-backdrop" for="my-modal">Close</label>
</div>
```

Using anchor links (legacy)
```html
<a href="#my-modal" class="btn">Open modal</a>
<div class="modal" id="my-modal">
  <div class="modal-box">{CONTENT}</div>
</div>
```

#### Rules
- {MODIFIER} is optional and can have one of the modifier/placement class names
- Add `tabindex="0"` to make modal focusable
- Use unique IDs for each modal
- For HTML dialog element modals, add `<form method="dialog">` for closing the modal with submit

### navbar
Navbar is used to show a navigation bar on the top of the page


value00: src/lib/utils/patients.js
value01:
/**
 * Format datetime for display
 * @param {string} dateStr - ISO datetime string
 * @returns {string} Formatted datetime
 */
export function formatDateTime(dateStr) {
  if (!dateStr) return '-';
  try {
    return new Date(dateStr).toLocaleString();
  } catch {
    return '-';
  }
}

/**
 * Format birthdate for patient list
 * @param {Object} patient - Patient object
 * @param {string} [patient.Birthdate] - Birthdate
 * @param {string} [patient.BirthdateFormatted] - Pre-formatted birthdate
 * @returns {string} Formatted birthdate
 */
export function formatBirthdate(patient) {
  if (!patient) return '-';
  if (patient.BirthdateFormatted) return patient.BirthdateFormatted;
  return formatDate(patient.Birthdate);
}


value00: docs/llms_daisyui.txt
value01:
### mask
Mask crops the content of the element to common shapes

[mask docs](https://daisyui.com/components/mask/)

#### Class names
- component: `mask`
- style: `mask-squircle`, `mask-heart`, `mask-hexagon`, `mask-hexagon-2`, `mask-decagon`, `mask-pentagon`, `mask-diamond`, `mask-square`, `mask-circle`, `mask-star`, `mask-star-2`, `mask-triangle`, `mask-triangle-2`, `mask-triangle-3`, `mask-triangle-4`
- modifier: `mask-half-1`, `mask-half-2`

#### Syntax
```html
<img class="mask {MODIFIER}" src="{image-url}" />
```


value00: docs/llms_daisyui.txt
value01:
</div>
```
FAB with rectangle buttons. These are not circular buttons so they can have more content.
```html
<div class="fab">
  <div tabindex="0" role="button" class="btn btn-lg btn-circle btn-primary">{IconOriginal}</div>
  <button class="btn btn-lg">{Label1}</button>
  <button class="btn btn-lg">{Label2}</button>
  <button class="btn btn-lg">{Label3}</button>
</div>
```
FAB with close button. When FAB is open, the original button is replaced with a close button
```html


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<img class="mask {MODIFIER}" src="{image-url}" />
```

#### Rules
- {MODIFIER} is required and can have one of the style/modifier class names
- You can change the shape of any element using `mask` class names
- You can set custom sizes using `w-*` and `h-*`

### menu
Menu is used to display a list of links vertically or horizontally

[menu docs](https://daisyui.com/components/menu/)

#### Class names
- component: `menu`
- part: `menu-title`, `menu-dropdown`, `menu-dropdown-toggle`
- modifier: `menu-disabled`, `menu-active`, `menu-focus`, `menu-dropdown-show`
- size: `menu-xs`, `menu-sm`, `menu-md`, `menu-lg`, `menu-xl`
- direction: `menu-vertical`, `menu-horizontal`


value00: docs/llms_daisyui.txt
value01:
root scrollbar gutter is excluded. `daisy-` prefix is used for all daisyUI classes and console.log is disabled
```css
@plugin "daisyui" {
  themes: light, dark, cupcake, bumblebee --default, emerald, corporate, synthwave --prefersdark, retro, cyberpunk, valentine, halloween, garden, forest, aqua, lofi, pastel, fantasy, wireframe, black, luxury, dracula, cmyk, autumn, business, acid, lemonade, night, coffee, winter, dim, nord, sunset, caramellatte, abyss, silk;
  root: ":root";
  include: ;
  exclude: rootscrollgutter, checkbox;
  prefix: daisy-;
  logs: false;
}
```
## daisyUI 5 colors


value00: docs/llms_daisyui.txt
value01:
#### Rules
- {MODIFIER} is optional and can have one of each modifier/size class names
- The `overflow-x-auto` class is added to the wrapper div to make the table horizontally scrollable on smaller screens

### text-rotate
Text Rotate can show up to 6 lines of text, one at a time, with a an infinite loop animation. Duration is 10 seconds by default. The animation will pause on hover.

[textarea docs](https://daisyui.com/components/text-rotate/)

#### Class Names:
- Component: `text-rotate`


value00: src/lib/utils/patients.js
value01:
/**
 * Calculate age from birthdate
 * @param {string} birthdate - Birthdate string
 * @returns {string} Age in years
 */
export function calculateAge(birthdate) {
  if (!birthdate) return '-';
  try {
    const birth = new Date(birthdate);
    const today = new Date();
    let age = today.getFullYear() - birth.getFullYear();
    const monthDiff = today.getMonth() - birth.getMonth();
    if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
      age--;
    }
    return `${age}y`;
  } catch {
    return '-';
  }
}

/**
 * Get order status badge class
 * @param {string} status - Order status
 * @returns {string} DaisyUI badge class
 */


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<kbd class="kbd {MODIFIER}">K</kbd>
```

#### Rules
- {MODIFIER} is optional and can have one of the size class names

### label
Label is used to provide a name or title for an input field. Label can be placed before or after the field

[label docs](https://daisyui.com/components/label/)

#### Class names
- component: `label`, `floating-label`


value00: docs/llms_daisyui.txt
value01:
### tab
Tabs can be used to show a list of links in a tabbed format

[tab docs](https://daisyui.com/components/tab/)

#### Class Names:
- Component: `tabs`
- Part: `tab`, `tab-content`
- Style: `tabs-box`, `tabs-border`, `tabs-lift`
- Modifier: `tab-active`, `tab-disabled`
- Placement: `tabs-top`, `tabs-bottom`

#### Syntax
Using buttons:
```html
<div role="tablist" class="tabs {MODIFIER}">
  <button role="tab" class="tab">Tab</button>
</div>
```

Using radio inputs:
```html
<div role="tablist" class="tabs tabs-box">
  <input type="radio" name="my_tabs" class="tab" aria-label="Tab" />
</div>
```


value00: docs/llms_daisyui.txt
value01:
[hover-3d docs](https://daisyui.com/components/hover-3d/)

#### Class names
- component: `hover-3d`

#### Syntax
```html
<div class="hover-3d my-12 mx-2">
  <figure class="max-w-100 rounded-2xl">
    <img src="https://img.daisyui.com/images/stock/creditcard.webp" alt="Tailwind CSS 3D card" />
  </figure>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>
```

#### Rules
- hover-3d can be a `<div>` or a `<a>`
- hover-3d must have exactly 9 direct children where the first child is the main content and the other 8 children are empty `<div>`s for hover zones
- content inside hover-3d should be non-interactive (no buttons, links, inputs, etc)


value00: docs/llms_daisyui.txt
value01:
### dropdown
Dropdown can open a menu or any other element when the button is clicked

[dropdown docs](https://daisyui.com/components/dropdown/)

#### Class names
- component: `dropdown`
- part: `dropdown-content`
- placement: `dropdown-start`, `dropdown-center`, `dropdown-end`, `dropdown-top`, `dropdown-bottom`, `dropdown-left`, `dropdown-right`
- modifier: `dropdown-hover`, `dropdown-open`, `dropdown-close`

#### Syntax
Using details and summary
```html
<details class="dropdown">
  <summary>Button</summary>
  <ul class="dropdown-content">{CONTENT}</ul>
</details>
```

Using popover API
```html
<button popovertarget="{id}" style="anchor-name:--{anchor}">{button}</button>
<ul class="dropdown-content" popover id="{id}" style="position-anchor:--{anchor}">{CONTENT}</ul>
```


value00: docs/llms_daisyui.txt
value01:
#### Rules
- {MODIFIER} is optional and can have one of the style/size class names
- Radio inputs are needed for tab content to work with tab click
- If tabs gets a background then every tab inside it becomes rounded from both top corners

### table
Table can be used to show a list of data in a table format

[table docs](https://daisyui.com/components/table/)

#### Class Names:
- Component: `table`
- Modifier: `table-zebra`, `table-pin-rows`, `table-pin-cols`
- Size: `table-xs`, `table-sm`, `table-md`, `table-lg`, `table-xl`

#### Syntax
```html
<div class="overflow-x-auto">
  <table class="table {MODIFIER}">
    <thead>
      <tr>
        <th></th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <th></th>
      </tr>
    </tbody>
  </table>
</div>
```


value00: docs/llms_daisyui.txt
value01:
### textarea
Textarea allows users to enter text in multiple lines

[textarea docs](https://daisyui.com/components/textarea/)

#### Class Names:
- Component: `textarea`
- Style: `textarea-ghost`
- Color: `textarea-neutral`, `textarea-primary`, `textarea-secondary`, `textarea-accent`, `textarea-info`, `textarea-success`, `textarea-warning`, `textarea-error`
- Size: `textarea-xs`, `textarea-sm`, `textarea-md`, `textarea-lg`, `textarea-xl`

#### Syntax
```html
<textarea class="textarea {MODIFIER}" placeholder="Bio"></textarea>
```

#### Rules
- {MODIFIER} is optional and can have one of each style/color/size class names


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<button class="btn {MODIFIER}">Button</button>
```
#### Rules
- {MODIFIER} is optional and can have one of each color/style/behavior/size/modifier class names
- btn can be used on any html tags such as `<button>`, `<a>`, `<input>`
- btn can have an icon before or after the text
- set `tabindex="-1" role="button" aria-disabled="true"` if you want to disable the button using a class name

### calendar
Calendar includes styles for different calendar libraries

[calendar docs](https://daisyui.com/components/calendar/)


value00: docs/llms_daisyui.txt
value01:
  <input id="my-drawer-4" type="checkbox" class="drawer-toggle" />
  <div class="drawer-content">
    <!-- Page content here -->
  </div>
  <div class="drawer-side is-drawer-close:overflow-visible">
    <label for="my-drawer-4" aria-label="close sidebar" class="drawer-overlay"></label>
    <div class="is-drawer-close:w-14 is-drawer-open:w-64 bg-base-200 flex flex-col items-start min-h-full">
      <!-- Sidebar content here -->
      <ul class="menu w-full grow">
        <!-- list item -->
        <li>
          <button class="is-drawer-close:tooltip is-drawer-close:tooltip-right" data-tip="Homepage">
            🏠
            <span class="is-drawer-close:hidden">Homepage</span>
          </button>
        </li>
        <!-- list item -->


value00: docs/llms_daisyui.txt
value01:
### skeleton
Skeleton is a component that can be used to show a loading state

[skeleton docs](https://daisyui.com/components/skeleton/)

#### Class names
- component: `skeleton`
- modifier: `skeleton-text`

#### Syntax
```html
<div class="skeleton"></div>
```
Example with text skeleton:
```html
<div class="skeleton skeleton-text">Loading data...</div>
```

#### Rules
- Add `h-*` and `w-*` utility classes to set height and width

### stack
Stack visually puts elements on top of each other

[stack docs](https://daisyui.com/components/stack/)

#### Class Names:
- Component: `stack`
- Modifier: `stack-top`, `stack-bottom`, `stack-start`, `stack-end`

#### Syntax
```html
<div class="stack {MODIFIER}">{CONTENT}</div>
```


value00: docs/llms_daisyui.txt
value01:
</div>
```
FAB with close button. When FAB is open, the original button is replaced with a close button
```html
<div class="fab">
  <div tabindex="0" role="button" class="btn btn-lg btn-circle btn-primary">{IconOriginal}</div>
  <div class="fab-close">Close <span class="btn btn-circle btn-lg btn-error">✕</span></div>
  <div>{Label1}<button class="btn btn-lg btn-circle">{Icon1}</button></div>
  <div>{Label2}<button class="btn btn-lg btn-circle">{Icon2}</button></div>
  <div>{Label3}<button class="btn btn-lg btn-circle">{Icon3}</button></div>
</div>
```
FAB with Main Action button. When FAB is open, the original button is replaced with a main action button
```html


value00: docs/llms_daisyui.txt
value01:
- `base-300`:-300 Base color, even more darker shade, to create elevations
- `base-content`: Foreground content color to use on base color
- `info`: Info color, For informative/helpful messages
- `info-content`: Foreground content color to use on info color
- `success`: Success color, For success/safe messages
- `success-content`: Foreground content color to use on success color
- `warning`: Warning color, For warning/caution messages
- `warning-content`: Foreground content color to use on warning color
- `error`: Error color, For error/danger/destructive messages
- `error-content`: Foreground content color to use on error color


value00: docs/llms_daisyui.txt
value01:
### range
Range slider is used to select a value by sliding a handle

[range docs](https://daisyui.com/components/range/)

#### Class names
- component: `range`
- color: `range-neutral`, `range-primary`, `range-secondary`, `range-accent`, `range-success`, `range-warning`, `range-info`, `range-error`
- size: `range-xs`, `range-sm`, `range-md`, `range-lg`, `range-xl`

#### Syntax
```html
<input type="range" min="0" max="100" value="40" class="range {MODIFIER}" />
```

#### Rules
- {MODIFIER} is optional and can have one of each color/size class names
- You must specify `min` and `max` attributes

### rating
Rating is a set of radio buttons that allow the user to rate something


value00: docs/llms_daisyui.txt
value01:
#### Class names
- component: `diff`
- part: `diff-item-1`, `diff-item-2`, `diff-resizer`

#### Syntax
```html
<figure class="diff">
  <div class="diff-item-1">{item1}</div>
  <div class="diff-item-2">{item2}</div>
  <div class="diff-resizer"></div>
</figure>
```

#### Rules
- To maintain aspect ratio, add `aspect-16/9` or other aspect ratio classes to `<figure class="diff">` element

### divider
Divider will be used to separate content vertically or horizontally


value00: docs/llms_daisyui.txt
value01:
### daisyUI color rules
1. daisyUI adds semantic color names to Tailwind CSS colors
2. daisyUI color names can be used in utility classes, like other Tailwind CSS color names. for example, `bg-primary` will use the primary color for the background
3. daisyUI color names include variables as value so they can change based the theme
4. There's no need to use `dark:` for daisyUI color names
5. Ideally only daisyUI color names should be used for colors so the colors can change automatically based on the theme
6. If a Tailwind CSS color name (like `red-500`) is used, it will be same red color on all themes
7. If a daisyUI color name (like `primary`) is used, it will change color based on the theme


value00: docs/llms_daisyui.txt
value01:
#### Syntax
Using checkbox
```html
<label class="swap {MODIFIER}">
  <input type="checkbox" />
  <div class="swap-on">{content when active}</div>
  <div class="swap-off">{content when inactive}</div>
</label>
```

Using class name
```html
<div class="swap {MODIFIER}">
  <div class="swap-on">{content when active}</div>
  <div class="swap-off">{content when inactive}</div>
</div>
```

#### Rules
- {MODIFIER} is optional and can have one of the modifier/style class names
- Use only a hidden checkbox to control swap state or add/remove the `swap-active` class using JS to control state
- To show something when the checkbox is indeterminate, use `swap-indeterminate` class

### tab
Tabs can be used to show a list of links in a tabbed format

[tab docs](https://daisyui.com/components/tab/)


value00: docs/llms_daisyui.txt
value01:
### pagination
Pagination is a group of buttons

[pagination docs](https://daisyui.com/components/pagination/)

#### Class names
- component: `join`
- part: `join-item`
- direction: `join-vertical`, `join-horizontal`

#### Syntax
```html
<div class="join">{CONTENT}</div>
```

#### Rules
- Use `join-item` for each button or link inside the pagination
- Use `btn` class for styling pagination items

### progress
Progress bar can be used to show the progress of a task or to show the passing of time

[progress docs](https://daisyui.com/components/progress/)


value00: docs/llms_daisyui.txt
value01:
#### Rules
- {MODIFIER} is optional and can have one of each style/color/size class names

### theme-controller
If a checked checkbox input or a checked radio input with theme-controller class exists in the page, The page will have the same theme as that input's value

[theme-controller docs](https://daisyui.com/components/theme-controller/)

#### Class names
- component: `theme-controller`

#### Syntax
```html
<input type="checkbox" value="{theme-name}" class="theme-controller" />
```

#### Rules
- The value attribute of the input element should be a valid daisyUI theme name

### timeline
Timeline component shows a list of events in chronological order


value00: docs/llms_daisyui.txt
value01:
### calendar
Calendar includes styles for different calendar libraries

[calendar docs](https://daisyui.com/components/calendar/)

#### Class names
- component
  - `cally (for Cally web component)`
  - `pika-single (for the input field that opens Pikaday calendar)`
  - `react-day-picker (for the DayPicker component)`

#### Syntax
For Cally:
```html
<calendar-date class="cally">{CONTENT}</calendar-date>
```
For Pikaday:
```html
<input type="text" class="input pika-single">
```
For React Day Picker:
```html
<DayPicker className="react-day-picker">
```

#### Rules
- daisyUI supports Cally, Pikaday, React Day Picker

### card
Cards are used to group and display content

[card docs](https://daisyui.com/components/card/)


value00: docs/llms_daisyui.txt
value01:
### timeline
Timeline component shows a list of events in chronological order

[timeline docs](https://daisyui.com/components/timeline/)

#### Class Names:
- Component: `timeline`
- Part: `timeline-start`, `timeline-middle`, `timeline-end`
- Modifier: `timeline-snap-icon`, `timeline-box`, `timeline-compact`
- Direction: `timeline-vertical`, `timeline-horizontal`

#### Syntax
```html
<ul class="timeline {MODIFIER}">
  <li>
    <div class="timeline-start">{start}</div>
    <div class="timeline-middle">{icon}</div>
    <div class="timeline-end">{end}</div>
  </li>
</ul>
```


value00: docs/llms_daisyui.txt
value01:
[validator docs](https://daisyui.com/components/validator/)

#### Class names
- component: `validator`
- part: `validator-hint`

#### Syntax
```html
<input type="{type}" class="input validator" required />
<p class="validator-hint">Error message</p>
```

#### Rules
- Use with `input`, `select`, `textarea`


value00: src/lib/types/index.ts
value01:
/**
 * Type Definitions Index
 * Central export point for all type definitions
 */

// Test Types
export * from './test.types.js';

// Rules Types
export * from './rules.types.js';

// Re-export specific types for convenience


value00: docs/llms_daisyui.txt
value01:
7. If a daisyUI color name (like `primary`) is used, it will change color based on the theme
8. Using Tailwind CSS color names for text colors should be avoided because Tailwind CSS color `text-gray-800` on `bg-base-100` would be unreadable on a dark theme - because on dark theme, `bg-base-100` is a dark color
9. `*-content` colors should have a good contrast compared to their associated colors
10. suggestion - when designing a page use `base-*` colors for majority of the page. use `primary` color for important elements


value00: docs/llms_daisyui.txt
value01:
### rating
Rating is a set of radio buttons that allow the user to rate something

[rating docs](https://daisyui.com/components/rating/)

#### Class names
- component: `rating`
- modifier: `rating-half`, `rating-hidden`
- size: `rating-xs`, `rating-sm`, `rating-md`, `rating-lg`, `rating-xl`

#### Syntax
```html
<div class="rating {MODIFIER}">
  <input type="radio" name="rating-1" class="mask mask-star" />
</div>
```


value00: docs/llms_daisyui.txt
value01:
#### Class names
- component: `mockup-browser`
- part: `mockup-browser-toolbar`

#### Syntax
```html
<div class="mockup-browser">
  <div class="mockup-browser-toolbar">
    {toolbar content}
  </div>
  <div>{CONTENT}</div>
</div>
```

#### Rules
- For a default mockup, use just `mockup-browser` class name
- To set a URL in toolbar, add a div with `input` class

### mockup-code
Code mockup is used to show a block of code in a box that looks like a code editor

[mockup-code docs](https://daisyui.com/components/mockup-code/)

#### Class names
- component: `mockup-code`

#### Syntax
```html
<div class="mockup-code">
  <pre data-prefix="$"><code>npm i daisyui</code></pre>
</div>
```


value00: docs/llms_daisyui.txt
value01:
[label docs](https://daisyui.com/components/label/)

#### Class names
- component: `label`, `floating-label`

#### Syntax
For regular label:
```html
<label class="input">
  <span class="label">{label text}</span>
  <input type="text" placeholder="Type here" />
</label>
```
For floating label:
```html
<label class="floating-label">
  <input type="text" placeholder="Type here" class="input" />
  <span>{label text}</span>
</label>
```

#### Rules
- The `input` class is for styling the parent element which contains the input field and label, so the label does not have the 'input' class
- Use `floating-label` for the parent of an input field and a span that floats above the input field when the field is focused

### link
Link adds the missing underline style to links


value00: docs/llms_daisyui.txt
value01:
#### Rules
- `text-rotate` must have one span or div inside it that contains 2 to 6 spans/divs for each line of text
- Total duration of the loop is 10000 milliseconds by default
- You can set custom duration using `duration-{value}` utility class, where value is in milliseconds (e.g. `duration-12000` for 12 seconds)


### textarea
Textarea allows users to enter text in multiple lines

[textarea docs](https://daisyui.com/components/textarea/)


value00: docs/llms_daisyui.txt
value01:
### toast
Toast is a wrapper to stack elements, positioned on the corner of page

[toast docs](https://daisyui.com/components/toast/)

#### Class Names:
- Component: `toast`
- Placement: `toast-start`, `toast-center`, `toast-end`, `toast-top`, `toast-middle`, `toast-bottom`

#### Syntax
```html
<div class="toast {MODIFIER}">{CONTENT}</div>
```

#### Rules
- {MODIFIER} is optional and can have one of the placement class names

### toggle
Toggle is a checkbox that is styled to look like a switch button

[toggle docs](https://daisyui.com/components/toggle/)


value00: docs/llms_daisyui.txt
value01:
  --depth: 1; /* only 0 or 1 – Adds a shadow and subtle 3D depth effect to components */
  --noise: 0; /* only 0 or 1 - Adds a subtle noise (grain) effect to components */
}
```
#### Rules
- All CSS variables above are required
- Colors can be OKLCH or hex or other formats
- If you're generating a custom theme, do not include the comments from the example above. Just provide the code.

People can use https://daisyui.com/theme-generator/ visual tool to create their own theme.


value00: src/lib/types/index.ts
value01:
export * from './test.types.js';

// Rules Types
export * from './rules.types.js';

// Re-export specific types for convenience
export type {
  TestType,
  ResultType,
  RefType,
  TestSummary,
  TestDetail,
  CreateTestPayload,
  UpdateTestPayload,
  RefNumRange,
  RefTxtRange,
  TestMapping,
  GroupMember,
  TechDetail,
  CalcDetails,
  TestFormState,
  TabConfig
} from './test.types.js';

export type {
  RuleEventCode,
  RuleScopeType,
  RuleActionType,
  RuleDef,
  RuleAction,
  RuleWithActions,
  SetResultActionParams
} from './rules.types.js';


value00: docs/llms_daisyui.txt
value01:
[progress docs](https://daisyui.com/components/progress/)

#### Class names
- component: `progress`
- color: `progress-neutral`, `progress-primary`, `progress-secondary`, `progress-accent`, `progress-info`, `progress-success`, `progress-warning`, `progress-error`

#### Syntax
```html
<progress class="progress {MODIFIER}" value="50" max="100"></progress>
```

#### Rules
- {MODIFIER} is optional and can have one of the color class names
- You must specify value and max attributes

### radial-progress
Radial progress can be used to show the progress of a task or to show the passing of time

[radial-progress docs](https://daisyui.com/components/radial-progress/)


value00: docs/llms_daisyui.txt
value01:
### file-input
File Input is a an input field for uploading files

[file-input docs](https://daisyui.com/components/file-input/)

#### Class Names:
- Component: `file-input`
- Style: `file-input-ghost`
- Color: `file-input-neutral`, `file-input-primary`, `file-input-secondary`, `file-input-accent`, `file-input-info`, `file-input-success`, `file-input-warning`, `file-input-error`
- Size: `file-input-xs`, `file-input-sm`, `file-input-md`, `file-input-lg`, `file-input-xl`

#### Syntax
```html
<input type="file" class="file-input {MODIFIER}" />
```

#### Rules
- {MODIFIER} is optional and can have one of each style/color/size class names

### filter
Filter is a group of radio buttons. Choosing one of the options will hide the others and shows a reset button next to the chosen option


value00: docs/llms_daisyui.txt
value01:
### toggle
Toggle is a checkbox that is styled to look like a switch button

[toggle docs](https://daisyui.com/components/toggle/)

#### Class Names:
- Component: `toggle`
- Color: `toggle-primary`, `toggle-secondary`, `toggle-accent`, `toggle-neutral`, `toggle-success`, `toggle-warning`, `toggle-info`, `toggle-error`
- Size: `toggle-xs`, `toggle-sm`, `toggle-md`, `toggle-lg`, `toggle-xl`

#### Syntax
```html
<input type="checkbox" class="toggle {MODIFIER}" />
```

#### Rules
- {MODIFIER} is optional and can have one of each color/size class names

### validator
Validator class changes the color of form elements to error or success based on input's validation rules

[validator docs](https://daisyui.com/components/validator/)


value00: docs/llms_daisyui.txt
value01:
### divider
Divider will be used to separate content vertically or horizontally

[divider docs](https://daisyui.com/components/divider/)

#### Class names
- component: `divider`
- color: `divider-neutral`, `divider-primary`, `divider-secondary`, `divider-accent`, `divider-success`, `divider-warning`, `divider-info`, `divider-error`
- direction: `divider-vertical`, `divider-horizontal`
- placement: `divider-start`, `divider-end`

#### Syntax
```html
<div class="divider {MODIFIER}">{text}</div>
```

#### Rules
- {MODIFIER} is optional and can have one of each direction/color/placement class names
- Omit text for a blank divider


value00: docs/llms_daisyui.txt
value01:
#### Rules
- replace `{NAME}` with proper value, according to the context of the filter
- Each set of radio inputs must have unique `name` attributes to avoid conflicts
- Use `<form>` tag when possible and only use `<div>` if you can't use a HTML form for some reason
- Use `filter-reset` class for the reset button

### footer
Footer can contain logo, copyright notice, and links to other pages


value00: docs/llms_daisyui.txt
value01:
[hover-gallery docs](https://daisyui.com/components/hover-gallery/)

#### Class names
- component: `hover-gallery`

#### Syntax
```html
<figure class="hover-gallery max-w-60">
  <img src="https://img.daisyui.com/images/stock/daisyui-hat-1.webp" />
  <img src="https://img.daisyui.com/images/stock/daisyui-hat-2.webp" />
  <img src="https://img.daisyui.com/images/stock/daisyui-hat-3.webp" />
  <img src="https://img.daisyui.com/images/stock/daisyui-hat-4.webp" />
</figure>
```

#### Rules
- hover-gallery can be a `<div>` or a `<figure>`
- hover-gallery can include up to 10 images
- hover-gallery needs a max width otherwise if fills the container width
- images must be same dimensions for a proper alignment

### indicator
Indicators are used to place an element on the corner of another element


value00: src/lib/utils/patients.js
value01:
export function getOrderStatusClass(status) {
  const statusMap = {
    'pending': 'badge-warning',
    'in_progress': 'badge-info',
    'completed': 'badge-success',
    'cancelled': 'badge-error',
    'collected': 'badge-primary',
    'verified': 'badge-accent',
  };
  return statusMap[status?.toLowerCase()] || 'badge-ghost';
}

/**
 * Format order number
 * @param {Object} order - Order object
 * @param {string} [order.OrderNumber] - Order number
 * @param {string} [order.OrderID] - Order ID
 * @returns {string} Formatted order number
 */
export function formatOrderNumber(order) {
  if (!order) return '-';
  return order.OrderNumber || order.OrderID || '-';
}


value00: docs/llms_daisyui.txt
value01:
### link
Link adds the missing underline style to links

[link docs](https://daisyui.com/components/link/)

#### Class names
- component: `link`
- style: `link-hover`
- color: `link-neutral`, `link-primary`, `link-secondary`, `link-accent`, `link-success`, `link-info`, `link-warning`, `link-error`

#### Syntax
```html
<a class="link {MODIFIER}">Click me</a>
```

#### Rules
- {MODIFIER} is optional and can have one of the modifier class names

### list
List is a vertical layout to display information in rows

[list docs](https://daisyui.com/components/list/)

#### Class Names:
- Component: `list`, `list-row`
- Modifier: `list-col-wrap`, `list-col-grow`

#### Syntax
```html
<ul class="list">
  <li class="list-row">{CONTENT}</li>
</ul>
```


value00: docs/llms_daisyui.txt
value01:
### loading
Loading shows an animation to indicate that something is loading

[loading docs](https://daisyui.com/components/loading/)

#### Class names
- component: `loading`
- style: `loading-spinner`, `loading-dots`, `loading-ring`, `loading-ball`, `loading-bars`, `loading-infinity`
- size: `loading-xs`, `loading-sm`, `loading-md`, `loading-lg`, `loading-xl`

#### Syntax
```html
<span class="loading {MODIFIER}"></span>
```

#### Rules
- {MODIFIER} is optional and can have one of the style/size class names

### mask
Mask crops the content of the element to common shapes

[mask docs](https://daisyui.com/components/mask/)


value00: docs/llms_daisyui.txt
value01:
[filter docs](https://daisyui.com/components/filter/)

#### Class names
- component: `filter`
- part: `filter-reset`

#### Syntax
Using HTML form
```html
<form class="filter">
  <input class="btn btn-square" type="reset" value="×"/>
  <input class="btn" type="radio" name="{NAME}" aria-label="Tab 1 title"/>
  <input class="btn" type="radio" name="{NAME}" aria-label="Tab 2 title"/>
</form>
```
Without HTML form
```html
<div class="filter">
  <input class="btn filter-reset" type="radio" name="{NAME}" aria-label="×"/>
  <input class="btn" type="radio" name="{NAME}" aria-label="Tab 1 title"/>
  <input class="btn" type="radio" name="{NAME}" aria-label="Tab 2 title"/>
</div>
```


value00: docs/llms_daisyui.txt
value01:
</div>
```
FAB with Main Action button. When FAB is open, the original button is replaced with a main action button
```html
<div class="fab">
  <div tabindex="0" role="button" class="btn btn-lg btn-circle btn-primary">{IconOriginal}</div>
  <div class="fab-main-action">
    {LabelMainAction}<button class="btn btn-circle btn-secondary btn-lg">{IconMainAction}</button>
  </div>
  <div>{Label1}<button class="btn btn-lg btn-circle">{Icon1}</button></div>
  <div>{Label2}<button class="btn btn-lg btn-circle">{Icon2}</button></div>
  <div>{Label3}<button class="btn btn-lg btn-circle">{Icon3}</button></div>
</div>
```
FAB Flower. It opens the buttons in a flower shape (quarter circle) arrangement instead of vertical
```html


value00: docs/llms_daisyui.txt
value01:
People can use https://daisyui.com/theme-generator/ visual tool to create their own theme.

## daisyUI 5 components

### accordion
Accordion is used for showing and hiding content but only one item can stay open at a time

[accordion docs](https://daisyui.com/components/accordion/)

#### Class names
- component: `collapse`
- part: `collapse-title`, `collapse-content`
- modifier: `collapse-arrow`, `collapse-plus`, `collapse-open`, `collapse-close`

#### Syntax
```html
<div class="collapse {MODIFIER}">{CONTENT}</div>
```
where content is:
```html
<input type="radio" name="{name}" checked="{checked}" />
<div class="collapse-title">{title}</div>
<div class="collapse-content">{CONTENT}</div>
```


value00: docs/llms_daisyui.txt
value01:
Using CSS focus
```html
<div class="dropdown">
  <div tabindex="0" role="button">Button</div>
  <ul tabindex="-1" class="dropdown-content">{CONTENT}</ul>
</div>
```

#### Rules
- {MODIFIER} is optional and can have one of the modifier/placement class names
- replace `{id}` and `{anchor}` with a unique name
- For CSS focus dropdowns, use `tabindex="0"` and `role="button"` on the button
- The content can be any HTML element (not just `<ul>`)

### fab
FAB (Floating Action Button) stays in the bottom corner of screen. It includes a focusable and accessible element with button role. Clicking or focusing it shows additional buttons (known as Speed Dial buttons) in a vertical arrangement or a flower shape (quarter circle)

[fab docs](https://daisyui.com/components/fab/)


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<span class="text-rotate">
  <span>
    <span>Word 1</span>
    <span>Word 2</span>
    <span>Word 3</span>
    <span>Word 4</span>
    <span>Word 5</span>
    <span>Word 6</span>
  </span>
</span>
```
Example:
Big font size, horizontally centered
```html
<span class="text-rotate max-md:text-3xl text-7xl font-title">
  <span class="justify-items-center">
    <span>DESIGN</span>
    <span>DEVELOP</span>
    <span>DEPLOY</span>
    <span>SCALE</span>
    <span>MAINTAIN</span>
    <span>REPEAT</span>
  </span>
</span>
```
Rotating words in a sentence, different colors for each word
```html
<span>
  Providing AI Agents for 
  <span class="text-rotate">


value00: docs/llms_daisyui.txt
value01:
```
Rotating words in a sentence, different colors for each word
```html
<span>
  Providing AI Agents for 
  <span class="text-rotate">
    <span>
      <span class="bg-teal-400 text-teal-800 px-2">Designers</span>
      <span class="bg-red-400 text-red-800 px-2">Developers</span>
      <span class="bg-blue-400 text-blue-800 px-2">Managers</span>
    </span>
  </span>
</span>
```
Custom line height in case you have a tall font or need more vertical spacing between lines
```html
<span class="text-rotate max-md:text-3xl text-7xl font-title leading-[2]">
  <span class="justify-items-center">
    <span>📐 DESIGN</span>
    <span>⌨️ DEVELOP</span>
    <span>🌎 DEPLOY</span>
    <span>🌱 SCALE</span>
    <span>🔧 MAINTAIN</span>
    <span>♻️ REPEAT</span>
  </span>
</span>
```


value00: src/lib/types/rules.types.ts
value01:
/**
 * Rules Engine Type Definitions
 * Based on CLQMS API Specification - Refactored Rule System
 */

export type RuleEventCode = 'ORDER_CREATED';
export type RuleActionType = 'SET_RESULT';

export interface RuleDef {
  RuleID: number;
  RuleCode: string;
  RuleName: string;
  Description?: string;
  EventCode: RuleEventCode | string;
  ConditionExpr?: string | null;
  ConditionExprCompiled?: string | null;
  Priority?: number;
  Active: 0 | 1 | number;
  /** ISO timestamp strings */
  createdAt?: string;
  updatedAt?: string;
  deletedAt?: string | null;
}


value00: docs/llms_daisyui.txt
value01:
#### Rules
- {MODIFIER} is optional and can have one of the modifier class names
- Accordion uses radio inputs. All radio inputs with the same name work together and only one of them can be open at a time
- If you have more than one set of accordion items on a page, use different names for the radio inputs on each set
- Replace {name} with a unique name for the accordion group
- replace `{checked}` with `checked="checked"` if you want the accordion to be open by default

### alert
Alert informs users about important events

[alert docs](https://daisyui.com/components/alert/)


value00: src/lib/types/rules.types.ts
value01:
export interface RulesListResponse extends ApiResponse<RuleDef[]> {}
export interface RuleDetailResponse extends ApiResponse<RuleDef> {}

export interface ValidateExprResponse extends ApiResponse<{ valid: boolean; result?: any; error?: string }> {}

export interface CompileExprResponse {
  compiled: any;
  conditionExprCompiled: string;
}

export type SetResultActionParams = {
  testSiteID?: number;
  testSiteCode?: string;
  value?: any;
  valueExpr?: string;
};


value00: docs/llms_daisyui.txt
value01:
### alert
Alert informs users about important events

[alert docs](https://daisyui.com/components/alert/)

#### Class names
- component: `alert`
- style: `alert-outline`, `alert-dash`, `alert-soft`
- color: `alert-info`, `alert-success`, `alert-warning`, `alert-error`
- direction: `alert-vertical`, `alert-horizontal`

#### Syntax
```html
<div role="alert" class="alert {MODIFIER}">{CONTENT}</div>
```

#### Rules
- {MODIFIER} is optional and can have one of each style/color/direction class names
- Add `sm:alert-horizontal` for responsive layouts

### avatar
Avatars are used to show a thumbnail


value00: src/lib/utils/patients.js
value01:
export function formatOrderNumber(order) {
  if (!order) return '-';
  return order.OrderNumber || order.OrderID || '-';
}

/**
 * Debounce function for search inputs
 * @param {Function} func - Function to debounce
 * @param {number} wait - Milliseconds to wait
 * @returns {Function} Debounced function
 */
export function debounce(func, wait = 300) {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
}


value00: docs/llms_daisyui.txt
value01:
[radial-progress docs](https://daisyui.com/components/radial-progress/)

#### Class names
- component: `radial-progress`

#### Syntax
```html
<div class="radial-progress" style="--value:70;" aria-valuenow="70" role="progressbar">70%</div>
```

#### Rules
- The `--value` CSS variable and text must be a number between 0 and 100
- you need to add `aria-valuenow="{value}"`, `aria-valuenow={value}` so screen readers can properly read value and also show that its a progress element to them
- Use `div` instead of progress because browsers can't show text inside progress tag
- Use `--size` for setting size (default 5rem) and `--thickness` to set how thick the indicator is

### radio
Radio buttons allow the user to select one option

[radio docs](https://daisyui.com/components/radio/)


value00: docs/llms_daisyui.txt
value01:
### steps
Steps can be used to show a list of steps in a process

[steps docs](https://daisyui.com/components/steps/)

#### Class Names:
- Component: `steps`
- Part: `step`, `step-icon`
- Color: `step-neutral`, `step-primary`, `step-secondary`, `step-accent`, `step-info`, `step-success`, `step-warning`, `step-error`
- Direction: `steps-vertical`, `steps-horizontal`

#### Syntax
```html
<ul class="steps {MODIFIER}">
  <li class="step">{step content}</li>
</ul>
```


value00: docs/llms_daisyui.txt
value01:
### card
Cards are used to group and display content

[card docs](https://daisyui.com/components/card/)

#### Class names
- component: `card`
- part: `card-title`, `card-body`, `card-actions`
- style: `card-border`, `card-dash`
- modifier: `card-side`, `image-full`
- size: `card-xs`, `card-sm`, `card-md`, `card-lg`, `card-xl`

#### Syntax
```html
<div class="card {MODIFIER}">
  <figure><img src="{image-url}" alt="{alt-text}" /></figure>
  <div class="card-body">
    <h2 class="card-title">{title}</h2>
    <p>{CONTENT}</p>
    <div class="card-actions">{actions}</div>
  </div>
</div>
```


value00: docs/llms_daisyui.txt
value01:
### daisyUI custom theme with custom colors
A CSS file with Tailwind CSS, daisyUI and a custom daisyUI theme looks like this:
```css
@import "tailwindcss";
@plugin "daisyui";
@plugin "daisyui/theme" {
  name: "mytheme";
  default: true; /* set as default */
  prefersdark: false; /* set as default dark mode (prefers-color-scheme:dark) */
  color-scheme: light; /* color of browser-provided UI */


value00: docs/llms_daisyui.txt
value01:
### hover-gallery
Hover Gallery is container of images. The first image is visible be default and when we hover it horizontally, other images show up. Hover Gallery is useful for product cards in ecommerce sites, portfoilios or in image galleries. Hover Gallery can include up to 10 images.

[hover-gallery docs](https://daisyui.com/components/hover-gallery/)

#### Class names
- component: `hover-gallery`


value00: docs/llms_daisyui.txt
value01:
#### Rules
- {MODIFIER} is optional and can have one of the size class names
- To make a button active, add `dock-active` class to the button
- add `<meta name="viewport" content="viewport-fit=cover">` is required for responsivness of the dock in iOS

### drawer
Drawer is a grid layout that can show/hide a sidebar on the left or right side of the page

[drawer docs](https://daisyui.com/components/drawer/)

#### Class names
- component: `drawer`
- part: `drawer-toggle`, `drawer-content`, `drawer-side`, `drawer-overlay`
- placement: `drawer-end`
- modifier: `drawer-open`
- variant: `is-drawer-open:`, `is-drawer-close:`


value00: src/lib/types/rules.types.ts
value01:
export interface RuleAction {
  RuleActionID: number;
  RuleID: number;
  Seq: number;
  ActionType: RuleActionType | string;
  ActionParams: string | Record<string, any>;
  /** ISO timestamp strings */
  createdAt?: string;
  updatedAt?: string;
}

export interface ApiResponse<T> {
  status: 'success' | 'created' | 'error' | string;
  message: string;
  data: T;
}

export interface RulesListResponse extends ApiResponse<RuleDef[]> {}


value00: docs/llms_daisyui.txt
value01:
#### Rules
- {MODIFIER} is optional and can have one of the modifier class names and one of the size class names
- `<figure>` and `<div class="card-body">` are optional
- can use `sm:card-horizontal` for responsive layouts
- If image is placed after `card-body`, the image will be placed at the bottom

### carousel
Carousel show images or content in a scrollable area

[carousel docs](https://daisyui.com/components/carousel/)

#### Class names
- component: `carousel`
- part: `carousel-item`
- modifier: `carousel-start`, `carousel-center`, `carousel-end`
- direction: `carousel-horizontal`, `carousel-vertical`

#### Syntax
```html
<div class="carousel {MODIFIER}">{CONTENT}</div>
```


value00: docs/llms_daisyui.txt
value01:
#### Rules
- {MODIFIER} is optional and can have one of the modifier/direction class names
- To make a vertical timeline, add the `timeline-vertical` class to the `ul` element or just do nothing (because its the default style.)
- Add `timeline-snap-icon` to snap the icon to the start instead of middle
- Add the `timeline-compact` class to force all items on one side

### toast
Toast is a wrapper to stack elements, positioned on the corner of page


value00: docs/llms_daisyui.txt
value01:
### indicator
Indicators are used to place an element on the corner of another element

[indicator docs](https://daisyui.com/components/indicator/)

#### Class names
- component: `indicator`
- part: `indicator-item`
- placement: `indicator-start`, `indicator-center`, `indicator-end`, `indicator-top`, `indicator-middle`, `indicator-bottom`

#### Syntax
```html
<div class="indicator">
  <span class="indicator-item">{indicator content}</span>
  <div>{main content}</div>
</div>
```

#### Rules
- Add all indicator elements (with `indicator-item` class) before the main content
- {placement} is optional and can have one of each horizontal/vertical class names. default is `indicator-end indicator-top`

### input
Text Input is a simple input field


value00: docs/llms_daisyui.txt
value01:
### radio
Radio buttons allow the user to select one option

[radio docs](https://daisyui.com/components/radio/)

#### Class names
- component: `radio`
- color: `radio-neutral`, `radio-primary`, `radio-secondary`, `radio-accent`, `radio-success`, `radio-warning`, `radio-info`, `radio-error`
- size: `radio-xs`, `radio-sm`, `radio-md`, `radio-lg`, `radio-xl`

#### Syntax
```html
<input type="radio" name="{name}" class="radio {MODIFIER}" />
```

#### Rules
- {MODIFIER} is optional and can have one of the size/color class names
- Replace {name} with a unique name for the radio group
- Each set of radio inputs should have unique `name` attributes to avoid conflicts with other sets of radio inputs on the same page

### range
Range slider is used to select a value by sliding a handle


value00: docs/llms_daisyui.txt
value01:
#### Rules
- {MODIFIER} is optional and can have one of the modifier/direction class names
- Content is a list of `carousel-item` divs: `<div class="carousel-item"></div>`
- To create a full-width carousel, add `w-full` to each carousel item

### chat
Chat bubbles are used to show one line of conversation and all its data, including the author image, author name, time, etc

[chat docs](https://daisyui.com/components/chat/)

#### Class names
- component: `chat`
- part: `chat-image`, `chat-header`, `chat-footer`, `chat-bubble`
- placement: `chat-start`, `chat-end`
- color: `chat-bubble-neutral`, `chat-bubble-primary`, `chat-bubble-secondary`, `chat-bubble-accent`, `chat-bubble-info`, `chat-bubble-success`, `chat-bubble-warning`, `chat-bubble-error`


value00: docs/llms_daisyui.txt
value01:
```
FAB Flower with tooltips. There's no space for a text label in a quarter circle, so tooltips are used to indicate the button's function
```html
<div class="fab fab-flower">
  <div tabindex="0" role="button" class="btn btn-lg btn-circle btn-primary">{IconOriginal}</div>
  <button class="fab-main-action btn btn-circle btn-lg">{IconMainAction}</button>
  <div class="tooltip tooltip-left" data-tip="{Label1}">
    <button class="btn btn-lg btn-circle">{Icon1}</button>
  </div>
  <div class="tooltip tooltip-left" data-tip="{Label2}">
    <button class="btn btn-lg btn-circle">{Icon2}</button>
  </div>
  <div class="tooltip tooltip-left" data-tip="{Label3}">
    <button class="btn btn-lg btn-circle">{Icon3}</button>
  </div>
</div>


value00: docs/llms_daisyui.txt
value01:
</div>
```
FAB Flower. It opens the buttons in a flower shape (quarter circle) arrangement instead of vertical
```html
<div class="fab fab-flower">
  <div tabindex="0" role="button" class="btn btn-lg btn-circle btn-primary">{IconOriginal}</div>
  <button class="fab-main-action btn btn-circle btn-lg">{IconMainAction}</button>
  <button class="btn btn-lg btn-circle">{Icon1}</button>
  <button class="btn btn-lg btn-circle">{Icon2}</button>
  <button class="btn btn-lg btn-circle">{Icon3}</button>
</div>
```
FAB Flower with tooltips. There's no space for a text label in a quarter circle, so tooltips are used to indicate the button's function


value00: docs/llms_daisyui.txt
value01:
#### Rules
- {MODIFIER} is optional and can have one of each direction/color/placement class names
- Omit text for a blank divider

### dock
Dock (also know as Bottom navigation or Bottom bar) is a UI element that provides navigation options to the user. Dock sticks to the bottom of the screen

[dock docs](https://daisyui.com/components/dock/)

#### Class names
- component: `dock`
- part: `dock-label`
- modifier: `dock-active`
- size: `dock-xs`, `dock-sm`, `dock-md`, `dock-lg`, `dock-xl`

#### Syntax
```html
<div class="dock {MODIFIER}">{CONTENT}</div>
```
where content is a list of buttons:
```html
<button>
    <svg>{icon}</svg>
    <span class="dock-label">Text</span>
</button>
```


value00: docs/llms_daisyui.txt
value01:
### avatar
Avatars are used to show a thumbnail

[avatar docs](https://daisyui.com/components/avatar/)

#### Class names
- component: `avatar`, `avatar-group`
- modifier: `avatar-online`, `avatar-offline`, `avatar-placeholder`

#### Syntax
```html
<div class="avatar {MODIFIER}">
  <div>
    <img src="{image-url}" />
  </div>
</div>
```

#### Rules
- {MODIFIER} is optional and can have one of the modifier class names
- Use `avatar-group` for containing multiple avatars
- You can set custom sizes using `w-*` and `h-*`
- You can use mask classes such as `mask-squircle`, `mask-hexagon`, `mask-triangle`

### badge
Badges are used to inform the user of the status of specific data

[badge docs](https://daisyui.com/components/badge/)


value00: docs/llms_daisyui.txt
value01:
### badge
Badges are used to inform the user of the status of specific data

[badge docs](https://daisyui.com/components/badge/)

#### Class names
- component: `badge`
- style: `badge-outline`, `badge-dash`, `badge-soft`, `badge-ghost`
- color: `badge-neutral`, `badge-primary`, `badge-secondary`, `badge-accent`, `badge-info`, `badge-success`, `badge-warning`, `badge-error`
- size: `badge-xs`, `badge-sm`, `badge-md`, `badge-lg`, `badge-xl`

#### Syntax
```html
<span class="badge {MODIFIER}">Badge</span>
```


value00: docs/llms_daisyui.txt
value01:
---
description: daisyUI 5
alwaysApply: true
applyTo: "**"
downloadedFrom: https://daisyui.com/llms.txt
version: 5.5.x
---

# daisyUI 5
daisyUI 5 is a CSS library for Tailwind CSS 4
daisyUI 5 provides class names for common UI components

- [daisyUI 5 docs](http://daisyui.com)
- [Guide: How to use this file in LLMs and code editors](https://daisyui.com/docs/editor/)
- [daisyUI 5 release notes](https://daisyui.com/docs/v5/)
- [daisyUI 4 to 5 upgrade guide](https://daisyui.com/docs/upgrade/)


value00: docs/llms_daisyui.txt
value01:
  --color-base-100: oklch(98% 0.02 240);
  --color-base-200: oklch(95% 0.03 240);
  --color-base-300: oklch(92% 0.04 240);
  --color-base-content: oklch(20% 0.05 240);
  --color-primary: oklch(55% 0.3 240);
  --color-primary-content: oklch(98% 0.01 240);
  --color-secondary: oklch(70% 0.25 200);
  --color-secondary-content: oklch(98% 0.01 200);


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<div class="drawer {MODIFIER}">
  <input id="my-drawer" type="checkbox" class="drawer-toggle" />
  <div class="drawer-content">{CONTENT}</div>
  <div class="drawer-side">{SIDEBAR}</div>
</div>
```
where {CONTENT} can be navbar, site content, footer, etc
and {SIDEBAR} can be a menu like:
```html
<ul class="menu p-4 w-80 min-h-full bg-base-100 text-base-content">
  <li><a>Item 1</a></li>
  <li><a>Item 2</a></li>
</ul>
```
To open/close the drawer, use a label that points to the `drawer-toggle` input:


value00: docs/llms_daisyui.txt
value01:
  --color-secondary: oklch(70% 0.25 200);
  --color-secondary-content: oklch(98% 0.01 200);
  --color-accent: oklch(65% 0.25 160);
  --color-accent-content: oklch(98% 0.01 160);
  --color-neutral: oklch(50% 0.05 240);
  --color-neutral-content: oklch(98% 0.01 240);
  --color-info: oklch(70% 0.2 220);
  --color-info-content: oklch(98% 0.01 220);
  --color-success: oklch(65% 0.25 140);
  --color-success-content: oklch(98% 0.01 140);
  --color-warning: oklch(80% 0.25 80);
  --color-warning-content: oklch(20% 0.05 80);
  --color-error: oklch(65% 0.3 30);
  --color-error-content: oklch(98% 0.01 30);


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<div class="chat {PLACEMENT}">
  <div class="chat-image"></div>
  <div class="chat-header"></div>
  <div class="chat-bubble {COLOR}">Message text</div>
  <div class="chat-footer"></div>
</div>
```

#### Rules
- {PLACEMENT} is required and must be either `chat-start` or `chat-end`
- {COLOR} is optional and can have one of the color class names
- To add an avatar, use `<div class="chat-image avatar">` and nest the avatar content inside

### checkbox
Checkboxes are used to select or deselect a value

[checkbox docs](https://daisyui.com/components/checkbox/)


value00: docs/llms_daisyui.txt
value01:
## daisyUI 5 install notes
[install guide](https://daisyui.com/docs/install/)
1. daisyUI 5 requires Tailwind CSS 4
2. `tailwind.config.js` file is deprecated in Tailwind CSS v4. do not use `tailwind.config.js`. Tailwind CSS v4 only needs `@import "tailwindcss";` in the CSS file if it's a node dependency.
3. daisyUI 5 can be installed using `npm i -D daisyui@latest` and then adding `@plugin "daisyui";` to the CSS file
4. daisyUI is suggested to be installed as a dependency but if you really want to use it from CDN, you can use Tailwind CSS and daisyUI CDN files:
```html
<link href="https://cdn.jsdelivr.net/npm/daisyui@5" rel="stylesheet" type="text/css" />
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>


value00: docs/llms_daisyui.txt
value01:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
```
5. A CSS file with Tailwind CSS and daisyUI looks like this (if it's a node dependency)
```css
@import "tailwindcss";
@plugin "daisyui";
```


value00: docs/llms_daisyui.txt
value01:
### checkbox
Checkboxes are used to select or deselect a value

[checkbox docs](https://daisyui.com/components/checkbox/)

#### Class names
- component: `checkbox`
- color: `checkbox-primary`, `checkbox-secondary`, `checkbox-accent`, `checkbox-neutral`, `checkbox-success`, `checkbox-warning`, `checkbox-info`, `checkbox-error`
- size: `checkbox-xs`, `checkbox-sm`, `checkbox-md`, `checkbox-lg`, `checkbox-xl`

#### Syntax
```html
<input type="checkbox" class="checkbox {MODIFIER}" />
```

#### Rules
- {MODIFIER} is optional and can have one of each color/size class names

### collapse
Collapse is used for showing and hiding content

[collapse docs](https://daisyui.com/components/collapse/)


value00: src/lib/utils/toast.js
value01:
export function error(message, duration) {
  return addToast(message, 'error', duration);
}

export default {
  add: addToast,
  remove: removeToast,
  info,
  success,
  warning,
  error,
};


value00: src/lib/utils/toast.js
value01:
import { writable } from 'svelte/store';

/**
 * Toast notification system using DaisyUI
 */

export const toasts = writable([]);

let toastId = 0;

/**
 * Add a toast notification
 * @param {string} message - Toast message
 * @param {'info'|'success'|'warning'|'error'} type - Toast type
 * @param {number} duration - Duration in milliseconds
 */
export function addToast(message, type = 'info', duration = 3000) {
  const id = ++toastId;
  
  toasts.update((items) => [
    ...items,
    { id, message, type, duration },
  ]);
  
  // Auto-remove after duration
  if (duration > 0) {
    setTimeout(() => {
      removeToast(id);
    }, duration);
  }
  
  return id;
}

/**
 * Remove a toast by ID
 * @param {number} id - Toast ID
 */


value00: docs/llms_daisyui.txt
value01:
#### Syntax
```html
<span class="badge {MODIFIER}">Badge</span>
```

#### Rules
- {MODIFIER} is optional and can have one of each style/color/size class names
- Can be used inside text or buttons
- To create an empty badge, just remove the text between the span tags

### breadcrumbs
Breadcrumbs helps users to navigate

[breadcrumbs docs](https://daisyui.com/components/breadcrumbs/)

#### Class names
- component: `breadcrumbs`

#### Syntax
```html
<div class="breadcrumbs">
  <ul><li><a>Link</a></li></ul>
</div>
```

#### Rules
- breadcrumbs only has one main class name
- Can contain icons inside the links
- If you set `max-width` or the list gets larger than the container it will scroll

### button
Buttons allow the user to take actions

[button docs](https://daisyui.com/components/button/)


value00: src/lib/utils/toast.js
value01:
export function removeToast(id) {
  toasts.update((items) => items.filter((item) => item.id !== id));
}

/**
 * Show info toast
 * @param {string} message
 * @param {number} duration
 */
export function info(message, duration) {
  return addToast(message, 'info', duration);
}

/**
 * Show success toast
 * @param {string} message
 * @param {number} duration
 */
export function success(message, duration) {
  return addToast(message, 'success', duration);
}

/**
 * Show warning toast
 * @param {string} message
 * @param {number} duration
 */
export function warning(message, duration) {
  return addToast(message, 'warning', duration);
}

/**
 * Show error toast
 * @param {string} message
 * @param {number} duration
 */


value00: docs/llms_daisyui.txt
value01:
## daisyUI 5 usage rules
1. We can give styles to a HTML element by adding daisyUI class names to it. By adding a component class name, part class names (if there's any available for that component), and modifier class names (if there's any available for that component)
2. Components can be customized using Tailwind CSS utility classes if the customization is not possible using the existing daisyUI classes. For example `btn px-10` sets a custom horizontal padding to a `btn`


value00: docs/llms_daisyui.txt
value01:
  <li><a>Item 1</a></li>
  <li><a>Item 2</a></li>
</ul>
```
To open/close the drawer, use a label that points to the `drawer-toggle` input:
```html
<label for="my-drawer" class="btn drawer-button">Open/close drawer</label>
```
Example: This sidebar is always visible on large screen, can be toggled on small screen:
```html
<div class="drawer lg:drawer-open">
  <input id="my-drawer-3" type="checkbox" class="drawer-toggle" />
  <div class="drawer-content flex flex-col items-center justify-center">
    <!-- Page content here -->
    <label for="my-drawer-3" class="btn drawer-button lg:hidden">
      Open drawer
    </label>


value00: docs/llms_daisyui.txt
value01:
3. If customization of daisyUI styles using Tailwind CSS utility classes didn't work because of CSS specificity issues, you can use the `!` at the end of the Tailwind CSS utility class to override the existing styles. For example `btn bg-red-500!` sets a custom background color to a `btn` forcefully. This is a last resort solution and should be used sparingly
4. If a specific component or something similar to it doesn't exist in daisyUI, you can create your own component using Tailwind CSS utility
5. when using Tailwind CSS `flex` and `grid` for layout, it should be responsive using Tailwind CSS responsive utility prefixes.
6. Only allowed class names are existing daisyUI class names or Tailwind CSS utility classes.


value00: src/lib/types/test.types.ts
value01:
;
  SeqScr: number;
  SeqRpt: number;
  VisibleScr: number | string | boolean;
  VisibleRpt: number | string | boolean;
  CountStat: number | boolean;
  StartDate?: string;
  EndDate?: string;

  // Technical details
  DisciplineID?: number;
  DepartmentID?: number;
  ResultType?: ResultType;
  RefType?: RefType;
  VSet?: string;
  Unit1?: string;
  Factor?: number;
  Unit2?: string;
  Decimal?: number;
  ReqQty?: number;
  ReqQtyUnit?: string;
  CollReq?: string;
  Method?: string;
  ExpectedTAT?: number;

  // Calculated test specific
  FormulaCode?: string;

  // Nested data
  testdefcal?: CalcDetails[];
  testdefgrp?: GroupMember[];
  testmap?: TestMapping[];
  testdeftech?: TechDetail[];
  refnum?: RefNumRange[];
  reftxt?: RefTxtRange[];
}


value00: src/lib/types/test.types.ts
value01:
{
  // Base fields
  TestSiteID: number;
  TestSiteCode: string;
  TestSiteName: string;
  TestType: TestType;
  TestTypeLabel: string;
  Description?: string;
  SiteID: number;
  SeqScr: number;
  SeqRpt: number;
  VisibleScr: number | string | boolean;
  VisibleRpt: number | string | boolean;
  CountStat: number | boolean


value00: src/lib/types/test.types.ts
value01:
/**
 * Test Management Type Definitions
 * Based on CLQMS API Specification
 */

// Test Types
export type TestType = 'TEST' | 'PARAM' | 'CALC' | 'GROUP' | 'TITLE';
export type ResultType = 'NMRIC' | 'RANGE' | 'TEXT' | 'VSET' | 'NORES';
export type RefType = 'RANGE' | 'THOLD' | 'VSET' | 'TEXT' | 'NOREF';
export type NumRefType = 'REF' | 'CRTC' | 'VAL' | 'RERUN';
export type RangeType = 'RANGE' | 'THOLD';
export type TxtRefType = 'Normal' | 'Abnormal' | 'Critical';
export type SexType = '0' | '1' | '2';
export type SexLabel = 'All' | 'Female' | 'Male';

// Base Test Summary (from list endpoint)


value00: src/lib/types/test.types.ts
value01:
;
  VisibleRpt?: number | boolean;
  CountStat?: number | boolean;
  StartDate?: string;

  // Nested details based on TestType
  details?: {
    // Technical (TEST/PARAM/CALC)
    DisciplineID?: number;
    DepartmentID?: number;
    ResultType?: ResultType;
    RefType?: RefType;
    VSet?: string;
    Unit1?: string;
    Factor?: number;
    Unit2?: string;
    Decimal?: number;
    ReqQty?: number;
    ReqQtyUnit?: string;
    CollReq?: string;
    Method?: string;
    ExpectedTAT?: number;

    // CALC only
    FormulaCode?: string;

    // GROUP only
    members?: number[];
  };

  // Reference ranges (TEST/PARAM)
  refnum?: Omit<RefNumRange, 'RefNumID' | 'NumRefTypeLabel' | 'RangeTypeLabel' | 'SexLabel' | 'LowSignLabel' | 'HighSignLabel'>[]


value00: src/lib/types/test.types.ts
value01:
// Technical Details
export interface TechDetail {
  DisciplineID?: number;
  DepartmentID?: number;
  DisciplineName?: string;
  DepartmentName?: string;
  ResultType?: ResultType;
  RefType?: RefType;
  VSet?: string;
  Unit1?: string;
  Factor?: number;
  Unit2?: string;
  Decimal?: number;
  ReqQty?: number;
  ReqQtyUnit?: string;
  CollReq?: string;
  Method?: string;
  ExpectedTAT?: number;
}

// Calculation Details (extends TechDetail)
export interface CalcDetails extends TechDetail {
  FormulaCode?: string;
}


value00: src/lib/types/test.types.ts
value01:
// Create/Update Test Payload
export interface CreateTestPayload {
  SiteID: number;
  TestSiteCode: string;
  TestSiteName: string;
  TestType: TestType;
  Description?: string;
  SeqScr?: number;
  SeqRpt?: number;
  VisibleScr?: number | boolean;
  VisibleRpt?: number | boolean;
  CountStat?: number | boolean;
  StartDate?: string;

  // Nested details based on TestType


value00: src/lib/types/test.types.ts
value01:
// API Response Types
export interface ApiResponse<T> {
  status: 'success' | 'created' | 'error';
  message: string;
  data: T;
}

export interface TestListResponse extends ApiResponse<TestSummary[]> {
  pagination?: {
    page: number;
    perPage: number;
    total: number;
  };
}

export interface TestDetailResponse extends ApiResponse<TestDetail> {}

export interface CreateTestResponse extends ApiResponse<{ TestSiteId: number }> {
  status: 'created';
}

export interface UpdateTestResponse extends ApiResponse<{ TestSiteId: number }> {}

export interface DeleteTestResponse extends ApiResponse<{ TestSiteId: number; EndDate: string }> {}

// Filter Options
export interface TestFilterOptions {
  TestType?: TestType;
  VisibleScr?: number;
  VisibleRpt?: number;
  search?: string;
}


value00: src/lib/types/test.types.ts
value01:
// Tab Configuration
export interface TabConfig {
  id: string;
  label: string;
  icon: string;
  isVisible: (testType: TestType) => boolean;
}

// Test Type Configuration (for UI display)
export interface TestTypeConfig {
  label: string;
  badgeClass: string;
  description: string;
}

// API Response Types
export interface ApiResponse<T> {
  status: 'success' | 'created' | 'error';
  message: string;
  data: T;
}


value00: src/lib/types/test.types.ts
value01:
// Numeric Reference Range
export interface RefNumRange {
  RefNumID?: number;
  NumRefType: NumRefType;
  NumRefTypeLabel?: string;
  RangeType: RangeType;
  RangeTypeLabel?: string;
  Sex: SexType;
  SexLabel?: string;
  AgeStart: number;
  AgeEnd: number;
  LowSign?: string;
  LowSignLabel?: string;
  Low?: number;
  HighSign?: string;
  HighSignLabel?: string;
  High?: number;
  Flag?: string;
  Interpretation?: string;
}

// Text Reference Range
export interface RefTxtRange {
  RefTxtID?: number;
  TxtRefType: TxtRefType;
  TxtRefTypeLabel?: string;
  Sex: SexType;
  SexLabel?: string;
  AgeStart: number;
  AgeEnd: number;
  RefTxt: string;
  Flag?: string;
}

// Complete Test Detail (from GET /api/tests/:id)
export interface TestDetail


value00: src/lib/types/test.types.ts
value01:
// Calculation Details (extends TechDetail)
export interface CalcDetails extends TechDetail {
  FormulaCode?: string;
}

// Group Member
export interface GroupMember {
  TestSiteID: number;
  TestSiteCode: string;
  TestSiteName: string;
  TestType: TestType;
  Seq?: number;
}

// Test Mapping
export interface TestMapping {
  TestMapID?: number;
  HostType?: string;
  HostID?: string | number;
  HostDataSource?: string;
  HostTestCode?: string;
  HostTestName?: string;
  ClientType?: string;
  ClientID?: string | number;
  ClientDataSource?: string;
  ConDefID?: string | number;
  ClientTestCode?: string;
  ClientTestName?: string;
}

// Numeric Reference Range


value00: src/lib/types/test.types.ts
value01:
  refnum?: Omit<RefNumRange, 'RefNumID' | 'NumRefTypeLabel' | 'RangeTypeLabel' | 'SexLabel' | 'LowSignLabel' | 'HighSignLabel'>[];
  reftxt?: Omit<RefTxtRange, 'RefTxtID' | 'TxtRefTypeLabel' | 'SexLabel'>[];

  // Mappings (all types)
  testmap?: TestMapping[];
}

// Update Test Payload (includes TestSiteID)
export interface UpdateTestPayload extends CreateTestPayload {
  TestSiteID: number;
}

// Form State (for Svelte 5 runes)


value00: src/lib/types/test.types.ts
value01:
// Form State (for Svelte 5 runes)
export interface TestFormState {
  TestSiteID?: number;
  TestSiteCode: string;
  TestSiteName: string;
  TestType: TestType;
  Description?: string;
  SiteID: number;
  SeqScr: number;
  SeqRpt: number;
  VisibleScr: boolean;
  VisibleRpt: boolean;
  CountStat: boolean;
  StartDate?: string;
  details: {
    DisciplineID?: number;
    DepartmentID?: number;
    ResultType?: ResultType;
    RefType?: RefType;
    VSet?: string;
    Unit1?: string;
    Factor?: number;
    Unit2?: string;
    Decimal?: number;
    ReqQty?: number;
    ReqQtyUnit?: string;
    CollReq?: string;
    Method?: string;
    ExpectedTAT?: number;
    FormulaCode?: string;
    members?: number[];
  };
  refnum: RefNumRange[];
  reftxt: RefTxtRange[];
  testmap: TestMapping[];
}


value00: src/lib/types/test.types.ts
value01:
export type SexType = '0' | '1' | '2';
export type SexLabel = 'All' | 'Female' | 'Male';

// Base Test Summary (from list endpoint)
export interface TestSummary {
  TestSiteID: number;
  TestSiteCode: string;
  TestSiteName: string;
  TestType: TestType;
  TestTypeLabel: string;
  SeqScr: number;
  SeqRpt: number;
  VisibleScr: number | string;
  VisibleRpt: number | string;
  CountStat: number;
  StartDate: string;
  EndDate?: string;
  DisciplineID?: number;
  DepartmentID?: number;
  DisciplineName?: string;
  DepartmentName?: string;
  IsActive?: string | number;
}

// Technical Details


value00: docs/llms-full_sveltekit.txt
value01:
You can also check your code from the command line using [`npx sv check`](https://svelte.dev/docs/cli/sv-check).


## Getting help

Don't be shy about asking for help in the [Discord chatroom](/chat)! You can also find answers on [Stack Overflow](https://stackoverflow.com/questions/tagged/svelte).

# .svelte files

Components are the building blocks of Svelte applications. They are written into `.svelte` files, using a superset of HTML.

All three sections — script, styles and markup — are optional.

<!-- prettier-ignore -->
```svelte
/// file: MyComponent.svelte
<script module>
	// module-level logic goes here
	// (you will rarely use this)
</script>

<script>
	// instance-level logic goes here
</script>

<!-- markup (zero or more items) goes here -->


value00: docs/llms-full_sveltekit.txt
value01:
They differ from normal JavaScript functions in important ways, however:

- You don't need to import them — they are part of the language
- They're not values — you can't assign them to a variable or pass them as arguments to a function
- Just like JavaScript keywords, they are only valid in certain positions (the compiler will help you if you put them in the wrong place)

> [!LEGACY]
> Runes didn't exist prior to Svelte 5.

# $state

The `$state` rune allows you to create _reactive state_, which means that your UI _reacts_ when it changes.

```svelte
<script>
	let count = $state(0);
</script>


value00: docs/llms-full_sveltekit.txt
value01:
<SYSTEM>This is the full developer documentation for Svelte and SvelteKit.</SYSTEM>

# Start of Svelte documentation


# Overview

Svelte is a framework for building user interfaces on the web. It uses a compiler to turn declarative components written in HTML, CSS and JavaScript...

```svelte
<!--- file: App.svelte --->
<script>
	function greet() {
		alert('Welcome to Svelte!');
	}
</script>

<button onclick={greet}>click me</button>

<style>
	button {
		font-size: 2em;
	}
</style>
```

...into lean, tightly optimized JavaScript.

You can use it to build anything on the web, from standalone components to ambitious full stack apps (using Svelte's companion application framework, [SvelteKit](../kit)) and everything in between.


value00: docs/llms-full_sveltekit.txt
value01:
> [!NOTE] If you are using TypeScript and import such exports from a `module` block into a `.ts` file, make sure to have your editor setup so that TypeScript knows about them. This is the case for our VS Code extension and the IntelliJ plugin, but in other cases you might need to setup our [TypeScript editor plugin](https://www.npmjs.com/package/typescript-svelte-plugin).

> [!LEGACY]
> In Svelte 4, this script tag was created using `<script context="module">`

## `<style>`

CSS inside a `<style>` block will be scoped to that component.

```svelte
<style>
	p {
		/* this will only affect <p> elements in this component */
		color: burlywood;
	}
</style>
```

For more information, head to the section on [styling](scoped-styles).


value00: docs/llms-full_sveltekit.txt
value01:
<p>{a} + {b} = {a + b}</p>
```

If the input is empty or invalid (in the case of `type="number"`), the value is `undefined`.

Since 5.6.0, if an `<input>` has a `defaultValue` and is part of a form, it will revert to that value instead of the empty string when the form is reset. Note that for the initial render the value of the binding takes precedence unless it is `null` or `undefined`.

```svelte
<script>
	let value = $state('');
</script>

<form>
	<input bind:value defaultValue="not the empty string">
	<input type="reset" value="Reset">
</form>
```

> [!NOTE]
> Use reset buttons sparingly, and ensure that users won't accidentally click them while trying to submit the form.

## `<input bind:checked>`


value00: docs/llms-full_sveltekit.txt
value01:
## `<input bind:checked>`

Checkbox inputs can be bound with `bind:checked`:

```svelte
<label>
	<input type="checkbox" bind:checked={accepted} />
	Accept terms and conditions
</label>
```

Since 5.6.0, if an `<input>` has a `defaultChecked` attribute and is part of a form, it will revert to that value instead of `false` when the form is reset. Note that for the initial render the value of the binding takes precedence unless it is `null` or `undefined`.

```svelte
<script>
	let checked = $state(true);
</script>

<form>
	<input type="checkbox" bind:checked defaultChecked={true}>
	<input type="reset" value="Reset">
</form>
```

> [!NOTE] Use `bind:group` for radio inputs instead of `bind:checked`.


value00: docs/llms-full_sveltekit.txt
value01:
<!-- TODO describe behaviour of `export` -->

## `<script module>`

A `<script>` tag with a `module` attribute runs once when the module first evaluates, rather than for each component instance. Variables declared in this block can be referenced elsewhere in the component, but not vice versa.

```svelte
<script module>
	let total = 0;
</script>

<script>
	total += 1;
	console.log(`instantiated ${total} times`);
</script>
```

You can `export` bindings from this block, and they will become exports of the compiled module. You cannot `export default`, since the default export is the component itself.


value00: docs/llms-full_sveltekit.txt
value01:
These pages serve as reference documentation. If you're new to Svelte, we recommend starting with the [interactive tutorial](/tutorial) and coming back here when you have questions.

You can also try Svelte online in the [playground](/playground) or, if you need a more fully-featured environment, on [StackBlitz](https://sveltekit.new).

# Getting started

We recommend using [SvelteKit](../kit), which lets you [build almost anything](../kit/project-types). It's the official application framework from the Svelte team and powered by [Vite](https://vite.dev/). Create a new project with:

```sh
npx sv create myapp
cd myapp
npm install
npm run dev
```

Don't worry if you don't know Svelte yet! You can ignore all the nice features SvelteKit brings on top for now and dive into it later.


value00: docs/llms-full_sveltekit.txt
value01:
> [!NOTE] Use `bind:group` for radio inputs instead of `bind:checked`.

## `<input bind:indeterminate>`

Checkboxes can be in an [indeterminate](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/indeterminate) state, independently of whether they are checked or unchecked:

```svelte
<script>
	let checked = $state(false);
	let indeterminate = $state(true);
</script>

<form>
	<input type="checkbox" bind:checked bind:indeterminate>

	{#if indeterminate}
		waiting...
	{:else if checked}
		checked
	{:else}
		unchecked
	{/if}
</form>
```

## `<input bind:group>`


value00: docs/llms-full_sveltekit.txt
value01:
> [!NOTE] When you update properties of proxies, the original object is _not_ mutated. If you need to use your own proxy handlers in a state proxy, [you should wrap the object _after_ wrapping it in `$state`](https://svelte.dev/playground/hello-world?version=latest#H4sIAAAAAAAACpWR3WoDIRCFX2UqhWyIJL3erAulL9C7XnQLMe5ksbUqOpsfln33YuyGFNJC8UKdc2bOhw7Myk9kJXsJ0nttO9jcR5KEG9AWJDwHdzwxznbaYGTl68Do5JM_FRifuh-9X8Y9Gkq1rYx4q66cJbQUWcmqqIL2VDe2IYMEbvuOikBADi-GJDSkXG-phId0G-frye2DO2psQYDFQ0Ys8gQO350dUkEydEg82T0GOs0nsSG9g2IqgxACZueo2ZUlpdvoDC6N64qsg1QKY8T2bpZp8gpIfbCQ85Zn50Ud82HkeY83uDjspenxv3jXcSDyjPWf9L1vJf0GH666J-jLu1ery4dV257IWXBWGa0-xFDMQdTTn2ScxWKsn86ROsLwQxqrVR5QM84Ij8TKFD2-cUZSm4O2LSt30kQcvwCgCmfZnAIAAA==).


value00: docs/llms-full_sveltekit.txt
value01:
If `true`, causes extra code to be added that will perform runtime checks and provide debugging information during development.

</div>
</div>

<div class="ts-block-property">

```dts
generate?: 'client' | 'server' | false;
```

<div class="ts-block-property-details">

<div class="ts-block-property-bullets">

- <span class="tag">default</span> `'client'`

</div>

If `"client"`, Svelte emits code designed to run in the browser.
If `"server"`, Svelte emits code suitable for server-side rendering.
If `false`, nothing is generated. Useful for tooling that is only interested in warnings.

</div>
</div>

<div class="ts-block-property">

```dts
filename?: string;
```

<div class="ts-block-property-details">

Used for debugging hints and sourcemaps. Your bundler plugin will set it automatically.


value00: docs/llms-full_sveltekit.txt
value01:
```svelte
<script>
	let count = $state(0);
</script>

<button onclick={() => count++}>
	clicks: {count}
</button>
```

Unlike other frameworks you may have encountered, there is no API for interacting with state — `count` is just a number, rather than an object or a function, and you can update it like you would update any other variable.

### Deep state

If `$state` is used with an array or a simple object, the result is a deeply reactive _state proxy_. [Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) allow Svelte to run code when you read or write properties, including via methods like `array.push(...)`, triggering granular updates.


value00: docs/llms-full_sveltekit.txt
value01:
<script>
	// instance-level logic goes here
</script>

<!-- markup (zero or more items) goes here -->

<style>
	/* styles go here */
</style>
```

## `<script>`

A `<script>` block contains JavaScript (or TypeScript, when adding the `lang="ts"` attribute) that runs when a component instance is created. Variables declared (or imported) at the top level can be referenced in the component's markup.

In addition to normal JavaScript, you can use _runes_ to declare [component props]($props) and add reactivity to your component. Runes are covered in the next section.

<!-- TODO describe behaviour of `export` -->


value00: docs/llms-full_sveltekit.txt
value01:
## Alternatives to SvelteKit

You can also use Svelte directly with Vite via [vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte) by running `npm create vite@latest` and selecting the `svelte` option (or, if working with an existing project, adding the plugin to your `vite.config.js` file). With this, `npm run build` will generate HTML, JS, and CSS files inside the `dist` directory. In most cases, you will probably need to [choose a routing library](/packages#routing) as well.

>[!NOTE] Vite is often used in standalone mode to build [single page apps (SPAs)](../kit/glossary#SPA), which you can also [build with SvelteKit](../kit/single-page-apps).

There are also [plugins for other bundlers](/packages#bundler-plugins), but we recommend Vite.


value00: docs/llms-full_sveltekit.txt
value01:
<div class="ts-block-property-bullets">

- <span class="tag">default</span> `process.cwd() on node-like environments, undefined elsewhere`

</div>

Used for ensuring filenames don't leak filesystem information. Your bundler plugin will set it automatically.

</div>
</div>

<div class="ts-block-property">

```dts
warningFilter?: (warning: Warning) => boolean;
```

<div class="ts-block-property-details">

A function that gets a `Warning` as an argument and returns a boolean.
Use this to filter out warnings. Return `true` to keep the warning, `false` to discard it.

</div>
</div>

<div class="ts-block-property">

```dts
experimental?: {/*…*/}
```

<div class="ts-block-property-details">

<div class="ts-block-property-bullets">

- <span class="tag since">available since</span> v5.36


value00: docs/llms-full_sveltekit.txt
value01:
You can now write unit tests for code inside your `.js/.ts` files:

```js
/// file: multiplier.svelte.test.js
import { flushSync } from 'svelte';
import { expect, test } from 'vitest';
import { multiplier } from './multiplier.svelte.js';

test('Multiplier', () => {
	let double = multiplier(0, 2);

	expect(double.value).toEqual(0);

	double.set(5);

	expect(double.value).toEqual(10);
});
```

```js
/// file: multiplier.svelte.js
/**
 * @param {number} initial
 * @param {number} k
 */
export function multiplier(initial, k) {
	let count = $state(initial);

	return {
		get value() {
			return count * k;
		},
		/** @param {number} c */
		set: (c) => {
			count = c;
		}
	};
}
```

### Using runes inside your test files


value00: docs/llms-full_sveltekit.txt
value01:
> [!NOTE]
> Function bindings are available in Svelte 5.9.0 and newer.

## `<input bind:value>`

A `bind:value` directive on an `<input>` element binds the input's `value` property:

<!-- prettier-ignore -->
```svelte
<script>
	let message = $state('hello');
</script>

<input bind:value={message} />
<p>{message}</p>
```

In the case of a numeric input (`type="number"` or `type="range"`), the value will be coerced to a number ([demo](/playground/untitled#H4sIAAAAAAAAE6WPwYoCMQxAfyWEPeyiOOqx2w74Hds9pBql0IllmhGXYf5dKqwiyILsLXnwwsuI-5i4oPkaUX8yo7kCnKNQV7dNzoty4qSVBSr8jG-Poixa0KAt2z5mbb14TaxA4OCtKCm_rz4-f2m403WltrlrYhMFTtcLNkoeFGqZ8yhDF7j3CCHKzpwoDexGmqCL4jwuPUJHZ-dxVcfmyYGe5MAv-La5pbxYFf5Z9Zf_UJXb-sEMquFgJJhBmGyTW5yj8lnRaD_w9D1dAKSSj7zqAQAA)):


value00: docs/llms-full_sveltekit.txt
value01:
You can find more information about these in [page options](page-options).

### +page.server.js

If your `load` function can only run on the server — for example, if it needs to fetch data from a database or you need to access private [environment variables]($env-static-private) like API keys — then you can rename `+page.js` to `+page.server.js` and change the `PageLoad` type to `PageServerLoad`.

```js
/// file: src/routes/blog/[slug]/+page.server.js

// @filename: ambient.d.ts
declare global {
	const getPostFromDatabase: (slug: string) => {
		title: string;
		content: string;
	}
}


value00: docs/llms-full_sveltekit.txt
value01:
Note that if you destructure a reactive value, the references are not reactive — as in normal JavaScript, they are evaluated at the point of destructuring:

```js
let todos = [{ done: false, text: 'add more todos' }];
// ---cut---
let { done, text } = todos[0];

// this will not affect the value of `done`
todos[0].done = !todos[0].done;
```

### Classes

Class instances are not proxied. Instead, you can use `$state` in class fields (whether public or private), or as the first assignment to a property immediately inside the `constructor`:

```js
// @errors: 7006 2554
class Todo {
	done = $state(false);


value00: docs/llms-full_sveltekit.txt
value01:
// @filename: ambient.d.ts
declare global {
	const getPostFromDatabase: (slug: string) => {
		title: string;
		content: string;
	}
}

export {};

// @filename: index.js
// ---cut---
import { error } from '@sveltejs/kit';

/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
	const post = await getPostFromDatabase(params.slug);

	if (post) {
		return post;
	}

	error(404, 'Not found');
}
```

During client-side navigation, SvelteKit will load this data from the server, which means that the returned value must be serializable using [devalue](https://github.com/rich-harris/devalue). See [`load`](load) for full details of the API.

Like `+page.js`, `+page.server.js` can export [page options](page-options) — `prerender`, `ssr` and `csr`.


value00: docs/llms-full_sveltekit.txt
value01:
> [!LEGACY]
> This is a concept that didn't exist prior to Svelte 5

# What are runes?

> [!NOTE] **rune** /ruːn/ _noun_
>
> A letter or mark used as a mystical or magic symbol.

Runes are symbols that you use in `.svelte` and `.svelte.js`/`.svelte.ts` files to control the Svelte compiler. If you think of Svelte as a language, runes are part of the syntax — they are _keywords_.

Runes have a `$` prefix and look like functions:

```js
let message = $state('hello');
```

They differ from normal JavaScript functions in important ways, however:


value00: docs/llms-full_sveltekit.txt
value01:
There are also [plugins for other bundlers](/packages#bundler-plugins), but we recommend Vite.

## Editor tooling

The Svelte team maintains a [VS Code extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode), and there are integrations with various other [editors](https://sveltesociety.dev/collection/editor-support-c85c080efc292a34) and tools as well.

You can also check your code from the command line using [`npx sv check`](https://svelte.dev/docs/cli/sv-check).


value00: docs/llms-full_sveltekit.txt
value01:
### render_tag_invalid_call_expression

```
Calling a snippet function using apply, bind or call is not allowed
```

### render_tag_invalid_expression

```
`{@render ...}` tags can only contain call expressions
```

### render_tag_invalid_spread_argument

```
cannot use spread arguments in `{@render ...}` tags
```

### rune_invalid_arguments

```
`%rune%` cannot be called with arguments
```

### rune_invalid_arguments_length

```
`%rune%` must be called with %args%
```

### rune_invalid_computed_property

```
Cannot access a computed property of a rune
```

### rune_invalid_name

```
`%name%` is not a valid rune
```

### rune_invalid_spread

```
`%rune%` cannot be called with a spread argument
```


value00: docs/llms-full_sveltekit.txt
value01:
You won't need a Node server or server capable of running JavaScript to deploy this page. It will only server render your page while building your project for the purposes of outputting an `.html` page that can be served from any static web host.

## Apache

To run an SPA on [Apache](https://httpd.apache.org/), you should add a `static/.htaccess` file to route requests to the fallback page:


value00: docs/llms-full_sveltekit.txt
value01:
... and the browser would auto-insert a `<tbody>` element:

```svelte
<table>
	<tbody>
		<tr>
			<td>hi</td>
		</tr>
	</tbody>
</table>
```

Svelte 5 is more strict about the HTML structure and will throw a compiler error in cases where the browser would repair the DOM.

## Other breaking changes

### Stricter `@const` assignment validation

Assignments to destructured parts of a `@const` declaration are no longer allowed. It was an oversight that this was ever allowed.

### :is(...), :has(...), and :where(...) are scoped


value00: docs/llms-full_sveltekit.txt
value01:
SvelteKit will 'walk up the tree' looking for the closest error boundary — if the file above didn't exist it would try `src/routes/blog/+error.svelte` and then `src/routes/+error.svelte` before rendering the default error page. If _that_ fails (or if the error was thrown from the `load` function of the root `+layout`, which sits 'above' the root `+error`), SvelteKit will bail out and render a static fallback error page, which you can customise by creating a `src/error.html` file.

If the error occurs inside a `load` function in `+layout(.server).js`, the closest error boundary in the tree is an `+error.svelte` file _above_ that layout (not next to it).

If no route can be found (404), `src/routes/+error.svelte` (or the default error page, if that file does not exist) will be used.


value00: docs/llms-full_sveltekit.txt
value01:
export {};

// @filename: index.js
// ---cut---
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
	event.locals.user = await getUser(event.cookies.get('sessionid'));
	return resolve(event);
}
```

```js
/// file: src/routes/account/+page.server.js
// @filename: ambient.d.ts
declare namespace App {
	interface Locals {
		user: {
			name: string;
		} | null
	}
}

// @filename: index.js
// ---cut---
/** @type {import('./$types').PageServerLoad} */
export function load(event) {
	return {
		user: event.locals.user
	};
}

/** @satisfies {import('./$types').Actions} */
export const actions = {
	logout: async (event) => {
		event.cookies.delete('sessionid', { path: '/' });
		event.locals.user = null;
	}
};
```

## Progressive enhancement


value00: docs/llms-full_sveltekit.txt
value01:
For more information, head to the section on [styling](scoped-styles).

# .svelte.js and .svelte.ts files

Besides `.svelte` files, Svelte also operates on `.svelte.js` and `.svelte.ts` files.

These behave like any other `.js` or `.ts` module, except that you can use runes. This is useful for creating reusable reactive logic, or sharing reactive state across your app (though note that you [cannot export reassigned state]($state#Passing-state-across-modules)).

> [!LEGACY]
> This is a concept that didn't exist prior to Svelte 5


value00: docs/llms-full_sveltekit.txt
value01:
		// unset it...
		src = undefined;

		$effect(() => {
			// ...and reset after we've mounted
			src = initial;
		});
	}
</script>

<img {src} />
```

### hydration_html_changed

```
The value of an `{@html ...}` block changed between server and client renders. The client value will be ignored in favour of the server value
```

```
The value of an `{@html ...}` block %location% changed between server and client renders. The client value will be ignored in favour of the server value
```

If the `{@html ...}` value changes between the server and the client, it will not be repaired during hydration, i.e. the server value will be kept. That's because change detection during hydration is expensive and usually unnecessary.


value00: docs/llms-full_sveltekit.txt
value01:
```js
/// file: svelte.config.js
import adapter from '@sveltejs/adapter-static';

/** @type {import('@sveltejs/kit').Config} */
const config = {
	kit: {
		adapter: adapter({
			fallback: '200.html' // may differ from host to host
		})
	}
};

export default config;
```

The `fallback` page is an HTML page created by SvelteKit from your page template (e.g. `app.html`) that loads your app and navigates to the correct route. For example [Surge](https://surge.sh/help/adding-a-200-page-for-client-side-routing), a static web host, lets you add a `200.html` file that will handle any requests that don't correspond to static assets or prerendered pages.


value00: docs/llms-full_sveltekit.txt
value01:
On some hosts it may be something else entirely — consult your platform's documentation. We recommend avoiding `index.html` if possible as it may conflict with prerendering.

> [!NOTE] Note that the fallback page will always contain absolute asset paths (i.e. beginning with `/` rather than `.`) regardless of the value of [`paths.relative`](configuration#paths), since it is used to respond to requests for arbitrary paths.

## Prerendering individual pages

If you want certain pages to be prerendered, you can re-enable `ssr` alongside `prerender` for just those parts of your app:

```js
/// file: src/routes/my-prerendered-page/+page.js
export const prerender = true;
export const ssr = true;
```


value00: docs/llms-full_sveltekit.txt
value01:
/** @type {import('./$types').PageLoad} */
export function load({ params }) {
	if (params.slug === 'hello-world') {
		return {
			title: 'Hello world!',
			content: 'Welcome to our blog. Lorem ipsum dolor sit amet...'
		};
	}

	error(404, 'Not found');
}
```

This function runs alongside `+page.svelte`, which means it runs on the server during server-side rendering and in the browser during client-side navigation. See [`load`](load) for full details of the API.

As well as `load`, `+page.js` can export values that configure the page's behaviour:

- `export const prerender = true` or `false` or `'auto'`
- `export const ssr = true` or `false`
- `export const csr = true` or `false`

You can find more information about these in [page options](page-options).

### +page.server.js


value00: docs/llms-full_sveltekit.txt
value01:
To fix this, either silence the warning with a [`svelte-ignore`](basic-markup#Comments) comment, or ensure that the value stays the same between server and client. If you really need the value to change on hydration, you can force an update like this:

```svelte
<script>
	let { markup } = $props();

	if (typeof window !== 'undefined') {
		// stash the value...
		const initial = markup;

		// unset it...
		markup = undefined;

		$effect(() => {
			// ...and reset after we've mounted
			markup = initial;
		});
	}
</script>

{@html markup}
```

### hydration_mismatch

```
Hydration failed because the initial UI does not match what was rendered on the server
```

```
Hydration failed because the initial UI does not match what was rendered on the server. The error occurred near %location%
```


value00: docs/llms-full_sveltekit.txt
value01:
```js
/// file: src/hooks.server.js
// @filename: ambient.d.ts
declare namespace App {
	interface Locals {
		user: {
			name: string;
		} | null
	}
}

// @filename: global.d.ts
declare global {
	function getUser(sessionid: string | undefined): {
		name: string;
	};
}

export {};


value00: docs/llms-full_sveltekit.txt
value01:
### Using runes inside your test files

Since Vitest processes your test files the same way as your source files, you can use runes inside your tests as long as the filename includes `.svelte`:

```js
/// file: multiplier.svelte.test.js
import { flushSync } from 'svelte';
import { expect, test } from 'vitest';
import { multiplier } from './multiplier.svelte.js';

test('Multiplier', () => {
	let count = $state(0);
	let double = multiplier(() => count, 2);

	expect(double.value).toEqual(0);

	count = 5;

	expect(double.value).toEqual(10);
});
```


value00: docs/llms-full_sveltekit.txt
value01:
This adapter will be installed by default when you use [`adapter-auto`](adapter-auto). If you plan on staying with Cloudflare, you can switch from [`adapter-auto`](adapter-auto) to using this adapter directly so that `event.platform` is emulated during local development, type declarations are automatically applied, and the ability to set Cloudflare-specific options is provided.

## Comparisons

- `adapter-cloudflare` – supports all SvelteKit features; builds for Cloudflare Workers Static Assets and Cloudflare Pages
- `adapter-cloudflare-workers` – deprecated. Supports all SvelteKit features; builds for Cloudflare Workers Sites
- `adapter-static` – only produces client-side static assets; compatible with Cloudflare Workers Static Assets and Cloudflare Pages

## Usage


value00: docs/llms-full_sveltekit.txt
value01:
## Progressive enhancement

In the preceding sections we built a `/login` action that [works without client-side JavaScript](https://kryogenix.org/code/browser/everyonehasjs.html) — not a `fetch` in sight. That's great, but when JavaScript _is_ available we can progressively enhance our form interactions to provide a better user experience.

### use:enhance

The easiest way to progressively enhance a form is to add the `use:enhance` action:

```svelte
/// file: src/routes/login/+page.svelte
<script>
	+++import { enhance } from '$app/forms';+++

	/** @type {import('./$types').PageProps} */
	let { form } = $props();
</script>


value00: docs/llms-full_sveltekit.txt
value01:
To fix this, either silence the warning with a [`svelte-ignore`](basic-markup#Comments) comment, or ensure that the value stays the same between server and client. If you really need the value to change on hydration, you can force an update like this:

```svelte
<script>
	let { src } = $props();

	if (typeof window !== 'undefined') {
		// stash the value...
		const initial = src;

		// unset it...
		src = undefined;

		$effect(() => {
			// ...and reset after we've mounted
			src = initial;
		});
	}
</script>


value00: docs/llms-full_sveltekit.txt
value01:
Instead, we can specify which queries should be refreshed in response to a particular form submission. This is called a _single-flight mutation_, and there are two ways to achieve it. The first is to refresh the query on the server, inside the form handler:

```js
import * as v from 'valibot';
import { error, redirect } from '@sveltejs/kit';
import { query, form } from '$app/server';
const slug = '';
const post = { id: '' };
/** @type {any} */
const externalApi = '';
// ---cut---
export const getPosts = query(async () => { /* ... */ });

export const getPost = query(v.string(), async (slug) => { /* ... */ });

export const createPost = form(
	v.object({/* ... */}),
	async (data) => {
		// form logic goes here...


value00: docs/llms-full_sveltekit.txt
value01:
```svelte
<script>
	let a = $state(1);
	let b = $state(2);
</script>

<label>
	<input type="number" bind:value={a} min="0" max="10" />
	<input type="range" bind:value={a} min="0" max="10" />
</label>

<label>
	<input type="number" bind:value={b} min="0" max="10" />
	<input type="range" bind:value={b} min="0" max="10" />
</label>

<p>{a} + {b} = {a + b}</p>
```

If the input is empty or invalid (in the case of `type="number"`), the value is `undefined`.


value00: docs/llms-full_sveltekit.txt
value01:
Inputs that work together can use `bind:group` ([demo](/playground/untitled#H4sIAAAAAAAAE62T32_TMBDH_5XDQkpbrct7SCMGEvCEECDxsO7BSW6L2c227EvbKOv_jp0f6jYhQKJv5_P3PvdL1wstH1Bk4hMSGdgbRzUssFaM9VJciFtF6EV23QvubNRFR_BPUVfWXvodEkdfKT3-zl8Zzag5YETuK6csF1u9ZUIGNo4VkYQNvPYsGRfJF5JKJ8s3QRJE6WoFb2Nq6K-ck13u2Sl9Vxxhlc6QUBIFnz9Brm9ifJ6esun81XoNd860FmtwslYGlLYte5AO4aHlVhJ1gIeKWq92COt1iMtJlkhFPkgh1rHZiiF6K6BUus4G5KafGznCTlIbVUMfQZUWMJh5OrL-C_qjMYSwb1DyiH7iOEuCb1ZpWTUjfHqcwC_GWDVY3ZfmME_SGttSmD9IHaYatvWHIc6xLyqad3mq6KuqcCwnWn9p8p-p71BqP2IH81zc9w2in-od7XORP7ayCpd5YCeXI_-p59mObPF9WmwGpx3nqS2Gzw8TO3zOaS5_GqUXyQUkS3h8hOSz0ZhMESHGc0c4Hm3MAn00t1wrb0l2GZRkqvt4sXwczm6Qh8vnUJzI2LV4vAkvqWgfehTZrSSPx19WiVfFfAQAAA==)):

```svelte
<!--- file: BurritoChooser.svelte --->
<script>
	let tortilla = $state('Plain');


value00: docs/llms-full_sveltekit.txt
value01:
Allow `await` keyword in deriveds, template expressions, and the top level of components

</div>
</div></div>

</div>
</div></div>

## Preprocessor

A script/style preprocessor that takes a string of code and returns a processed version.

<div class="ts-block">

```dts
type Preprocessor = (options: {
	/**
	 * The script/style tag content
	 */
	content: string;
	/**
	 * The attributes on the script/style tag
	 */
	attributes: Record<string, string | boolean>;
	/**
	 * The whole Svelte file content
	 */
	markup: string;
	/**
	 * The filename of the Svelte file
	 */
	filename?: string;
}) => Processed | void | Promise<Processed | void>;
```

</div>

## PreprocessorGroup

A preprocessor group is a set of preprocessors that are applied to a Svelte file.


value00: docs/llms-full_sveltekit.txt
value01:
<div class="ts-block-property-details">

Used for debugging hints and sourcemaps. Your bundler plugin will set it automatically.

</div>
</div>

<div class="ts-block-property">

```dts
rootDir?: string;
```

<div class="ts-block-property-details">

<div class="ts-block-property-bullets">

- <span class="tag">default</span> `process.cwd() on node-like environments, undefined elsewhere`


value00: docs/llms-full_sveltekit.txt
value01:
Previously, Svelte did not analyse selectors inside `:is(...)`, `:has(...)`, and `:where(...)`, effectively treating them as global. Svelte 5 analyses them in the context of the current component. Some selectors may now therefore be treated as unused if they were relying on this treatment. To fix this, use `:global(...)` inside the `:is(...)/:has(...)/:where(...)` selectors.

When using Tailwind's `@apply` directive, add a `:global` selector to preserve rules that use Tailwind-generated `:is(...)` selectors:

<!-- prettier-ignore -->
```css
main +++:global+++ {
	@apply bg-blue-100 dark:bg-blue-900;
}
```


value00: docs/llms-full_sveltekit.txt
value01:
> [!NOTE] If you don't handle 404 cases, they will appear in [`handleError`](hooks#Shared-hooks-handleError)

## Optional parameters

A route like `[lang]/home` contains a parameter named `lang` which is required. Sometimes it's beneficial to make these parameters optional, so that in this example both `home` and `en/home` point to the same page. You can do that by wrapping the parameter in another bracket pair: `[[lang]]/home`

Note that an optional route parameter cannot follow a rest parameter (`[...rest]/[[optional]]`), since parameters are matched 'greedily' and the optional parameter would always be unused.

## Matching


value00: docs/llms-full_sveltekit.txt
value01:
State is proxified recursively until Svelte finds something other than an array or simple object (like a class or an object created with `Object.create`). In a case like this...

```js
let todos = $state([
	{
		done: false,
		text: 'add more todos'
	}
]);
```

...modifying an individual todo's property will trigger updates to anything in your UI that depends on that specific property:

```js
let todos = [{ done: false, text: 'add more todos' }];
// ---cut---
todos[0].done = !todos[0].done;
```

If you push a new object to the array, it will also be proxified:

```js
let todos = [{ done: false, text: 'add more todos' }];
// ---cut---
todos.push({
	done: false,
	text: 'eat lunch'
});
```


value00: docs/llms-full_sveltekit.txt
value01:
- `include` defines routes that will invoke a function, and defaults to `['/*']`
- `exclude` defines routes that will _not_ invoke a function — this is a faster and cheaper way to serve your app's static assets. This array can include the following special values:
	- `<build>` contains your app's build artifacts (the files generated by Vite)
	- `<files>` contains the contents of your `static` directory
	- `<redirects>` contains a list of pathnames from your [`_redirects` file](https://developers.cloudflare.com/pages/configuration/redirects/) at the root
	- `<prerendered>` contains a list of prerendered pages
	- `<all>` (the default) contains all of the above


value00: docs/llms-full_sveltekit.txt
value01:
...and augmenting your routes:

```
src/routes/fruits/[page+++=fruit+++]
```

If the pathname doesn't match, SvelteKit will try to match other routes (using the sort order specified below), before eventually returning a 404.

Each module in the `params` directory corresponds to a matcher, with the exception of `*.test.js` and `*.spec.js` files which may be used to unit test your matchers.

> [!NOTE] Matchers run both on the server and in the browser.

## Sorting

It's possible for multiple routes to match a given path. For example each of these routes would match `/foo-abc`:

```sh
src/routes/[...catchall]/+page.svelte
src/routes/[[a=x]]/+page.svelte
src/routes/[b]/+page.svelte
src/routes/foo-[c]/+page.svelte
src/routes/foo-abc/+page.svelte
```


value00: docs/llms-full_sveltekit.txt
value01:
## Usage

First, disable SSR for the pages you don't want to prerender. These pages will be served via the fallback page; for example, to serve all pages via the fallback by default, you can update the root layout as shown below. You should [opt back into prerendering individual pages and directories](#Prerendering-individual-pages) where possible.
```js
/// file: src/routes/+layout.js
export const ssr = false;
```

If you don't have any server-side logic (i.e. `+page.server.js`, `+layout.server.js` or `+server.js` files) you can use [`adapter-static`](adapter-static) to create your SPA. Install `adapter-static` with `npm i -D @sveltejs/adapter-static` and add it to your `svelte.config.js` with the `fallback` option:


value00: docs/llms-full_sveltekit.txt
value01:
```
`%name%` is not a valid rune
```

### rune_invalid_spread

```
`%rune%` cannot be called with a spread argument
```

### rune_invalid_usage

```
Cannot use `%rune%` rune in non-runes mode
```

### rune_missing_parentheses

```
Cannot use rune without parentheses
```

### rune_removed

```
The `%name%` rune has been removed
```

### rune_renamed

```
`%name%` is now `%replacement%`
```

### runes_mode_invalid_import

```
%name% cannot be used in runes mode
```

### script_duplicate

```
A component can have a single top-level `<script>` element and/or a single top-level `<script module>` element
```

### script_invalid_attribute_value

```
If the `%name%` attribute is supplied, it must be a boolean attribute
```


value00: docs/llms-full_sveltekit.txt
value01:
<div class="ts-block-property-details">

<div class="ts-block-property-bullets">

- <span class="tag since">available since</span> v5.36

</div>

Experimental options

<div class="ts-block-property-children"><div class="ts-block-property">

```dts
async?: boolean;
```

<div class="ts-block-property-details">

<div class="ts-block-property-bullets">

- <span class="tag since">available since</span> v5.36

</div>

Allow `await` keyword in deriveds, template expressions, and the top level of components

</div>
</div></div>

</div>
</div></div>


value00: docs/llms-full_sveltekit.txt
value01:
	function clear() {
		files = new DataTransfer().files; // null or undefined does not work
	}
</script>

<label for="avatar">Upload a picture:</label>
<input accept="image/png, image/jpeg" bind:files id="avatar" name="avatar" type="file" />
<button onclick={clear}>clear</button>
```

`FileList` objects also cannot be modified, so if you want to e.g. delete a single file from the list, you need to create a new `DataTransfer` object and add the files you want to keep.

> [!NOTE] `DataTransfer` may not be available in server-side JS runtimes. Leaving the state that is bound to `files` uninitialized prevents potential errors if components are server-side rendered.

## `<select bind:value>`


value00: docs/llms-full_sveltekit.txt
value01:
## Apache

To run an SPA on [Apache](https://httpd.apache.org/), you should add a `static/.htaccess` file to route requests to the fallback page:

```
<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteBase /
	RewriteRule ^200\.html$ - [L]
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteRule . /200.html [L]
</IfModule>
```

# Cloudflare

To deploy to [Cloudflare Workers](https://workers.cloudflare.com/) or [Cloudflare Pages](https://pages.cloudflare.com/), use [`adapter-cloudflare`](https://github.com/sveltejs/kit/tree/main/packages/adapter-cloudflare).


value00: docs/llms-full_sveltekit.txt
value01:
```json
{
	"svelte": "./dist/index.js"
}
```

### sideEffects

The `sideEffects` field in `package.json` is used by bundlers to determine if a module may contain code that has side effects. A module is considered to have side effects if it makes changes that are observable from other scripts outside the module when it's imported. For example, side effects include modifying global variables or the prototype of built-in JavaScript objects. Because a side effect could potentially affect the behavior of other parts of the application, these files/modules will be included in the final bundle regardless of whether their exports are used in the application. It is a best practice to avoid side effects in your code.


value00: docs/llms-full_sveltekit.txt
value01:
```svelte
<div data-sveltekit-preload-data={condition ? 'hover' : false}>
```

# Service workers

Service workers act as proxy servers that handle network requests inside your app. This makes it possible to make your app work offline, but even if you don't need offline support (or can't realistically implement it because of the type of app you're building), it's often worth using service workers to speed up navigation by precaching your built JS and CSS.

In SvelteKit, if you have a `src/service-worker.js` file (or `src/service-worker/index.js`) it will be bundled and automatically registered. You can change the [location of your service worker](configuration#files) if you need to.


value00: docs/llms-full_sveltekit.txt
value01:
To fix it, `bind:` to the value instead of just passing a property (i.e. in this example do `<Parent bind:value />`).

### ownership_invalid_mutation

```
Mutating unbound props (`%name%`, at %location%) is strongly discouraged. Consider using `bind:%prop%={...}` in %parent% (or using a callback) instead
```

Consider the following code:


value00: docs/llms-full_sveltekit.txt
value01:
Setting the `sideEffects` field in `package.json` can help the bundler to be more aggressive in eliminating unused exports from the final bundle, a process known as tree-shaking. This results in smaller and more efficient bundles. Different bundlers handle `sideEffects` in various manners. While not necessary for Vite, we recommend that libraries state that all CSS files have side effects so that your library will be [compatible with webpack](https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free). This is the configuration that comes with newly created projects:

```json
/// file: package.json
{
	"sideEffects": ["**/*.css"]
}
```


value00: docs/llms-full_sveltekit.txt
value01:
> [!NOTE] `+error.svelte` is _not_ used when an error occurs inside [`handle`](hooks#Server-hooks-handle) or a [+server.js](#server) request handler.

You can read more about error handling [here](errors).

## +layout

So far, we've treated pages as entirely standalone components — upon navigation, the existing `+page.svelte` component will be destroyed, and a new one will take its place.

But in many apps, there are elements that should be visible on _every_ page, such as top-level navigation or a footer. Instead of repeating them in every `+page.svelte`, we can put them in _layouts_.

### +layout.svelte


value00: docs/llms-full_sveltekit.txt
value01:
- `-t`/`--types` — whether or not to create type definitions (`d.ts` files). We strongly recommend doing this as it fosters ecosystem library quality. Defaults to `true`
- `--tsconfig` - the path to a tsconfig or jsconfig. When not provided, searches for the next upper tsconfig/jsconfig in the workspace path.


value00: docs/llms-full_sveltekit.txt
value01:
			if (response) {
				return response;
			}
		}

		// for everything else, try the network first, but
		// fall back to the cache if we're offline
		try {
			const response = await fetch(event.request);

			// if we're offline, fetch can return a value that is not a Response
			// instead of throwing - and we can't pass this non-Response to respondWith
			if (!(response instanceof Response)) {
				throw new Error('invalid response from fetch');
			}

			if (response.status === 200) {
				cache.put(event.request, response.clone());
			}

			return response;
		} catch (err) {
			const response = await cache.match(event.request);


value00: docs/llms-full_sveltekit.txt
value01:
	function onclick() {
		// Will log `{ count: ... }` rather than `Proxy { ... }`
		console.log($state.snapshot(counter));
	}
</script>
```

This is handy when you want to pass some state to an external library or API that doesn't expect a proxy, such as `structuredClone`.

## `$state.eager`

When state changes, it may not be reflected in the UI immediately if it is used by an `await` expression, because [updates are synchronized](await-expressions#Synchronized-updates).

In some cases, you may want to update the UI as soon as the state changes. For example, you might want to update a navigation bar when the user clicks on a link, so that they get visual feedback while waiting for the new page to load. To do this, use `$state.eager(value)`:


value00: docs/llms-full_sveltekit.txt
value01:
```svelte
<form {...register}>
	<label>
		Username
		<input {...register.fields.username.as('text')} />
	</label>

	<label>
		Password
		<input +++{...register.fields._password.as('password')}+++ />
	</label>

	<button>Sign up!</button>
</form>
```

In this example, if the data does not validate, only the first `<input>` will be populated when the page reloads.

### Single-flight mutations

By default, all queries used on the page (along with any `load` functions) are automatically refreshed following a successful form submission. This ensures that everything is up-to-date, but it's also inefficient: many queries will be unchanged, and it requires a second trip to the server to get the updated data.


value00: docs/llms-full_sveltekit.txt
value01:
If you're using the [Git integration](https://developers.cloudflare.com/pages/get-started/git-integration/), your build settings should look like this:

- Framework preset – SvelteKit
- Build command – `npm run build` or `vite build`
- Build output directory – `.svelte-kit/cloudflare`


Once configured, go to the **Runtime** section of your project settings, and add the `nodejs_als` compability flag to enable the [Node.js AsyncLocalStorage](https://developers.cloudflare.com/workers/configuration/compatibility-flags/#nodejs-asynclocalstorage). Alternatively, do this in your wrangler config using the `compatibility_flags` array.

### Further reading


value00: docs/llms-full_sveltekit.txt
value01:
You can [disable automatic registration](configuration#serviceWorker) if you need to register the service worker with your own logic or use another solution. The default registration looks something like this:

```js
if ('serviceWorker' in navigator) {
	addEventListener('load', function () {
		navigator.serviceWorker.register('./path/to/service-worker.js');
	});
}
```

## Inside the service worker


value00: docs/llms-full_sveltekit.txt
value01:
By default, each layout inherits the layout above it. Sometimes that isn't what you want - in this case, [advanced layouts](advanced-routing#Advanced-layouts) can help you.

### +layout.js

Just like `+page.svelte` loading data from `+page.js`, your `+layout.svelte` component can get data from a [`load`](load) function in `+layout.js`.

```js
/// file: src/routes/settings/+layout.js
/** @type {import('./$types').LayoutLoad} */
export function load() {
	return {
		sections: [
			{ slug: 'profile', title: 'Profile' },
			{ slug: 'notifications', title: 'Notifications' }
		]
	};
}
```

If a `+layout.js` exports [page options](page-options) — `prerender`, `ssr` and `csr` — they will be used as defaults for child pages.


value00: docs/llms-full_sveltekit.txt
value01:
	/** @type {import('./$types').PageProps} */
	let { form } = $props();
</script>

<form method="POST" +++use:enhance+++>
```

> [!NOTE] `use:enhance` can only be used with forms that have `method="POST"` and point to actions defined in a `+page.server.js` file. It will not work with `method="GET"`, which is the default for forms without a specified method. Attempting to use `use:enhance` on forms without `method="POST"` or posting to a `+server.js` endpoint will result in an error.

> [!NOTE] Yes, it's a little confusing that the `enhance` action and `<form action>` are both called 'action'. These docs are action-packed. Sorry.

Without an argument, `use:enhance` will emulate the browser-native behaviour, just without the full-page reloads. It will:


value00: docs/llms-full_sveltekit.txt
value01:
Data returned from a layout's `load` function is also available to all its child pages:

```svelte
<!--- file: src/routes/settings/profile/+page.svelte --->
<script>
	/** @type {import('./$types').PageProps} */
	let { data } = $props();

	console.log(data.sections); // [{ slug: 'profile', title: 'Profile' }, ...]
</script>
```

> [!NOTE] Often, layout data is unchanged when navigating between pages. SvelteKit will intelligently rerun [`load`](load) functions when necessary.

### +layout.server.js

To run your layout's `load` function on the server, move it to `+layout.server.js`, and change the `LayoutLoad` type to `LayoutServerLoad`.

Like `+layout.js`, `+layout.server.js` can export [page options](page-options) — `prerender`, `ssr` and `csr`.

## +server


value00: docs/llms-full_sveltekit.txt
value01:
A `+page.server.js` file can also export _actions_. If `load` lets you read data from the server, `actions` let you write data _to_ the server using the `<form>` element. To learn how to use them, see the [form actions](form-actions) section.

## +error

If an error occurs during `load`, SvelteKit will render a default error page. You can customise this error page on a per-route basis by adding an `+error.svelte` file:

```svelte
<!--- file: src/routes/blog/[slug]/+error.svelte --->
<script>
	import { page } from '$app/state';
</script>

<h1>{page.status}: {page.error.message}</h1>
```

> [!LEGACY]
> `$app/state` was added in SvelteKit 2.12. If you're using an earlier version or are using Svelte 4, use `$app/stores` instead.


value00: docs/llms-full_sveltekit.txt
value01:
Like `+layout.js`, `+layout.server.js` can export [page options](page-options) — `prerender`, `ssr` and `csr`.

## +server

As well as pages, you can define routes with a `+server.js` file (sometimes referred to as an 'API route' or an 'endpoint'), which gives you full control over the response. Your `+server.js` file exports functions corresponding to HTTP verbs like `GET`, `POST`, `PATCH`, `PUT`, `DELETE`, `OPTIONS`, and `HEAD` that take a [`RequestEvent`](@sveltejs-kit#RequestEvent) argument and return a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object.

For example we could create an `/api/random-number` route with a `GET` handler:

```js
/// file: src/routes/api/random-number/+server.js
import { error } from '@sveltejs/kit';


value00: docs/llms-full_sveltekit.txt
value01:
<!-- prettier-ignore -->
```css
main +++:global+++ {
	@apply bg-blue-100 dark:bg-blue-900;
}
```

### CSS hash position no longer deterministic

Previously Svelte would always insert the CSS hash last. This is no longer guaranteed in Svelte 5. This is only breaking if you [have very weird css selectors](https://stackoverflow.com/questions/15670631/does-the-order-of-classes-listed-on-an-item-affect-the-css).

### Scoped CSS uses :where(...)

To avoid issues caused by unpredictable specificity changes, scoped CSS selectors now use `:where(.svelte-xyz123)` selector modifiers alongside `.svelte-xyz123` (where `xyz123` is, as previously, a hash of the `<style>` contents). You can read more detail [here](https://github.com/sveltejs/svelte/pull/10443).


value00: docs/llms-full_sveltekit.txt
value01:
## Best practices

You should avoid using SvelteKit-specific modules like `$app/environment` in your packages unless you intend for them to only be consumable by other SvelteKit projects. E.g. rather than using `import { browser } from '$app/environment'` you could use `import { BROWSER } from 'esm-env'` ([see esm-env docs](https://github.com/benmccann/esm-env)). You may also wish to pass in things like the current URL or a navigation action as a prop rather than relying directly on `$app/state`, `$app/navigation`, etc. Writing your app in this more generic fashion will also make it easier to set up tools for testing, UI demos and so on.


value00: docs/llms-full_sveltekit.txt
value01:
export default config;
```

## Options

### config

Path to your [Wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/configuration/). If you would like to use a Wrangler configuration filename other than `wrangler.jsonc`, `wrangler.json`, or `wrangler.toml` you can specify it using this option.

### platformProxy

Preferences for the emulated `platform.env` local bindings. See the [getPlatformProxy](https://developers.cloudflare.com/workers/wrangler/api/#parameters-1) Wrangler API documentation for a full list of options.

### fallback


value00: docs/llms-full_sveltekit.txt
value01:
```json
{
	"exports": {
		".": {
			"types": "./dist/index.d.ts",
// changing `svelte` to `default` is a breaking change:
---			"svelte": "./dist/index.js"---
+++			"default": "./dist/index.js"+++
		},
// removing this is a breaking change:
---		"./foo": {
			"types": "./dist/foo.d.ts",
			"svelte": "./dist/foo.js",
			"default": "./dist/foo.js"
		},---
// adding this is ok:
+++		"./bar": {
			"types": "./dist/bar.d.ts",
			"svelte": "./dist/bar.js",
			"default": "./dist/bar.js"
		}+++
	}
}
```

## Source maps


value00: docs/llms-full_sveltekit.txt
value01:
## Inside the service worker

Inside the service worker you have access to the [`$service-worker` module]($service-worker), which provides you with the paths to all static assets, build files and prerendered pages. You're also provided with an app version string, which you can use for creating a unique cache name, and the deployment's `base` path. If your Vite config specifies `define` (used for global variable replacements), this will be applied to service workers as well as your server/client builds.

The following example caches the built app and any files in `static` eagerly, and caches all other requests as they happen. This would make each page work offline once visited.


value00: docs/llms-full_sveltekit.txt
value01:
```js
':'.charCodeAt(0).toString(16); // '3a', hence '[x+3a]'
```

You can also use Unicode escape sequences. Generally you won't need to as you can use the unencoded character directly, but if — for some reason — you can't have a filename with an emoji in it, for example, then you can use the escaped characters. In other words, these are equivalent:

```
src/routes/[u+d83e][u+dd2a]/+page.svelte
src/routes/🤪/+page.svelte
```

The format for a Unicode escape sequence is `[u+nnnn]` where `nnnn` is a valid value between `0000` and `10ffff`. (Unlike JavaScript string escaping, there's no need to use surrogate pairs to represent code points above `ffff`.) To learn more about Unicode encodings, consult [Programming with Unicode](https://unicodebook.readthedocs.io/unicode_encodings.html).


value00: docs/llms-full_sveltekit.txt
value01:
SvelteKit needs to know which route is being requested. To do so, it sorts them according to the following rules...

- More specific routes are higher priority (e.g. a route with no parameters is more specific than a route with one dynamic parameter, and so on)
- Parameters with [matchers](#Matching) (`[name=type]`) are higher priority than those without (`[name]`)
- `[[optional]]` and `[...rest]` parameters are ignored unless they are the final part of the route, in which case they are treated with lowest priority. In other words `x/[[y]]/z` is treated equivalently to `x/z` for the purposes of sorting
- Ties are resolved alphabetically


value00: docs/llms-full_sveltekit.txt
value01:
An auth system is tightly coupled to a web framework because most of the code lies in validating user input, handling errors, and directing users to the appropriate next page. As a result, many of the generic JS auth libraries include one or more web frameworks within them. For this reason, many users will find it preferrable to follow a SvelteKit-specific guide such as the examples found in [Lucia](https://lucia-auth.com/) rather than having multiple web frameworks inside their project.

# Performance

Out of the box, SvelteKit does a lot of work to make your applications as performant as possible:


value00: docs/llms-full_sveltekit.txt
value01:
```js
/// file: src/service-worker.js
// Disables access to DOM typings like `HTMLElement` which are not available
// inside a service worker and instantiates the correct globals
/// <reference no-default-lib="true"/>
/// <reference lib="esnext" />
/// <reference lib="webworker" />

// Ensures that the `$service-worker` import has proper type definitions
/// <reference types="@sveltejs/kit" />

// Only necessary if you have an import from `$env/static/public`
/// <reference types="../.svelte-kit/ambient.d.ts" />

import { build, files, version } from '$service-worker';

// This gives `self` the correct types
const self = /** @type {ServiceWorkerGlobalScope} */ (/** @type {unknown} */ (globalThis.self));

// Create a unique cache name for this deployment
const CACHE = `cache-${version}`;


value00: docs/llms-full_sveltekit.txt
value01:
## Source maps

You can create so-called declaration maps (`d.ts.map` files) by setting `"declarationMap": true` in your `tsconfig.json`. This will allow editors such as VS Code to go to the original `.ts` or `.svelte` file when using features like _Go to Definition_. This means you also need to publish your source files alongside your dist folder in a way that the relative path inside the declaration files leads to a file on disk. Assuming that you have all your library code inside `src/lib` as suggested by Svelte's CLI, this is as simple as adding `src/lib` to `files` in your `package.json`:

```json
{
	"files": [
		"dist",
		"!dist/**/*.test.*",
		"!dist/**/*.spec.*",
		+++"src/lib",
		"!src/lib/**/*.test.*",
		"!src/lib/**/*.spec.*"+++
	]
}
```

## Options


value00: docs/llms-full_sveltekit.txt
value01:
		// Refresh `getPosts()` on the server, and send
		// the data back with the result of `createPost`
		+++await getPosts().refresh();+++

		// Redirect to the newly created page
		redirect(303, `/blog/${slug}`);
	}
);

export const updatePost = form(
	v.object({/* ... */}),
	async (data) => {
		// form logic goes here...
		const result = externalApi.update(post);

		// The API already gives us the updated post,
		// no need to refresh it, we can set it directly
		+++await getPost(post.id).set(result);+++
	}
);
```

The second is to drive the single-flight mutation from the client, which we'll see in the section on [`enhance`](#form-enhance).

### Returns and redirects


value00: docs/llms-full_sveltekit.txt
value01:
```js
let person = $state.raw({
	name: 'Heraclitus',
	age: 49
});

// this will have no effect
person.age += 1;

// this will work, because we're creating a new person
person = {
	name: 'Heraclitus',
	age: 50
};
```

This can improve performance with large arrays and objects that you weren't planning to mutate anyway, since it avoids the cost of making them reactive. Note that raw state can _contain_ reactive state (for example, a raw array of reactive objects).

As with `$state`, you can declare class fields using `$state.raw`.

## `$state.snapshot`

To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`:

```svelte
<script>
	let counter = $state({ count: 0 });


value00: docs/llms-full_sveltekit.txt
value01:
const ASSETS = [
	...build, // the app itself
	...files  // everything in `static`
];

self.addEventListener('install', (event) => {
	// Create a new cache and add all files to it
	async function addFilesToCache() {
		const cache = await caches.open(CACHE);
		await cache.addAll(ASSETS);
	}

	event.waitUntil(addFilesToCache());
});


value00: docs/llms-full_sveltekit.txt
value01:
The first option is to require people using your library to set the `moduleResolution` option in their `tsconfig.json` (or `jsconfig.json`) to `bundler` (available since TypeScript 5, the best and recommended option in the future), `node16` or `nodenext`. This opts TypeScript into actually looking at the exports map and resolving the types correctly.


value00: docs/llms-full_sveltekit.txt
value01:
### script_invalid_attribute_value

```
If the `%name%` attribute is supplied, it must be a boolean attribute
```

### script_invalid_context

```
If the context attribute is supplied, its value must be "module"
```

### script_reserved_attribute

```
The `%name%` attribute is reserved and cannot be used
```

### slot_attribute_duplicate

```
Duplicate slot name '%name%' in <%component%>
```

### slot_attribute_invalid

```
slot attribute must be a static value
```

### slot_attribute_invalid_placement

```
Element with a slot='...' attribute must be a child of a component or a descendant of a custom element
```

### slot_default_duplicate

```
Found default slot content alongside an explicit slot="default"
```


value00: docs/llms-full_sveltekit.txt
value01:
- Code-splitting, so that only the code you need for the current page is loaded
- Asset preloading, so that 'waterfalls' (of files requesting other files) are prevented
- File hashing, so that your assets can be cached forever
- Request coalescing, so that data fetched from separate server `load` functions is grouped into a single HTTP request
- Parallel loading, so that separate universal `load` functions fetch data simultaneously
- Data inlining, so that requests made with `fetch` during server rendering can be replayed in the browser without issuing a new request
- Conservative invalidation, so that `load` functions are only re-run when necessary


value00: docs/llms-full_sveltekit.txt
value01:
	event.waitUntil(addFilesToCache());
});

self.addEventListener('activate', (event) => {
	// Remove previous cached data from disk
	async function deleteOldCaches() {
		for (const key of await caches.keys()) {
			if (key !== CACHE) await caches.delete(key);
		}
	}

	event.waitUntil(deleteOldCaches());
});

self.addEventListener('fetch', (event) => {
	// ignore POST requests etc
	if (event.request.method !== 'GET') return;

	async function respond() {
		const url = new URL(event.request.url);
		const cache = await caches.open(CACHE);

		// `build`/`files` can always be served from the cache
		if (ASSETS.includes(url.pathname)) {
			const response = await cache.match(url.pathname);

			if (response) {
				return response;
			}
		}


value00: docs/llms-full_sveltekit.txt
value01:
### `<slot>` elements in declarative shadow roots are preserved

Svelte 4 replaced the `<slot />` tag in all places with its own version of slots. Svelte 5 preserves them in the case they are a child of a `<template shadowrootmode="...">` element.

### `<svelte:element>` tag must be an expression

In Svelte 4, `<svelte:element this="div">` is valid code. This makes little sense — you should just do `<div>`. In the vanishingly rare case that you _do_ need to use a literal value for some reason, you can do this:

```svelte
<svelte:element this=+++{+++"div"+++}+++>
```


value00: docs/llms-full_sveltekit.txt
value01:
	/** @type {string[]} */
	let fillings = $state([]);
</script>

<!-- grouped radio inputs are mutually exclusive -->
<label><input type="radio" bind:group={tortilla} value="Plain" /> Plain</label>
<label><input type="radio" bind:group={tortilla} value="Whole wheat" /> Whole wheat</label>
<label><input type="radio" bind:group={tortilla} value="Spinach" /> Spinach</label>

<!-- grouped checkbox inputs populate an array -->
<label><input type="checkbox" bind:group={fillings} value="Rice" /> Rice</label>
<label><input type="checkbox" bind:group={fillings} value="Beans" /> Beans</label>
<label><input type="checkbox" bind:group={fillings} value="Cheese" /> Cheese</label>
<label><input type="checkbox" bind:group={fillings} value="Guac (extra)" /> Guac (extra)</label>
```


value00: docs/llms-full_sveltekit.txt
value01:
- Prerendering (configurable on a per-route basis, if necessary) so that pages without dynamic data can be served instantaneously
- Link preloading, so that data and code requirements for a client-side navigation are eagerly anticipated


value00: docs/llms-full_sveltekit.txt
value01:
> [!NOTE] `build` and `prerendered` are empty arrays during development

## Other solutions

SvelteKit's service worker implementation is designed to be easy to work with and is probably a good solution for most users. However, outside of SvelteKit, many PWA applications leverage the [Workbox](https://web.dev/learn/pwa/workbox) library. If you're used to using Workbox you may prefer [Vite PWA plugin](https://vite-pwa-org.netlify.app/frameworks/sveltekit.html).

## References

For more general information on service workers, we recommend [the MDN web docs](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers).

# Server-only modules


value00: docs/llms-full_sveltekit.txt
value01:
## Sessions vs tokens

After the user has provided their credentials such as a username and password, we want to allow them to use the application without needing to provide their credentials again for future requests. Users are commonly authenticated on subsequent requests with either a session identifier or signed token such as a JSON Web Token (JWT).

Session IDs are most commonly stored in a database. They can be immediately revoked, but require a database query to be made on each request.

In contrast, JWT generally are not checked against a datastore, which means they cannot be immediately revoked. The advantage of this method is improved latency and reduced load on your datastore.

## Integration points


value00: docs/llms-full_sveltekit.txt
value01:
<nav>
	<a href="/">Home</a>
	<a href="/about">About</a>
	<a href="/settings">Settings</a>
</nav>

{@render children()}
```

If we create pages for `/`, `/about` and `/settings`...

```html
/// file: src/routes/+page.svelte
<h1>Home</h1>
```

```html
/// file: src/routes/about/+page.svelte
<h1>About</h1>
```

```html
/// file: src/routes/settings/+page.svelte
<h1>Settings</h1>
```

...the nav will always be visible, and clicking between the three pages will only result in the `<h1>` being replaced.


value00: docs/llms-full_sveltekit.txt
value01:
Note that your site running locally in `dev` mode will exhibit different behaviour than your production app, so you should do performance testing in [preview](building-your-app#Preview-your-app) mode after building.

### Instrumenting

If you see in the network tab of your browser that an API call is taking a long time and you'd like to understand why, you may consider instrumenting your backend with a tool like [OpenTelemetry](https://opentelemetry.io/) or [Server-Timing headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing).

## Optimizing assets

### Images


value00: docs/llms-full_sveltekit.txt
value01:
 update the `form` property, `page.form` and `page.status` on a successful or invalid response, but only if the action is on the same page you're submitting from. For example, if your form looks like `<form action="/somewhere/else" ..>`, the `form` prop and the `page.form` state will _not_ be updated. This is because in the native form submission case you would be redirected to the page the action is on. If you want to have them updated either way, use [`applyAction`](#Progressive-enhancement-Customising-use:enhance)
- reset the `<form>` element
- invalidate all data using `invalidateAll` on a successful response
- call `goto` on a redirect response
- render the nearest `+error` boundary if an error occurs
- [reset focus](accessibility#Focus-management) to the appropriate element


value00: docs/llms-full_sveltekit.txt
value01:
```js
/// file: src/routes/api/random-number/+server.js
import { error } from '@sveltejs/kit';

/** @type {import('./$types').RequestHandler} */
export function GET({ url }) {
	const min = Number(url.searchParams.get('min') ?? '0');
	const max = Number(url.searchParams.get('max') ?? '1');

	const d = max - min;

	if (isNaN(d) || d < 0) {
		error(400, 'min and max must be numbers, and min must be less than max');
	}


value00: docs/llms-full_sveltekit.txt
value01:
In the event that you need to support ancient browsers that don't implement `:where`, you can manually alter the emitted CSS, at the cost of unpredictable specificity changes:

```js
// @errors: 2552
css = css.replace(/:where\((.+?)\)/, '$1');
```

### Error/warning codes have been renamed

Error and warning codes have been renamed. Previously they used dashes to separate the words, they now use underscores (e.g. foo-bar becomes foo_bar). Additionally, a handful of codes have been reworded slightly.

### Reduced number of namespaces

The number of valid namespaces you can pass to the compiler option `namespace` has been reduced to `html` (the default), `mathml` and `svg`.

The `foreign` namespace was only useful for Svelte Native, which we're planning to support differently in a 5.x minor.


value00: docs/llms-full_sveltekit.txt
value01:
## Integration points

Auth [cookies](@sveltejs-kit#Cookies) can be checked inside [server hooks](hooks#Server-hooks). If a user is found matching the provided credentials, the user information can be stored in [`locals`](hooks#Server-hooks-locals).

## Guides

[Lucia](https://lucia-auth.com/) is a good reference for session-based web app auth. It contains example code snippets and projects for implementing session-based auth within SvelteKit and other JS projects. You can add code which follows the Lucia guide to your project with `npx sv create` when creating a new project or `npx sv add lucia` for an existing project.


value00: docs/llms-full_sveltekit.txt
value01:
			return response;
		} catch (err) {
			const response = await cache.match(event.request);

			if (response) {
				return response;
			}

			// if there's no cache, then just error out
			// as there is nothing we can do to respond to this request
			throw err;
		}
	}

	event.respondWith(respond());
});
```

> [!NOTE] Be careful when caching! In some cases, stale data might be worse than data that's unavailable while offline. Since browsers will empty caches if they get too full, you should also be careful about caching large assets like video files.

## During development


value00: docs/llms-full_sveltekit.txt
value01:
You can also put a `+page` directly inside a `(group)`, for example if `/` should be an `(app)` or a `(marketing)` page.

### Breaking out of layouts

The root layout applies to every page of your app — if omitted, it defaults to `{@render children()}`. If you want some pages to have a different layout hierarchy than the rest, then you can put your entire app inside one or more groups _except_ the routes that should not inherit the common layouts.

In the example above, the `/admin` route does not inherit either the `(app)` or `(marketing)` layouts.

### +page@


value00: docs/llms-full_sveltekit.txt
value01:
```html
<a href="path" data-sveltekit-noscroll>Path</a>
```

...will prevent scrolling after the link is clicked.

## Disabling options

To disable any of these options inside an element where they have been enabled, use the `"false"` value:

```html
<div data-sveltekit-preload-data>
	<!-- these links will be preloaded -->
	<a href="/a">a</a>
	<a href="/b">b</a>
	<a href="/c">c</a>

	<div data-sveltekit-preload-data="false">
		<!-- these links will NOT be preloaded -->
		<a href="/d">d</a>
		<a href="/e">e</a>
		<a href="/f">f</a>
	</div>
</div>
```

To apply an attribute to an element conditionally, do this:

```svelte
<div data-sveltekit-preload-data={condition ? 'hover' : false}>
```


value00: docs/llms-full_sveltekit.txt
value01:
Nevertheless, we can't (yet) eliminate all sources of slowness. To eke out maximum performance, you should be mindful of the following tips.

## Diagnosing issues

Google's [PageSpeed Insights](https://pagespeed.web.dev/) and (for more advanced analysis) [WebPageTest](https://www.webpagetest.org/) are excellent ways to understand the performance characteristics of a site that is already deployed to the internet.

Your browser also includes useful developer tools for analysing your site, whether deployed or running locally:


value00: docs/llms-full_sveltekit.txt
value01:
...resulting in this ordering, meaning that `/foo-abc` will invoke `src/routes/foo-abc/+page.svelte`, and `/foo-def` will invoke `src/routes/foo-[c]/+page.svelte` rather than less specific routes:

```sh
src/routes/foo-abc/+page.svelte
src/routes/foo-[c]/+page.svelte
src/routes/[[a=x]]/+page.svelte
src/routes/[b]/+page.svelte
src/routes/[...catchall]/+page.svelte
```

## Encoding

Some characters can't be used on the filesystem — `/` on Linux and Mac, `\ / : * ? " < > |` on Windows. The `#` and `%` characters have special meaning in URLs, and the `[ ] ( )` characters have special meaning to SvelteKit, so these also can't be used directly as part of your route.


value00: docs/llms-full_sveltekit.txt
value01:
The behaviour of `applyAction(result)` depends on `result.type`:

- `success`, `failure` — sets `page.status` to `result.status` and updates `form` and `page.form` to `result.data` (regardless of where you are submitting from, in contrast to `update` from `enhance`)
- `redirect` — calls `goto(result.location, { invalidateAll: true })`
- `error` — renders the nearest `+error` boundary with `result.error`

In all cases, [focus will be reset](accessibility#Focus-management).

### Custom event listener

We can also implement progressive enhancement ourselves, without `use:enhance`, with a normal event listener on the `<form>`:


value00: docs/llms-full_sveltekit.txt
value01:
### fallback

Whether to render a plaintext 404.html page or a rendered SPA fallback page for non-matching asset requests.

For Cloudflare Workers, the default behaviour is to return a null-body 404-status response for non-matching assets requests. However, if the [`assets.not_found_handling`](https://developers.cloudflare.com/workers/static-assets/routing/#2-not_found_handling) Wrangler configuration setting is set to `"404-page"`, this page will be served if a request fails to match an asset. If `assets.not_found_handling` is set to `"single-page-application"`, the adapter will render a SPA fallback `index.html` page regardless of the `fallback` option specified.


value00: docs/llms-full_sveltekit.txt
value01:
## Optimizing assets

### Images

Reducing the size of image files is often one of the most impactful changes you can make to a site's performance. Svelte provides the `@sveltejs/enhanced-img` package, detailed on the [images](images) page, for making this easier. Additionally, Lighthouse is useful for identifying the worst offenders.

### Videos


value00: docs/llms-full_sveltekit.txt
value01:
</div>

## PreprocessorGroup

A preprocessor group is a set of preprocessors that are applied to a Svelte file.

<div class="ts-block">

```dts
interface PreprocessorGroup {/*…*/}
```

<div class="ts-block-property">

```dts
name?: string;
```

<div class="ts-block-property-details">

Name of the preprocessor. Will be a required option in the next major version

</div>
</div>

<div class="ts-block-property">

```dts
markup?: MarkupPreprocessor;
```

<div class="ts-block-property-details"></div>
</div>

<div class="ts-block-property">

```dts
style?: Preprocessor;
```

<div class="ts-block-property-details"></div>
</div>

<div class="ts-block-property">

```dts
script?: Preprocessor;
```

<div class="ts-block-property-details"></div>
</div></div>


value00: docs/llms-full_sveltekit.txt
value01:
### snippet_invalid_export

```
An exported snippet can only reference things declared in a `<script module>`, or other exportable snippets
```

It's possible to export a snippet from a `<script module>` block, but only if it doesn't reference anything defined inside a non-module-level `<script>`. For example you can't do this...

```svelte
<script module>
	export { greeting };
</script>

<script>
	let message = 'hello';
</script>

{#snippet greeting(name)}
	<p>{message} {name}!</p>
{/snippet}
```

...because `greeting` references `message`, which is defined in the second `<script>`.

### snippet_invalid_rest_parameter

```
Snippets do not support rest parameters; use an array instead
```

### snippet_parameter_assignment

```
Cannot reassign or bind to snippet parameter
```


value00: docs/llms-full_sveltekit.txt
value01:
This warning is thrown when Svelte encounters an error while hydrating the HTML from the server. During hydration, Svelte walks the DOM, expecting a certain structure. If that structure is different (for example because the HTML was repaired by the DOM because of invalid HTML), then Svelte will run into issues, resulting in this warning.

During development, this error is often preceded by a `console.error` detailing the offending HTML, which needs fixing.

### invalid_raw_snippet_render

```
The `render` function passed to `createRawSnippet` should return HTML for a single element
```

### legacy_recursive_reactive_block


value00: docs/llms-full_sveltekit.txt
value01:
```svelte
<nav>
	<a href="/" aria-current={$state.eager(pathname) === '/' ? 'page' : null}>home</a>
	<a href="/about" aria-current={$state.eager(pathname) === '/about' ? 'page' : null}>about</a>
</nav>
```

Use this feature sparingly, and only to provide feedback in response to user action — in general, allowing Svelte to coordinate updates will provide a better user experience.

## Passing state into functions

JavaScript is a _pass-by-value_ language — when you call a function, the arguments are the _values_ rather than the _variables_. In other words:

```js
/// file: index.js
// @filename: index.js
// ---cut---
/**
 * @param {number} a
 * @param {number} b
 */
function add(a, b) {
	return a + b;
}

let a = 1;
let b = 2;
let total = add(a, b);
console.log(total); // 3


value00: docs/llms-full_sveltekit.txt
value01:
For Cloudflare Pages, this page will only be served when a request that matches an entry in `routes.exclude` fails to match an asset.

Most of the time `plaintext` is sufficient, but if you are using `routes.exclude` to manually exclude a set of prerendered pages without exceeding the 100 route limit, you may wish to use `spa` instead to avoid showing an unstyled 404 page to users.

See Cloudflare Pages' [Not Found behaviour](https://developers.cloudflare.com/pages/configuration/serving-pages/#not-found-behavior) for more info.

### routes

Only for Cloudflare Pages. Allows you to customise the [`_routes.json`](https://developers.cloudflare.com/pages/functions/routing/#create-a-_routesjson-file) file generated by `adapter-cloudflare`.


value00: docs/llms-full_sveltekit.txt
value01:
```dts
function expoOut(t: number): number;
```

</div>



## linear

<div class="ts-block">

```dts
function linear(t: number): number;
```

</div>



## quadIn

<div class="ts-block">

```dts
function quadIn(t: number): number;
```

</div>



## quadInOut

<div class="ts-block">

```dts
function quadInOut(t: number): number;
```

</div>



## quadOut

<div class="ts-block">

```dts
function quadOut(t: number): number;
```

</div>



## quartIn

<div class="ts-block">

```dts
function quartIn(t: number): number;
```


value00: docs/llms-full_sveltekit.txt
value01:
### +layout.svelte

To create a layout that applies to every page, make a file called `src/routes/+layout.svelte`. The default layout (the one that SvelteKit uses if you don't bring your own) looks like this...

```svelte
<script>
	let { children } = $props();
</script>

{@render children()}
```

...but we can add whatever markup, styles and behaviour we want. The only requirement is that the component includes a `@render` tag for the page content. For example, let's add a nav bar:

```svelte
<!--- file: src/routes/+layout.svelte --->
<script>
	let { children } = $props();
</script>

<nav>
	<a href="/">Home</a>
	<a href="/about">About</a>
	<a href="/settings">Settings</a>
</nav>


value00: docs/llms-full_sveltekit.txt
value01:
	expect(document.body.innerHTML).toBe('<button>1</button>');

	// Remove the component from the DOM
	unmount(component);
});
```

While the process is very straightforward, it is also low level and somewhat brittle, as the precise structure of your component may change frequently. Tools like [@testing-library/svelte](https://testing-library.com/docs/svelte-testing-library/intro/) can help streamline your tests. The above test could be rewritten like this:

```js
/// file: component.test.js
import { render, screen } from '@testing-library/svelte';
import userEvent from '@testing-library/user-event';
import { expect, test } from 'vitest';
import Component from './Component.svelte';

test('Component', async () => {
	const user = userEvent.setup();
	render(Component);


value00: docs/llms-full_sveltekit.txt
value01:
```svelte
<button onclick=+++{() => todo.reset()}>+++
	reset
</button>
```

...or use an arrow function in the class definition:

```js
// @errors: 7006 2554
class Todo {
	done = $state(false);

	constructor(text) {
		this.text = $state(text);
	}

	+++reset = () => {+++
		this.text = '';
		this.done = false;
	}
}
```


value00: docs/llms-full_sveltekit.txt
value01:
## Publishing

To publish the generated package:

```sh
npm publish
```

## Caveats

All relative file imports need to be fully specified, adhering to Node's ESM algorithm. This means that for a file like `src/lib/something/index.js`, you must include the filename with the extension:

```js
// @errors: 2307
import { something } from './something+++/index.js+++';
```

If you are using TypeScript, you need to import `.ts` files the same way, but using a `.js` file ending, _not_ a `.ts` file ending. (This is a TypeScript design decision outside our control.) Setting `"moduleResolution": "NodeNext"` in your `tsconfig.json` or `jsconfig.json` will help you with this.

All files except Svelte files (preprocessed) and TypeScript files (transpiled to JavaScript) are copied across as-is.


value00: docs/llms-full_sveltekit.txt
value01:
### Customising use:enhance

To customise the behaviour, you can provide a `SubmitFunction` that runs immediately before the form is submitted, and (optionally) returns a callback that runs with the `ActionResult`.

```svelte
<form
	method="POST"
	use:enhance={({ formElement, formData, action, cancel, submitter }) => {
		// `formElement` is this `<form>` element
		// `formData` is its `FormData` object that's about to be submitted
		// `action` is the URL to which the form is posted
		// calling `cancel()` will prevent the submission
		// `submitter` is the `HTMLElement` that caused the form to be submitted


value00: docs/llms-full_sveltekit.txt
value01:
## Advanced layouts

By default, the _layout hierarchy_ mirrors the _route hierarchy_. In some cases, that might not be what you want.

### (group)

Perhaps you have some routes that are 'app' routes that should have one layout (e.g. `/dashboard` or `/item`), and others that are 'marketing' routes that should have a different layout (`/about` or `/testimonials`). We can group these routes with a directory whose name is wrapped in parentheses — unlike normal directories, `(app)` and `(marketing)` do not affect the URL pathname of the routes inside them:

```tree
src/routes/
+++│ (app)/+++
│ ├ dashboard/
│ ├ item/
│ └ +layout.svelte
+++│ (marketing)/+++
│ ├ about/
│ ├ testimonials/
│ └ +layout.svelte
├ admin/
└ +layout.svelte
```


value00: docs/llms-full_sveltekit.txt
value01:
### beforeUpdate/afterUpdate changes

`beforeUpdate` no longer runs twice on initial render if it modifies a variable referenced in the template.

`afterUpdate` callbacks in a parent component will now run after `afterUpdate` callbacks in any child components.

`beforeUpdate/afterUpdate` no longer run when the component contains a `<slot>` and its content is updated.

Both functions are disallowed in runes mode — use `$effect.pre(...)` and `$effect(...)` instead.


value00: docs/llms-full_sveltekit.txt
value01:
### Fonts

SvelteKit automatically preloads critical `.js` and `.css` files when the user visits a page, but it does _not_ preload fonts by default, since this may cause unnecessary files (such as font weights that are referenced by your CSS but not actually used on the current page) to be downloaded. Having said that, preloading fonts correctly can make a big difference to how fast your site feels. In your [`handle`](hooks#Server-hooks-handle) hook, you can call `resolve` with a `preload` filter that includes your fonts.

You can reduce the size of font files by [subsetting](https://web.dev/learn/performance/optimize-web-fonts#subset_your_web_fonts) your fonts.

## Reducing code size


value00: docs/llms-full_sveltekit.txt
value01:
<div class="ts-block-property">

```dts
script?: Preprocessor;
```

<div class="ts-block-property-details"></div>
</div></div>

## Processed

The result of a preprocessor run. If the preprocessor does not return a result, it is assumed that the code is unchanged.

<div class="ts-block">

```dts
interface Processed {/*…*/}
```

<div class="ts-block-property">

```dts
code: string;
```

<div class="ts-block-property-details">

The new code

</div>
</div>

<div class="ts-block-property">

```dts
map?: string | object;
```

<div class="ts-block-property-details">

A source map mapping back to the original code

</div>
</div>

<div class="ts-block-property">

```dts
dependencies?: string[];
```

<div class="ts-block-property-details">

A list of additional files to watch for changes


value00: docs/llms-full_sveltekit.txt
value01:
### +page@

Pages can break out of the current layout hierarchy on a route-by-route basis. Suppose we have an `/item/[id]/embed` route inside the `(app)` group from the previous example:

```tree
src/routes/
├ (app)/
│ ├ item/
│ │ ├ [id]/
│ │ │ ├ embed/
+++│ │ │ │ └ +page.svelte+++
│ │ │ └ +layout.svelte
│ │ └ +layout.svelte
│ └ +layout.svelte
└ +layout.svelte
```

Ordinarily, this would inherit the root layout, the `(app)` layout, the `item` layout and the `[id]` layout. We can reset to one of those layouts by appending `@` followed by the segment name — or, for the root layout, the empty string. In this example, we can choose from the following options:


value00: docs/llms-full_sveltekit.txt
value01:
For this to work, you need to load the data that the `+page.svelte` expects. A convenient way to do this is to use [`preloadData`]($app-navigation#preloadData) inside the `click` handler of an `<a>` element. If the element (or a parent) uses [`data-sveltekit-preload-data`](link-options#data-sveltekit-preload-data), the data will have already been requested, and `preloadData` will reuse that request.

```svelte
<!--- file: src/routes/photos/+page.svelte --->
<script>
	import { preloadData, pushState, goto } from '$app/navigation';
	import { page } from '$app/state';
	import Modal from './Modal.svelte';
	import PhotoPage from './[id]/+page.svelte';

	let { data } = $props();
</script>


value00: docs/llms-full_sveltekit.txt
value01:
- `+page@[id].svelte` - inherits from `src/routes/(app)/item/[id]/+layout.svelte`
- `+page@item.svelte` - inherits from `src/routes/(app)/item/+layout.svelte`
- `+page@(app).svelte` - inherits from `src/routes/(app)/+layout.svelte`
- `+page@.svelte` - inherits from `src/routes/+layout.svelte`

```tree
src/routes/
├ (app)/
│ ├ item/
│ │ ├ [id]/
│ │ │ ├ embed/
+++│ │ │ │ └ +page@(app).svelte+++
│ │ │ └ +layout.svelte
│ │ └ +layout.svelte
│ └ +layout.svelte
└ +layout.svelte
```

### +layout@


value00: docs/llms-full_sveltekit.txt
value01:
```
The `render` function passed to `createRawSnippet` should return HTML for a single element
```

### legacy_recursive_reactive_block

```
Detected a migrated `$:` reactive block in `%filename%` that both accesses and updates the same reactive value. This may cause recursive updates when converted to an `$effect`.
```

### lifecycle_double_unmount

```
Tried to unmount a component that was not mounted
```

### ownership_invalid_binding


value00: docs/llms-full_sveltekit.txt
value01:
We can also implement progressive enhancement ourselves, without `use:enhance`, with a normal event listener on the `<form>`:

```svelte
<!--- file: src/routes/login/+page.svelte --->
<script>
	import { invalidateAll, goto } from '$app/navigation';
	import { applyAction, deserialize } from '$app/forms';

	/** @type {import('./$types').PageProps} */
	let { form } = $props();

	/** @param {SubmitEvent & { currentTarget: EventTarget & HTMLFormElement}} event */
	async function handleSubmit(event) {
		event.preventDefault();
		const data = new FormData(event.currentTarget, event.submitter);

		const response = await fetch(event.currentTarget.action, {
			method: 'POST',
			body: data
		});


value00: docs/llms-full_sveltekit.txt
value01:
# Server-only modules

Like a good friend, SvelteKit keeps your secrets. When writing your backend and frontend in the same repository, it can be easy to accidentally import sensitive data into your front-end code (environment variables containing API keys, for example). SvelteKit provides a way to prevent this entirely: server-only modules.

## Private environment variables


value00: docs/llms-full_sveltekit.txt
value01:
The second option is to (ab)use the `typesVersions` feature from TypeScript to wire up the types. This is a field inside `package.json` TypeScript uses to check for different type definitions depending on the TypeScript version, and also contains a path mapping feature for that. We leverage that path mapping feature to get what we want. For the mentioned `foo` export above, the corresponding `typesVersions` looks like this:

```json
{
	"exports": {
		"./foo": {
			"types": "./dist/foo.d.ts",
			"svelte": "./dist/foo.js"
		}
	},
	"typesVersions": {
		">4.0": {
			"foo": ["./dist/foo.d.ts"]
		}
	}
}
```


value00: docs/llms-full_sveltekit.txt
value01:
## Private environment variables

The [`$env/static/private`]($env-static-private) and [`$env/dynamic/private`]($env-dynamic-private) modules can only be imported into modules that only run on the server, such as [`hooks.server.js`](hooks#Server-hooks) or [`+page.server.js`](routing#page-page.server.js).

## Server-only utilities

The [`$app/server`]($app-server) module, which contains a [`read`]($app-server#read) function for reading assets from the filesystem, can likewise only be imported by code that runs on the server.

## Your modules

You can make your own modules server-only in two ways:

- adding `.server` to the filename, e.g. `secrets.server.js`
- placing them in `$lib/server`, e.g. `$lib/server/secrets.js`


value00: docs/llms-full_sveltekit.txt
value01:
	const button = screen.getByRole('button');
	expect(button).toHaveTextContent(0);

	await user.click(button);
	expect(button).toHaveTextContent(1);
});
```

When writing component tests that involve two-way bindings, context or snippet props, it's best to create a wrapper component for your specific test and interact with that. `@testing-library/svelte` contains some [examples](https://testing-library.com/docs/svelte-testing-library/example).

## Component tests with Storybook

[Storybook](https://storybook.js.org) is a tool for developing and documenting UI components, and it can also be used to test your components. They're run with Vitest's browser mode, which renders your components in a real browser for the most realistic testing environment.


value00: docs/llms-full_sveltekit.txt
value01:
If you're only using the import as a type, change it to `import type`.
```

Even though the public-facing code — `src/routes/+page.svelte` — only uses the `add` export and not the secret `atlantisCoordinates` export, the secret code could end up in JavaScript that the browser downloads, and so the import chain is considered unsafe.

This feature also works with dynamic imports, even interpolated ones like ``await import(`./${foo}.js`)``.

> [!NOTE] Unit testing frameworks like Vitest do not distinguish between server-only and public-facing code. For this reason, illegal import detection is disabled when running tests, as determined by `process.env.TEST === 'true'`.

## Further reading

- [Tutorial: Environment variables](/tutorial/kit/env-static-private)

# Snapshots


value00: docs/llms-full_sveltekit.txt
value01:
## Runtime APIs

The [`env`](https://developers.cloudflare.com/workers/runtime-apis/fetch-event#parameters) object contains your project's [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/), which consist of KV/DO namespaces, etc. It is passed to SvelteKit via the `platform` property, along with [`ctx`](https://developers.cloudflare.com/workers/runtime-apis/context/), [`caches`](https://developers.cloudflare.com/workers/runtime-apis/cache/), and [`cf`](https://developers.cloudflare.com/workers/runtime-apis/request/#incomingrequestcfproperties), meaning that you can access it in hooks and endpoints:

```js
// @filename: ambient.d.ts
import { DurableObjectNamespace } from '@cloudflare/workers-types';


value00: docs/llms-full_sveltekit.txt
value01:
## Matching

A route like `src/routes/fruits/[page]` would match `/fruits/apple`, but it would also match `/fruits/rocketship`. We don't want that. You can ensure that route parameters are well-formed by adding a _matcher_ — which takes the parameter string (`"apple"` or `"rocketship"`) and returns `true` if it is valid — to your [`params`](configuration#files) directory...

```js
/// file: src/params/fruit.js
/**
 * @param {string} param
 * @return {param is ('apple' | 'orange')}
 * @satisfies {import('@sveltejs/kit').ParamMatcher}
 */
export function match(param) {
	return param === 'apple' || param === 'orange';
}
```

...and augmenting your routes:


value00: docs/llms-full_sveltekit.txt
value01:
```svelte
<svelte:element this=+++{+++"div"+++}+++>
```

Note that whereas Svelte 4 would treat `<svelte:element this="input">` (for example) identically to `<input>` for the purposes of determining which `bind:` directives could be applied, Svelte 5 does not.

### `mount` plays transitions by default

The `mount` function used to render a component tree plays transitions by default unless the `intro` option is set to `false`. This is different from legacy class components which, when manually instantiated, didn't play transitions by default.

### `<img src={...}>` and `{@html ...}` hydration mismatches are not repaired


value00: docs/llms-full_sveltekit.txt
value01:
...the nav will always be visible, and clicking between the three pages will only result in the `<h1>` being replaced.

Layouts can be _nested_. Suppose we don't just have a single `/settings` page, but instead have nested pages like `/settings/profile` and `/settings/notifications` with a shared submenu (for a real-life example, see [github.com/settings](https://github.com/settings)).

We can create a layout that only applies to pages below `/settings` (while inheriting the root layout with the top-level nav):


value00: docs/llms-full_sveltekit.txt
value01:
## `<select bind:value>`

A `<select>` value binding corresponds to the `value` property on the selected `<option>`, which can be any value (not just strings, as is normally the case in the DOM).

```svelte
<select bind:value={selected}>
	<option value={a}>a</option>
	<option value={b}>b</option>
	<option value={c}>c</option>
</select>
```

A `<select multiple>` element behaves similarly to a checkbox group. The bound variable is an array with an entry corresponding to the `value` property of each selected `<option>`.

```svelte
<select multiple bind:value={fillings}>
	<option value="Rice">Rice</option>
	<option value="Beans">Beans</option>
	<option value="Cheese">Cheese</option>
	<option value="Guac (extra)">Guac (extra)</option>
</select>
```


value00: docs/llms-full_sveltekit.txt
value01:
SvelteKit makes this possible with the [`pushState`]($app-navigation#pushState) and [`replaceState`]($app-navigation#replaceState) functions, which allow you to associate state with a history entry without navigating. For example, to implement a history-driven modal:

```svelte
<!--- file: +page.svelte --->
<script>
	import { pushState } from '$app/navigation';
	import { page } from '$app/state';
	import Modal from './Modal.svelte';

	function showModal() {
		pushState('', {
			showModal: true
		});
	}
</script>

{#if page.state.showModal}
	<Modal close={() => history.back()} />
{/if}
```


value00: docs/llms-full_sveltekit.txt
value01:
### store_invalid_subscription

```
Cannot reference store value inside `<script module>`
```

### store_invalid_subscription_module

```
Cannot reference store value outside a `.svelte` file
```

Using a `$` prefix to refer to the value of a store is only possible inside `.svelte` files, where Svelte can automatically create subscriptions when a component is mounted and unsubscribe when the component is unmounted. Consider migrating to runes instead.

### style_directive_invalid_modifier

```
`style:` directive can only use the `important` modifier
```


value00: docs/llms-full_sveltekit.txt
value01:
## Further reading

- [Tutorial: Environment variables](/tutorial/kit/env-static-private)

# Snapshots

Ephemeral DOM state — like scroll positions on sidebars, the content of `<input>` elements and so on — is discarded when you navigate from one page to another.

For example, if the user fills out a form but navigates away and then back before submitting, or if the user refreshes the page, the values they filled in will be lost. In cases where it's valuable to preserve that input, you can take a _snapshot_ of DOM state, which can then be restored if the user navigates back.

To do this, export a `snapshot` object with `capture` and `restore` methods from a `+page.svelte` or `+layout.svelte`:

```svelte
<!--- file: +page.svelte --->
<script>
	let comment = $state('');


value00: docs/llms-full_sveltekit.txt
value01:
### Selective loading

Code imported with static `import` declarations will be automatically bundled with the rest of your page. If there is a piece of code you need only when some condition is met, use the dynamic `import(...)` form to selectively lazy-load the component.

## Navigation

### Preloading

You can speed up client-side navigations by eagerly preloading the necessary code and data, using [link options](link-options). This is configured by default on the `<body>` element when you create a new SvelteKit app.

### Non-essential data


value00: docs/llms-full_sveltekit.txt
value01:
{#if page.state.showModal}
	<Modal close={() => history.back()} />
{/if}
```

The modal can be dismissed by navigating back (unsetting `page.state.showModal`) or by interacting with it in a way that causes the `close` callback to run, which will navigate back programmatically.

## API

The first argument to `pushState` is the URL, relative to the current URL. To stay on the current URL, use `''`.

The second argument is the new page state, which can be accessed via the [page object]($app-state#page) as `page.state`. You can make page state type-safe by declaring an [`App.PageState`](types#PageState) interface (usually in `src/app.d.ts`).

To set page state without creating a new history entry, use `replaceState` instead of `pushState`.


value00: docs/llms-full_sveltekit.txt
value01:
```dts
function quadOut(t: number): number;
```

</div>



## quartIn

<div class="ts-block">

```dts
function quartIn(t: number): number;
```

</div>



## quartInOut

<div class="ts-block">

```dts
function quartInOut(t: number): number;
```

</div>



## quartOut

<div class="ts-block">

```dts
function quartOut(t: number): number;
```

</div>



## quintIn

<div class="ts-block">

```dts
function quintIn(t: number): number;
```

</div>



## quintInOut

<div class="ts-block">

```dts
function quintInOut(t: number): number;
```

</div>



## quintOut

<div class="ts-block">

```dts
function quintOut(t: number): number;
```

</div>



## sineIn

<div class="ts-block">

```dts
function sineIn(t: number): number;
```


value00: docs/llms-full_sveltekit.txt
value01:
		return async ({ result, update }) => {
			// `result` is an `ActionResult` object
			// `update` is a function which triggers the default logic that would be triggered if this callback wasn't set
		};
	}}
>
```

You can use these functions to show and hide loading UI, and so on.

If you return a callback, you override the default post-submission behavior. To get it back, call `update`, which accepts `invalidateAll` and `reset` parameters, or use `applyAction` on the result:

```svelte
/// file: src/routes/login/+page.svelte
<script>
	import { enhance, +++applyAction+++ } from '$app/forms';

	/** @type {import('./$types').PageProps} */
	let { form } = $props();
</script>


value00: docs/llms-full_sveltekit.txt
value01:
## Svelte

There are many [icon libraries for Svelte](/packages#icons). When choosing an icon library, it is recommended to avoid those that provide a `.svelte` file per icon, as these libraries can have thousands of `.svelte` files which really slow down [Vite's dependency optimization](https://vite.dev/guide/dep-pre-bundling.html). This can become especially pathological if the icons are imported both via an umbrella import and subpath import [as described in the `vite-plugin-svelte` FAQ](https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/faq.md#what-is-going-on-with-vite-and-pre-bundling-dependencies).

# Images


value00: docs/llms-full_sveltekit.txt
value01:
```html
/// file: src/routes/+page.svelte
<script>
	import { add } from './utils.js';
</script>
```

...SvelteKit will error:

```
Cannot import $lib/server/secrets.ts into code that runs in the browser, as this could leak sensitive information.

 src/routes/+page.svelte imports
  src/routes/utils.js imports
   $lib/server/secrets.ts

If you're only using the import as a type, change it to `import type`.
```


value00: docs/llms-full_sveltekit.txt
value01:
To get started, first install Storybook ([using Svelte's CLI](/docs/cli/storybook)) in your project via `npx sv add storybook` and choose the recommended configuration that includes testing features. If you're already using Storybook, and for more information on Storybook's testing capabilities, follow the [Storybook testing docs](https://storybook.js.org/docs/writing-tests?renderer=svelte) to get started.


value00: docs/llms-full_sveltekit.txt
value01:
## Usage

Install with `npm i -D @sveltejs/adapter-cloudflare`, then add the adapter to your `svelte.config.js`:

```js
/// file: svelte.config.js
import adapter from '@sveltejs/adapter-cloudflare';

/** @type {import('@sveltejs/kit').Config} */
const config = {
	kit: {
		adapter: adapter({
			// See below for an explanation of these options
			config: undefined,
			platformProxy: {
				configPath: undefined,
				environment: undefined,
				persist: undefined
			},
			fallback: 'plaintext',
			routes: {
				include: ['/*'],
				exclude: ['<all>']
			}
		})
	}
};

export default config;
```

## Options


value00: docs/llms-full_sveltekit.txt
value01:
If an error occurs during submission, the nearest `+error.svelte` page will be rendered.

### enhance

We can customize what happens when the form is submitted with the `enhance` method:

```svelte
<!--- file: src/routes/blog/new/+page.svelte --->
<script>
	import { createPost } from '../data.remote';
	import { showToast } from '$lib/toast';
</script>

<h1>Create a new post</h1>

<form {...createPost.enhance(async ({ form, data, submit }) => {
	try {
		await submit();
		form.reset();

		showToast('Successfully published!');
	} catch (error) {
		showToast('Oh no! Something went wrong');
	}
})}>
	<!-- -->
</form>
```

> When using `enhance`, the `<form>` is not automatically reset — you must call `form.reset()` if you want to clear the inputs.


value00: docs/llms-full_sveltekit.txt
value01:
```js
// @errors: 7006 2554
class Todo {
	done = $state(false);

	constructor(text) {
		this.text = $state(text);
	}

	reset() {
		this.text = '';
		this.done = false;
	}
}
```

> [!NOTE] The compiler transforms `done` and `text` into `get`/`set` methods on the class prototype referencing private fields. This means the properties are not enumerable.

When calling methods in JavaScript, the value of [`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) matters. This won't work, because `this` inside the `reset` method will be the `<button>` rather than the `Todo`:

```svelte
<button onclick={todo.reset}>
	reset
</button>
```

You can either use an inline function...

```svelte
<button onclick=+++{() => todo.reset()}>+++
	reset
</button>
```


value00: docs/llms-full_sveltekit.txt
value01:
	let { data } = $props();
</script>

{#each data.thumbnails as thumbnail}
	<a
		href="/photos/{thumbnail.id}"
		onclick={async (e) => {
			if (innerWidth < 640        // bail if the screen is too small
				|| e.shiftKey             // or the link is opened in a new window
				|| e.metaKey || e.ctrlKey // or a new tab (mac: metaKey, win/linux: ctrlKey)
				// should also consider clicking with a mouse scroll wheel
			) return;

			// prevent navigation
			e.preventDefault();


value00: docs/llms-full_sveltekit.txt
value01:
In Svelte 4, if the value of a `src` attribute or `{@html ...}` tag differ between server and client (a.k.a. a hydration mismatch), the mismatch is repaired. This is very costly: setting a `src` attribute (even if it evaluates to the same thing) causes images and iframes to be reloaded, and reinserting a large blob of HTML is slow.

Since these mismatches are extremely rare, Svelte 5 assumes that the values are unchanged, but in development will warn you if they are not. To force an update you can do something like this:

```svelte
<script>
	let { markup, src } = $props();

	if (typeof window !== 'undefined') {
		// stash the values...
		const initial = { markup, src };


value00: docs/llms-full_sveltekit.txt
value01:
> [!NOTE] `bind:group` only works if the inputs are in the same Svelte component.

## `<input bind:files>`

On `<input>` elements with `type="file"`, you can use `bind:files` to get the [`FileList` of selected files](https://developer.mozilla.org/en-US/docs/Web/API/FileList). When you want to update the files programmatically, you always need to use a `FileList` object. Currently `FileList` objects cannot be constructed directly, so you need to create a new [`DataTransfer`](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer) object and get `files` from there.

```svelte
<script>
	let files = $state();

	function clear() {
		files = new DataTransfer().files; // null or undefined does not work
	}
</script>


value00: docs/llms-full_sveltekit.txt
value01:
		// logger uses an $effect to log updates of its input
		let log = logger(() => count);

		// effects normally run after a microtask,
		// use flushSync to execute all pending effects synchronously
		flushSync();
		expect(log).toEqual([0]);

		count = 1;
		flushSync();

		expect(log).toEqual([0, 1]);
	});

	cleanup();
});
```

```js
/// file: logger.svelte.js
/**
 * @param {() => any} getValue
 */
export function logger(getValue) {
	/** @type {any[]} */
	let log = [];

	$effect(() => {
		log.push(getValue());
	});

	return log;
}
```

### Component testing


value00: docs/llms-full_sveltekit.txt
value01:
Waterfalls can also occur on calls to the backend whether made from the browser or server. E.g. if a universal `load` function makes an API call to fetch the current user, then uses the details from that response to fetch a list of saved items, and then uses _that_ response to fetch the details for each item, the browser will end up making multiple sequential requests. This is deadly for performance, especially for users that are physically located far from your backend.


value00: docs/llms-full_sveltekit.txt
value01:
* Chrome - [Lighthouse](https://developer.chrome.com/docs/lighthouse/overview#devtools), [Network](https://developer.chrome.com/docs/devtools/network), and [Performance](https://developer.chrome.com/docs/devtools/performance) devtools
* Edge - [Lighthouse](https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/lighthouse/lighthouse-tool), [Network](https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/network/), and [Performance](https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/evaluate-performance/) devtools
* Firefox - [Network](https://firefox-source-docs.mozilla.org/devtools-user/network_monitor/) and [Performance](https://hacks.mozilla.org/2022/03/performance-tool-in-firefox-devtools-reloaded/) devtools


value00: docs/llms-full_sveltekit.txt
value01:
	if (isNaN(d) || d < 0) {
		error(400, 'min and max must be numbers, and min must be less than max');
	}

	const random = min + Math.random() * d;

	return new Response(String(random));
}
```

The first argument to `Response` can be a [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream), making it possible to stream large amounts of data or create server-sent events (unless deploying to platforms that buffer responses, like AWS Lambda).

You can use the [`error`](@sveltejs-kit#error), [`redirect`](@sveltejs-kit#redirect) and [`json`](@sveltejs-kit#json) methods from `@sveltejs/kit` for convenience (but you don't have to).


value00: docs/llms-full_sveltekit.txt
value01:
### state_field_invalid_assignment

```
Cannot assign to a state field before its declaration
```

### state_invalid_export

```
Cannot export state from a module if it is reassigned. Either export a function returning the state value or only mutate the state value's properties
```

### state_invalid_placement

```
`%rune%(...)` can only be used as a variable declaration initializer, a class field declaration, or the first assignment to a class field at the top level of the constructor.
```

### store_invalid_scoped_subscription

```
Cannot subscribe to stores that are not declared at the top level of the component
```

### store_invalid_subscription

```
Cannot reference store value inside `<script module>`
```


value00: docs/llms-full_sveltekit.txt
value01:
```svelte
<script>
	import logo from '$lib/assets/logo.png';
</script>

<img alt="The project logo" src={logo} />
```

## @sveltejs/enhanced-img

`@sveltejs/enhanced-img` is a plugin offered on top of Vite's built-in asset handling. It provides plug and play image processing that serves smaller file formats like `avif` or `webp`, automatically sets the intrinsic `width` and `height` of the image to avoid layout shift, creates images of multiple sizes for various devices, and strips EXIF data for privacy. It will work in any Vite-based project including, but not limited to, SvelteKit projects.


value00: docs/llms-full_sveltekit.txt
value01:
	$effect(() => {
		log.push(getValue());
	});

	return log;
}
```

### Component testing

It is possible to test your components in isolation, which allows you to render them in a browser (real or simulated), simulate behavior, and make assertions, without spinning up your whole app.

> [!NOTE] Before writing component tests, think about whether you actually need to test the component, or if it's more about the logic _inside_ the component. If so, consider extracting out that logic to test it in isolation, without the overhead of a component.

To get started, install jsdom (a library that shims DOM APIs):

```sh
npm install -D jsdom
```

Then adjust your `vite.config.js`:

```js
/// file: vite.config.js
import { defineConfig } from 'vitest/config';


value00: docs/llms-full_sveltekit.txt
value01:
## During development

The service worker is bundled for production, but not during development. For that reason, only browsers that support [modules in service workers](https://web.dev/es-modules-in-sw) will be able to use them at dev time. If you are manually registering your service worker, you will need to pass the `{ type: 'module' }` option in development:

```js
import { dev } from '$app/environment';

navigator.serviceWorker.register('/service-worker.js', {
	type: dev ? 'module' : 'classic'
});
```

> [!NOTE] `build` and `prerendered` are empty arrays during development


value00: docs/llms-full_sveltekit.txt
value01:
To use these characters in your routes, you can use hexadecimal escape sequences, which have the format `[x+nn]` where `nn` is a hexadecimal character code:

- `\` — `[x+5c]`
- `/` — `[x+2f]`
- `:` — `[x+3a]`
- `*` — `[x+2a]`
- `?` — `[x+3f]`
- `"` — `[x+22]`
- `<` — `[x+3c]`
- `>` — `[x+3e]`
- `|` — `[x+7c]`
- `#` — `[x+23]`
- `%` — `[x+25]`
- `[` — `[x+5b]`
- `]` — `[x+5d]`
- `(` — `[x+28]`
- `)` — `[x+29]`

For example, to create a `/smileys/:-)` route, you would create a `src/routes/smileys/[x+3a]-[x+29]/+page.svelte` file.

You can determine the hexadecimal code for a character with JavaScript:

```js
':'.charCodeAt(0).toString(16); // '3a', hence '[x+3a]'
```


value00: docs/llms-full_sveltekit.txt
value01:
### Returns and redirects

The example above uses [`redirect(...)`](@sveltejs-kit#redirect), which sends the user to the newly created page. Alternatively, the callback could return data, in which case it would be available as `createPost.result`:

```ts
/// file: src/routes/blog/data.remote.js
// @filename: ambient.d.ts
declare module '$lib/server/database' {
	export function sql(strings: TemplateStringsArray, ...values: any[]): Promise<any[]>;
}

declare module '$lib/server/auth' {
	interface User {
		name: string;
	}


value00: docs/llms-full_sveltekit.txt
value01:
The data must be serializable as JSON so that it can be persisted to `sessionStorage`. This allows the state to be restored when the page is reloaded, or when the user navigates back from a different site.

> [!NOTE] Avoid returning very large objects from `capture` — once captured, objects will be retained in memory for the duration of the session, and in extreme cases may be too large to persist to `sessionStorage`.

# Shallow routing


value00: docs/llms-full_sveltekit.txt
value01:
```dts
dependencies?: string[];
```

<div class="ts-block-property-details">

A list of additional files to watch for changes

</div>
</div>

<div class="ts-block-property">

```dts
attributes?: Record<string, string | boolean>;
```

<div class="ts-block-property-details">

Only for script/style preprocessors: The updated attributes to set on the tag. If undefined, attributes stay unchanged.

</div>
</div>

<div class="ts-block-property">

```dts
toString?: () => string;
```

<div class="ts-block-property-details"></div>
</div></div>

## Warning

<div class="ts-block">

```dts
interface Warning extends ICompileDiagnostic {}
```

</div>

# svelte/easing


value00: docs/llms-full_sveltekit.txt
value01:
Both of these features are currently experimental, meaning they are likely to contain bugs and are subject to change without notice. You must opt in by adding the `kit.experimental.tracing.server` and `kit.experimental.instrumentation.server` option in your `svelte.config.js`:

```js
/// file: svelte.config.js
/** @type {import('@sveltejs/kit').Config} */
const config = {
	kit: {
		experimental: {
			+++tracing: {
				server: true
			},
			instrumentation: {
				server: true
			}+++
		}
	}
};

export default config;
```


value00: docs/llms-full_sveltekit.txt
value01:
			// prevent navigation
			e.preventDefault();

			const { href } = e.currentTarget;

			// run `load` functions (or rather, get the result of the `load` functions
			// that are already running because of `data-sveltekit-preload-data`)
			const result = await preloadData(href);

			if (result.type === 'loaded' && result.status === 200) {
				pushState(href, { selected: result.data });
			} else {
				// something bad happened! try navigating
				goto(href);
			}
		}}
	>
		<img alt={thumbnail.alt} src={thumbnail.src} />
	</a>
{/each}

{#if page.state.selected}
	<Modal onclose={() => history.back()}>
		<!-- pass page data to the +page.svelte component,
		     just like SvelteKit would on navigation -->
		<PhotoPage data={page.state.selected} />
	</Modal>
{/if}
```

## Caveats


value00: docs/llms-full_sveltekit.txt
value01:
# Shallow routing

As you navigate around a SvelteKit app, you create _history entries_. Clicking the back and forward buttons traverses through this list of entries, re-running any `load` functions and replacing page components as necessary.

Sometimes, it's useful to create history entries _without_ navigating. For example, you might want to show a modal dialog that the user can dismiss by navigating back. This is particularly valuable on mobile devices, where swipe gestures are often more natural than interacting directly with the UI. In these cases, a modal that is _not_ associated with a history entry can be a source of frustration, as a user may swipe backwards in an attempt to dismiss it and find themselves on the wrong page.


value00: docs/llms-full_sveltekit.txt
value01:
// @filename: ambient.d.ts
declare module '$lib/auth-core' {
	export function getAuthenticatedUser(): Promise<{ id: string }>
}

// @filename: index.js
// ---cut---
import { getRequestEvent } from '$app/server';
import { getAuthenticatedUser } from '$lib/auth-core';

async function authenticate() {
	const user = await getAuthenticatedUser();
	const event = getRequestEvent();
	event.tracing.root.setAttribute('userId', user.id);
}
```

## Development quickstart

To view your first trace, you'll need to set up a local collector. We'll use [Jaeger](https://www.jaegertracing.io/docs/getting-started/) in this example, as they provide an easy-to-use quickstart command. Once your collector is running locally:


value00: docs/llms-full_sveltekit.txt
value01:
Both functions are disallowed in runes mode — use `$effect.pre(...)` and `$effect(...)` instead.

### `contenteditable` behavior change

If you have a `contenteditable` node with a corresponding binding _and_ a reactive value inside it (example: `<div contenteditable=true bind:textContent>count is {count}</div>`), then the value inside the contenteditable will not be updated by updates to `count` because the binding takes full control over the content immediately and it should only be updated through it.

### `oneventname` attributes no longer accept string values

In Svelte 4, it was possible to specify event attributes on HTML elements as a string:

```svelte
<button onclick="alert('hello')">...</button>
```


value00: docs/llms-full_sveltekit.txt
value01:
If an error is thrown (either `error(...)` or an unexpected error), the response will be a JSON representation of the error or a fallback error page — which can be customised via `src/error.html` — depending on the `Accept` header. The [`+error.svelte`](#error) component will _not_ be rendered in this case. You can read more about error handling [here](errors).

> [!NOTE] When creating an `OPTIONS` handler, note that Vite will inject `Access-Control-Allow-Origin` and `Access-Control-Allow-Methods` headers — these will not be present in production unless you add them.

> [!NOTE] `+layout` files have no effect on `+server.js` files. If you want to run some logic before each request, add it to the server [`handle`](hooks#Server-hooks-handle) hook.

### Receiving data


value00: docs/llms-full_sveltekit.txt
value01:
Consider the following code:

```svelte
<!--- file: App.svelte --->
<script>
	import Child from './Child.svelte';
	let person = $state({ name: 'Florida', surname: 'Man' });
</script>

<Child {person} />
```

```svelte
<!--- file: Child.svelte --->
<script>
	let { person } = $props();
</script>

<input bind:value={person.name}>
<input bind:value={person.surname}>
```

`Child` is mutating `person` which is owned by `App` without being explicitly "allowed" to do so. This is strongly discouraged since it can create code that is hard to reason about at scale ("who mutated this value?"), hence the warning.

To fix it, either create callback props to communicate changes, or mark `person` as [`$bindable`]($bindable).


value00: docs/llms-full_sveltekit.txt
value01:
To fix it, either create callback props to communicate changes, or mark `person` as [`$bindable`]($bindable).

### select_multiple_invalid_value

```
The `value` property of a `<select multiple>` element should be an array, but it received a non-array value. The selection will be kept as is.
```

When using `<select multiple value={...}>`, Svelte will mark all selected `<option>` elements as selected by iterating over the array passed to `value`. If `value` is not an array, Svelte will emit this warning and keep the selected options as they are.

To silence the warning, ensure that `value`:

- is an array for an explicit selection
- is `null` or `undefined` to keep the selection as is

### state_proxy_equality_mismatch


value00: docs/llms-full_sveltekit.txt
value01:
### Setup

Install:

```sh
npm i -D @sveltejs/enhanced-img
```

Adjust `vite.config.js`:

```js
import { sveltekit } from '@sveltejs/kit/vite';
+++import { enhancedImages } from '@sveltejs/enhanced-img';+++
import { defineConfig } from 'vite';

export default defineConfig({
	plugins: [
		+++enhancedImages(), // must come before the SvelteKit plugin+++
		sveltekit()
	]
});
```

Building will take longer on the first build due to the computational expense of transforming images. However, the build output will be cached in `./node_modules/.cache/imagetools` so that subsequent builds will be fast.

### Basic usage


value00: docs/llms-full_sveltekit.txt
value01:
- Turn on the experimental flags mentioned earlier in your `svelte.config.js` file
- Use your package manager to install the dependencies you'll need:
  ```sh
  npm i @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-trace-otlp-proto import-in-the-middle
  ```
- Create `src/instrumentation.server.js` with the following:

```js
/// file: src/instrumentation.server.js
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
import { createAddHookMessageChannel } from 'import-in-the-middle';
import { register } from 'node:module';


value00: docs/llms-full_sveltekit.txt
value01:
```svelte
<!--- file: +page.svelte --->
<script>
	let comment = $state('');

	/** @type {import('./$types').Snapshot<string>} */
	export const snapshot = {
		capture: () => comment,
		restore: (value) => comment = value
	};
</script>

<form method="POST">
	<label for="comment">Comment</label>
	<textarea id="comment" bind:value={comment} />
	<button>Post comment</button>
</form>
```

When you navigate away from this page, the `capture` function is called immediately before the page updates, and the returned value is associated with the current entry in the browser's history stack. If you navigate back, the `restore` function is called with the stored value as soon as the page is updated.


value00: docs/llms-full_sveltekit.txt
value01:
		/** @type {import('@sveltejs/kit').ActionResult} */
		const result = deserialize(await response.text());

		if (result.type === 'success') {
			// rerun all `load` functions, following the successful update
			await invalidateAll();
		}

		applyAction(result);
	}
</script>

<form method="POST" onsubmit={handleSubmit}>
	<!-- content -->
</form>
```

Note that you need to `deserialize` the response before processing it further using the corresponding method from `$app/forms`. `JSON.parse()` isn't enough because form actions - like `load` functions - also support returning `Date` or `BigInt` objects.


value00: docs/llms-full_sveltekit.txt
value01:
 The [`handle`](hooks#Server-hooks-handle) hook and `handle` functions running in a [`sequence`](@sveltejs-kit-hooks#sequence) (these will show up as children of each other and the root `handle` hook)
- Server [`load`](load) functions and universal `load` functions when they're run on the server
- [Form actions](form-actions)
- [Remote functions](remote-functions)

Just telling SvelteKit to emit spans won't get you far, though — you need to actually collect them somewhere to be able to view them. SvelteKit provides `src/instrumentation.server.ts` as a place to write your tracing setup and instrumentation code. It's guaranteed to be run prior to your application code being imported, providing your deployment platform supports it and your adapter is aware of it.


value00: docs/llms-full_sveltekit.txt
value01:
- adding `.server` to the filename, e.g. `secrets.server.js`
- placing them in `$lib/server`, e.g. `$lib/server/secrets.js`

## How it works

Any time you have public-facing code that imports server-only code (whether directly or indirectly)...

```js
// @errors: 7005
/// file: $lib/server/secrets.js
export const atlantisCoordinates = [/* redacted */];
```

```js
// @errors: 2307 7006 7005
/// file: src/routes/utils.js
export { atlantisCoordinates } from '$lib/server/secrets.js';

export const add = (a, b) => a + b;
```

```html
/// file: src/routes/+page.svelte
<script>
	import { add } from './utils.js';
</script>
```


value00: docs/llms-full_sveltekit.txt
value01:
To set page state without creating a new history entry, use `replaceState` instead of `pushState`.

> [!LEGACY]
> `page.state` from `$app/state` was added in SvelteKit 2.12. If you're using an earlier version or are using Svelte 4, use `$page.state` from `$app/stores` instead.

## Loading data for a route

When shallow routing, you may want to render another `+page.svelte` inside the current page. For example, clicking on a photo thumbnail could pop up the detail view without navigating to the photo page.


value00: docs/llms-full_sveltekit.txt
value01:
	expect(double.value).toEqual(0);

	count = 5;

	expect(double.value).toEqual(10);
});
```

```js
/// file: multiplier.svelte.js
/**
 * @param {() => number} getCount
 * @param {number} k
 */
export function multiplier(getCount, k) {
	return {
		get value() {
			return getCount() * k;
		}
	};
}
```

If the code being tested uses effects, you need to wrap the test inside `$effect.root`:

```js
/// file: logger.svelte.test.js
import { flushSync } from 'svelte';
import { expect, test } from 'vitest';
import { logger } from './logger.svelte.js';

test('Effect', () => {
	const cleanup = $effect.root(() => {
		let count = $state(0);

		// logger uses an $effect to log updates of its input
		let log = logger(() => count);


value00: docs/llms-full_sveltekit.txt
value01:
Read more about `exports` [here](https://nodejs.org/docs/latest-v18.x/api/packages.html#package-entry-points).

### svelte

This is a legacy field that enabled tooling to recognise Svelte component libraries. It's no longer necessary when using the `svelte` [export condition](#Anatomy-of-a-package.json-exports), but for backwards compatibility with outdated tooling that doesn't yet know about export conditions it's good to keep it around. It should point towards your root entry point.

```json
{
	"svelte": "./dist/index.js"
}
```


value00: docs/llms-full_sveltekit.txt
value01:
The callback receives the `form` element, the `data` it contains, and a `submit` function.

To enable client-driven [single-flight mutations](#form-Single-flight-mutations), use `submit().updates(...)`. For example, if the `getPosts()` query was used on this page, we could refresh it like so:

```ts
import type { RemoteQuery, RemoteQueryOverride } from '@sveltejs/kit';
interface Post {}
declare function submit(): Promise<any> & {
	updates(...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Promise<any>;
}

declare function getPosts(): RemoteQuery<Post[]>;
// ---cut---
await submit().updates(getPosts());
```

We can also _override_ the current data while the submission is ongoing:


value00: docs/llms-full_sveltekit.txt
value01:
	if (typeof window !== 'undefined') {
		// stash the values...
		const initial = { markup, src };

		// unset them...
		markup = src = undefined;

		$effect(() => {
			// ...and reset after we've mounted
			markup = initial.markup;
			src = initial.src;
		});
	}
</script>

{@html markup}
<img {src} />
```

### Hydration works differently

Svelte 5 makes use of comments during server-side rendering which are used for more robust and efficient hydration on the client. You therefore should not remove comments from your HTML output if you intend to hydrate it, and if you manually authored HTML to be hydrated by a Svelte component, you need to adjust that HTML to include said comments at the correct positions.

### `onevent` attributes are delegated


value00: docs/llms-full_sveltekit.txt
value01:
### `onevent` attributes are delegated

Event attributes replace event directives: Instead of `on:click={handler}` you write `onclick={handler}`. For backwards compatibility the `on:event` syntax is still supported and behaves the same as in Svelte 4. Some of the `onevent` attributes however are delegated, which means you need to take care to not stop event propagation on those manually, as they then might never reach the listener for this event type at the root.

### `--style-props` uses a different element

Svelte 5 uses an extra `<svelte-css-wrapper>` element instead of a `<div>` to wrap the component when using CSS custom properties.

<!-- TODO in final docs, add link to corresponding section for more details -->


value00: docs/llms-full_sveltekit.txt
value01:
## Reducing code size

### Svelte version

We recommend running the latest version of Svelte. Svelte 5 is smaller and faster than Svelte 4, which is smaller and faster than Svelte 3.

### Packages

[`rollup-plugin-visualizer`](https://www.npmjs.com/package/rollup-plugin-visualizer) can be helpful for identifying which packages are contributing the most to the size of your site. You may also find opportunities to remove code by manually inspecting the build output (use `build: { minify: false }` in your [Vite config](https://vitejs.dev/config/build-options.html#build-minify) to make the output readable, but remember to undo that before deploying your app), or via the network tab of your browser's devtools.

### External scripts


value00: docs/llms-full_sveltekit.txt
value01:
## Further reading

For the most part, building a performant SvelteKit app is the same as building any performant web app. You should be able to apply information from general performance resources such as [Core Web Vitals](https://web.dev/explore/learn-core-web-vitals) to any web experience you build.

# Icons

## CSS


value00: docs/llms-full_sveltekit.txt
value01:
## Hosting

Your frontend should be located in the same data center as your backend to minimize latency. For sites with no central backend, many SvelteKit adapters support deploying to the _edge_, which means handling each user's requests from a nearby server. This can reduce load times significantly. Some adapters even support [configuring deployment on a per-route basis](page-options#config). You should also consider serving images from a CDN (which are typically edge networks) — the hosts for many SvelteKit adapters will do this automatically.

Ensure your host uses HTTP/2 or newer. Vite's code splitting creates numerous small files for improved cacheability, which results in excellent performance, but this does assume that your files can be loaded in parallel with HTTP/2.


value00: docs/llms-full_sveltekit.txt
value01:
<!-- TODO in final docs, add link to corresponding section for more details -->

# Frequently asked questions

## I'm new to Svelte. Where should I start?

We think the best way to get started is playing through the interactive [tutorial](/tutorial). Each step there is mainly focused on one specific aspect and is easy to follow. You'll be editing and running real Svelte components right in your browser.

Five to ten minutes should be enough to get you up and running. An hour and a half should get you through the entire tutorial.

## Where can I get support?


value00: docs/llms-full_sveltekit.txt
value01:
## Options

`svelte-package` accepts the following options:

- `-w`/`--watch` — watch files in `src/lib` for changes and rebuild the package
- `-i`/`--input` — the input directory which contains all the files of the package. Defaults to `src/lib`
- `-o`/`--output` — the output directory where the processed files are written to. Your `package.json`'s `exports` should point to files inside there, and the `files` array should include that folder. Defaults to `dist`
- `-p`/`--preserve-output` — prevent deletion of the output directory before packaging. Defaults to `false`, which means that the output directory will be emptied first


value00: docs/llms-full_sveltekit.txt
value01:
> [!NOTE] As a build plugin, `@sveltejs/enhanced-img` can only optimize files located on your machine during the build process. If you have an image located elsewhere (such as a path served from your database, CMS, or backend), please read about [loading images dynamically from a CDN](#Loading-images-dynamically-from-a-CDN).

### Setup

Install:

```sh
npm i -D @sveltejs/enhanced-img
```

Adjust `vite.config.js`:


value00: docs/llms-full_sveltekit.txt
value01:
# Icons

## CSS

A great way to use icons is to define them purely via CSS. Iconify offers support for [many popular icon sets](https://icon-sets.iconify.design/) that [can be included via CSS](https://iconify.design/docs/usage/css/). This method can also be used with popular CSS frameworks by leveraging the Iconify [Tailwind CSS plugin](https://iconify.design/docs/usage/css/tailwind/) or [UnoCSS plugin](https://iconify.design/docs/usage/css/unocss/). As opposed to libraries based on Svelte components, it doesn't require each icon to be imported into your `.svelte` file.

## Svelte


value00: docs/llms-full_sveltekit.txt
value01:
### Videos

Video files can be very large, so extra care should be taken to ensure that they're optimized:

- Compress videos with tools such as [Handbrake](https://handbrake.fr/). Consider converting the videos to web-friendly formats such as `.webm` or `.mp4`.
- You can [lazy-load videos](https://web.dev/articles/lazy-loading-video) located below the fold with `preload="none"` (though note that this will slow down playback when the user _does_ initiate it).
- Strip the audio track out of muted videos using a tool like [FFmpeg](https://ffmpeg.org/).

### Fonts


value00: docs/llms-full_sveltekit.txt
value01:
For slow-loading data that isn't needed immediately, the object returned from your `load` function can contain promises rather than the data itself. For server `load` functions, this will cause the data to [stream](load#Streaming-with-promises) in after the navigation (or initial page load).

### Preventing waterfalls

One of the biggest performance killers is what is referred to as a _waterfall_, which is a series of requests that is made sequentially. This can happen on the server or in the browser, but is especially costly when dealing with data that has to travel further or across slower networks, such as a mobile user making a call to a distant server.


value00: docs/llms-full_sveltekit.txt
value01:
- is an array for an explicit selection
- is `null` or `undefined` to keep the selection as is

### state_proxy_equality_mismatch

```
Reactive `$state(...)` proxies and the values they proxy have different identities. Because of this, comparisons with `%operator%` will produce unexpected results
```

`$state(...)` creates a [proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) of the value it is passed. The proxy and the value have different identities, meaning equality checks will always return `false`:

```svelte
<script>
	let value = { foo: 'bar' };
	let proxy = $state(value);


value00: docs/llms-full_sveltekit.txt
value01:
You should provide your image at 2x resolution for HiDPI displays (a.k.a. retina displays). `<enhanced:img>` will automatically take care of serving smaller versions to smaller devices.

> [!NOTE] if you wish to use a [tag name CSS selector](https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Basic_selectors#type_selectors) in your `<style>` block you will need to write `enhanced\:img` to escape the colon in the tag name.

### Dynamically choosing an image


value00: docs/llms-full_sveltekit.txt
value01:
```js
// @filename: ambient.d.ts
import { DurableObjectNamespace } from '@cloudflare/workers-types';

declare global {
	namespace App {
		interface Platform {
			env: {
				YOUR_DURABLE_OBJECT_NAMESPACE: DurableObjectNamespace;
			};
		}
	}
}
// @filename: +server.js
// ---cut---
// @errors: 2355 2322
/// file: +server.js
/** @type {import('./$types').RequestHandler} */
export async function POST({ request, platform }) {
	const x = platform?.env.YOUR_DURABLE_OBJECT_NAMESPACE.idFromName('x');
}
```

> [!NOTE] SvelteKit's built-in [`$env` module]($env-static-private) should be preferred for environment variables.

To make these types available to your app, install [`@cloudflare/workers-types`](https://www.npmjs.com/package/@cloudflare/workers-types) and reference them in your `src/app.d.ts`:


value00: docs/llms-full_sveltekit.txt
value01:
# Images

Images can have a big impact on your app's performance. For best results, you should optimize them by doing the following:

- generate optimal formats like `.avif` and `.webp`
- create different sizes for different screens
- ensure that assets can be cached effectively

Doing this manually is tedious. There are a variety of techniques you can use, depending on your needs and preferences.


value00: docs/llms-full_sveltekit.txt
value01:
You can create stories for component variations and test interactions with the [play function](https://storybook.js.org/docs/writing-tests/interaction-testing?renderer=svelte#writing-interaction-tests), which allows you to simulate behavior and make assertions using the Testing Library and Vitest APIs. Here's an example of two stories that can be tested, one that renders an empty LoginForm component and one that simulates a user filling out the form:

```svelte
/// file: LoginForm.stories.svelte
<script module>
	import { defineMeta } from '@storybook/addon-svelte-csf';
	import { expect, fn } from 'storybook/test';

	import LoginForm from './LoginForm.svelte';


value00: docs/llms-full_sveltekit.txt
value01:
### Dynamically choosing an image

You can also manually import an image asset and pass it to an `<enhanced:img>`. This is useful when you have a collection of static images and would like to dynamically choose one or [iterate over them](https://github.com/sveltejs/kit/blob/0ab1733e394b6310895a1d3bf0f126ce34531170/sites/kit.svelte.dev/src/routes/home/Showcase.svelte). In this case you will need to update both the `import` statement and `<img>` element as shown below to indicate you'd like process them.

```svelte
<script>
	import MyImage from './path/to/your/image.jpg?enhanced';
</script>


value00: docs/llms-full_sveltekit.txt
value01:
### snippet_parameter_assignment

```
Cannot reassign or bind to snippet parameter
```

### snippet_shadowing_prop

```
This snippet is shadowing the prop `%prop%` with the same name
```

### state_field_duplicate

```
`%name%` has already been declared on this class
```

An assignment to a class field that uses a `$state` or `$derived` rune is considered a _state field declaration_. The declaration can happen in the class body...

```js
class Counter {
	count = $state(0);
}
```

...or inside the constructor...

```js
class Counter {
	constructor() {
		this.count = $state(0);
	}
}
```

...but it can only happen once.

### state_field_invalid_assignment

```
Cannot assign to a state field before its declaration
```

### state_invalid_export


value00: docs/llms-full_sveltekit.txt
value01:
 Avoid this issue by using [server `load` functions](load#Universal-vs-server) to make requests to backend services that are dependencies from the server rather than from the browser. Note, however, that server `load` functions are also not immune to waterfalls (though they are much less costly since they rarely involve round trips with high latency). For example, if you query a database to get the current user and then use that data to make a second query for a list of saved items, it will typically be more performant to issue a single query with a database join.


value00: docs/llms-full_sveltekit.txt
value01:
## Where can I get support?

If your question is about certain syntax, the [reference docs](/docs/svelte) are a good place to start.

Stack Overflow is a popular forum to ask code-level questions or if you’re stuck with a specific error. Read through the existing questions tagged with [Svelte](https://stackoverflow.com/questions/tagged/svelte+or+svelte-3) or [ask your own](https://stackoverflow.com/questions/ask?tags=svelte)!

There are online forums and chats which are a great place for discussion about best practices, application architecture or just to get to know fellow Svelte users. [Our Discord](/chat) or [the Reddit channel](https://www.reddit.com/r/sveltejs/) are examples of that. If you have an answerable code-level question, Stack Overflow is usually a better fit.


value00: docs/llms-full_sveltekit.txt
value01:
* Safari - [enhancing the performance of your webpage](https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/Web_Inspector_Tutorial/EnhancingyourWebpagesPerformance/EnhancingyourWebpagesPerformance.html)


value00: docs/llms-full_sveltekit.txt
value01:
### Basic usage

Use in your `.svelte` components by using `<enhanced:img>` rather than `<img>` and referencing the image file with a [Vite asset import](https://vitejs.dev/guide/assets.html#static-asset-handling) path:

```svelte
<enhanced:img src="./path/to/your/image.jpg" alt="An alt text" />
```

At build time, your `<enhanced:img>` tag will be replaced with an `<img>` wrapped by a `<picture>` providing multiple image types and sizes. It's only possible to downscale images without losing quality, which means that you should provide the highest resolution image that you need — smaller versions will be generated for the various device types that may request an image.


value00: docs/llms-full_sveltekit.txt
value01:
```dts
function quintOut(t: number): number;
```

</div>



## sineIn

<div class="ts-block">

```dts
function sineIn(t: number): number;
```

</div>



## sineInOut

<div class="ts-block">

```dts
function sineInOut(t: number): number;
```

</div>



## sineOut

<div class="ts-block">

```dts
function sineOut(t: number): number;
```

</div>

# svelte/events

```js
// @noErrors
import { on } from 'svelte/events';
```


value00: docs/llms-full_sveltekit.txt
value01:
- For each image type, use the appropriate solution from those discussed above. You can mix and match all three solutions in one project. For example, you may use Vite's built-in handling to provide images for `<meta>` tags, display images on your homepage with `@sveltejs/enhanced-img`, and display user-submitted content with a dynamic approach.
- Consider serving all images via CDN regardless of the image optimization types you use. CDNs reduce latency by distributing copies of static assets globally.


value00: docs/llms-full_sveltekit.txt
value01:
Avoid using `$state` here. If `component` _does_ need to be reactive for some reason, use `$state.raw` instead.

### svelte_boundary_reset_noop

```
A `<svelte:boundary>` `reset` function only resets the boundary the first time it is called
```

When an error occurs while rendering the contents of a [`<svelte:boundary>`](https://svelte.dev/docs/svelte/svelte-boundary), the `onerror` handler is called with the error plus a `reset` function that attempts to re-render the contents.

This `reset` function should only be called once. After that, it has no effect — in a case like this, where a reference to `reset` is stored outside the boundary, clicking the button while `<Contents />` is rendered will _not_ cause the contents to be rendered again.

```svelte
<script>
	let reset;
</script>


value00: docs/llms-full_sveltekit.txt
value01:
In the browser, waterfalls can occur when your HTML kicks off request chains such as requesting JS which requests CSS which requests a background image and web font. SvelteKit will largely solve this class of problems for you by adding [`modulepreload`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/modulepreload) tags or headers, but you should view [the network tab in your devtools](#Diagnosing-issues) to check whether additional resources need to be preloaded.
- Pay special attention to this if you use [web fonts](#Optimizing-assets-Fonts) since they need to be handled manually.


value00: docs/llms-full_sveltekit.txt
value01:
	import LoginForm from './LoginForm.svelte';

	const { Story } = defineMeta({
		component: LoginForm,
		args: {
			// Pass a mock function to the `onSubmit` prop
			onSubmit: fn(),
		}
	});
</script>
 
<Story name="Empty Form" />
 
<Story
	name="Filled Form"
	play={async ({ args, canvas, userEvent }) => {
		// Simulate a user filling out the form
		await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');
		await userEvent.type(canvas.getByTestId('password'), 'a-random-password');
		await userEvent.click(canvas.getByRole('button'));

		// Run assertions
		await expect(args.onSubmit).toHaveBeenCalledTimes(1);
		await expect(canvas.getByText('You’re in!')).toBeInTheDocument();
	}}
/>
```

## End-to-end tests with Playwright


value00: docs/llms-full_sveltekit.txt
value01:
We can also _override_ the current data while the submission is ongoing:

```ts
import type { RemoteQuery, RemoteQueryOverride } from '@sveltejs/kit';
interface Post {}
declare function submit(): Promise<any> & {
	updates(...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Promise<any>;
}

declare function getPosts(): RemoteQuery<Post[]>;
declare const newPost: Post;
// ---cut---
await submit().updates(
	getPosts().withOverride((posts) => [newPost, ...posts])
);
```

The override will be applied immediately, and released when the submission completes (or fails).


value00: docs/llms-full_sveltekit.txt
value01:
Doing this manually is tedious. There are a variety of techniques you can use, depending on your needs and preferences.

## Vite's built-in handling

[Vite will automatically process imported assets](https://vitejs.dev/guide/assets.html) for improved performance. This includes assets referenced via the CSS `url()` function. Hashes will be added to the filenames so that they can be cached, and assets smaller than `assetsInlineLimit` will be inlined. Vite's asset handling is most often used for images, but is also useful for video, audio, etc.

```svelte
<script>
	import logo from '$lib/assets/logo.png';
</script>

<img alt="The project logo" src={logo} />
```


value00: docs/llms-full_sveltekit.txt
value01:
### style_directive_invalid_modifier

```
`style:` directive can only use the `important` modifier
```

### style_duplicate

```
A component can have a single top-level `<style>` element
```

### svelte_body_illegal_attribute

```
`<svelte:body>` does not support non-event attributes or spread attributes
```

### svelte_boundary_invalid_attribute

```
Valid attributes on `<svelte:boundary>` are `onerror` and `failed`
```

### svelte_boundary_invalid_attribute_value

```
Attribute value must be a non-string expression
```

### svelte_component_invalid_this

```
Invalid component definition — must be an `{expression}`
```


value00: docs/llms-full_sveltekit.txt
value01:
### Receiving data

By exporting `POST`/`PUT`/`PATCH`/`DELETE`/`OPTIONS`/`HEAD` handlers, `+server.js` files can be used to create a complete API:

```svelte
<!--- file: src/routes/add/+page.svelte --->
<script>
	let a = $state(0);
	let b = $state(0);
	let total = $state(0);

	async function add() {
		const response = await fetch('/api/add', {
			method: 'POST',
			body: JSON.stringify({ a, b }),
			headers: {
				'content-type': 'application/json'
			}
		});

		total = await response.json();
	}
</script>

<input type="number" bind:value={a}> +
<input type="number" bind:value={b}> =
{total}

<button onclick={add}>Calculate</button>
```

```js
/// file: src/routes/api/add/+server.js
import { json } from '@sveltejs/kit';


value00: docs/llms-full_sveltekit.txt
value01:
### +layout@

Like pages, layouts can _themselves_ break out of their parent layout hierarchy, using the same technique. For example, a `+layout@.svelte` component would reset the hierarchy for all its child routes.

```
src/routes/
├ (app)/
│ ├ item/
│ │ ├ [id]/
│ │ │ ├ embed/
│ │ │ │ └ +page.svelte  // uses (app)/item/[id]/+layout.svelte
│ │ │ ├ +layout.svelte  // inherits from (app)/item/+layout@.svelte
│ │ │ └ +page.svelte    // uses (app)/item/+layout@.svelte
│ │ └ +layout@.svelte   // inherits from root layout, skipping (app)/+layout.svelte
│ └ +layout.svelte
└ +layout.svelte
```

### When to use layout groups


value00: docs/llms-full_sveltekit.txt
value01:
```svelte
<script>
	let value = { foo: 'bar' };
	let proxy = $state(value);

	value === proxy; // always false
</script>
```

To resolve this, ensure you're comparing values where both values were created with `$state(...)`, or neither were. Note that `$state.raw(...)` will _not_ create a state proxy.

### state_proxy_unmount

```
Tried to unmount a state proxy, rather than a component
```

`unmount` was called with a state proxy:

```js
import { mount, unmount } from 'svelte';
import Component from './Component.svelte';
let target = document.body;
// ---cut---
let component = $state(mount(Component, { target }));

// later...
unmount(component);
```

Avoid using `$state` here. If `component` _does_ need to be reactive for some reason, use `$state.raw` instead.


value00: docs/llms-full_sveltekit.txt
value01:
```dts
function sineOut(t: number): number;
```

</div>

# svelte/events

```js
// @noErrors
import { on } from 'svelte/events';
```

## on

Attaches an event handler to the window and returns a function that removes the handler. Using this
rather than `addEventListener` will preserve the correct order relative to handlers added declaratively
(with attributes like `onclick`), which use event delegation for performance reasons

<div class="ts-block">

```dts
function on<Type extends keyof WindowEventMap>(
	window: Window,
	type: Type,
	handler: (
		this: Window,
		event: WindowEventMap[Type] & { currentTarget: Window }
	) => any,
	options?: AddEventListenerOptions | undefined
): () => void;
```

</div>

<div class="ts-block">


value00: docs/llms-full_sveltekit.txt
value01:
- Your original images should have a good quality/resolution and should have 2x the width it will be displayed at to serve HiDPI devices. Image processing can size images down to save bandwidth when serving smaller screens, but it would be a waste of bandwidth to invent pixels to size images up.
- For images which are much larger than the width of a mobile device (roughly 400px), such as a hero image taking the width of the page design, specify `sizes` so that smaller images can be served on smaller devices.
- For important images, such as the [largest contentful paint (LCP)](https://web.dev/articles/lcp) image, set `fetchpriority="high"` and avoid `loading="lazy"` to prioritize loading as early as possible.


value00: docs/llms-full_sveltekit.txt
value01:
If you have a `+server.js` alongside your `+page.server.js`, `fetch` requests will be routed there by default. To `POST` to an action in `+page.server.js` instead, use the custom `x-sveltekit-action` header:

```js
// @errors: 2532 2304
const response = await fetch(this.action, {
	method: 'POST',
	body: data,
+++	headers: {
		'x-sveltekit-action': 'true'
	}+++
});
```

## Alternatives

Form actions are the preferred way to send data to the server, since they can be progressively enhanced, but you can also use [`+server.js`](routing#server) files to expose (for example) a JSON API. Here's how such an interaction could look like:

```svelte
<!--- file: src/routes/send-message/+page.svelte --->
<script>
	function rerun() {
		fetch('/api/ci', {
			method: 'POST'
		});
	}
</script>


value00: docs/llms-full_sveltekit.txt
value01:
The smallest picture generated automatically will have a width of 540px. If you'd like smaller images or would otherwise like to specify custom widths, you can do that with the `w` query parameter:
```svelte
<enhanced:img
  src="./image.png?w=1280;640;400"
  sizes="(min-width:1920px) 1280px, (min-width:1080px) 640px, (min-width:768px) 400px"
/>
```

If `sizes` is not provided, then a HiDPI/Retina image and a standard resolution image will be generated. The image you provide should be 2x the resolution you wish to display so that the browser can display that image on devices with a high [device pixel ratio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio).

### Per-image transforms


value00: docs/llms-full_sveltekit.txt
value01:
```ts
/// file: src/app.d.ts
+++import { KVNamespace, DurableObjectNamespace } from '@cloudflare/workers-types';+++

declare global {
	namespace App {
		interface Platform {
+++			env: {
				YOUR_KV_NAMESPACE: KVNamespace;
				YOUR_DURABLE_OBJECT_NAMESPACE: DurableObjectNamespace;
			};+++
		}
	}
}

export {};
```

### Testing locally


value00: docs/llms-full_sveltekit.txt
value01:
```svelte
<script>
	import MyImage from './path/to/your/image.jpg?enhanced';
</script>

<enhanced:img src={MyImage} alt="some alt text" />
```

You can also use [Vite's `import.meta.glob`](https://vitejs.dev/guide/features.html#glob-import). Note that you will have to specify `enhanced` via a [custom query](https://vitejs.dev/guide/features.html#custom-queries):

```svelte
<script>
	const imageModules = import.meta.glob(
		'/path/to/assets/*.{avif,gif,heif,jpeg,jpg,png,tiff,webp}',
		{
			eager: true,
			query: {
				enhanced: true
			}
		}
	)
</script>

{#each Object.entries(imageModules) as [_path, module]}
	<enhanced:img src={module.default} alt="some alt text" />
{/each}
```

> [!NOTE] svg images are currently only supported statically

### Intrinsic Dimensions


value00: docs/llms-full_sveltekit.txt
value01:
> [!NOTE] svg images are currently only supported statically

### Intrinsic Dimensions

`width` and `height` are optional as they can be inferred from the source image and will be automatically added when the `<enhanced:img>` tag is preprocessed. With these attributes, the browser can reserve the correct amount of space, preventing [layout shift](https://web.dev/articles/cls). If you'd like to use a different `width` and `height` you can style the image with CSS. Because the preprocessor adds a `width` and `height` for you, if you'd like one of the dimensions to be automatically calculated then you will need to specify that:

```svelte
<style>
	.hero-image img {
		width: var(--size);
		height: auto;
	}
</style>
```

### `srcset` and `sizes`


value00: docs/llms-full_sveltekit.txt
value01:
When the value of an `<option>` matches its text content, the attribute can be omitted.

```svelte
<select multiple bind:value={fillings}>
	<option>Rice</option>
	<option>Beans</option>
	<option>Cheese</option>
	<option>Guac (extra)</option>
</select>
```

You can give the `<select>` a default value by adding a `selected` attribute to the`<option>` (or options, in the case of `<select multiple>`) that should be initially selected. If the `<select>` is part of a form, it will revert to that selection when the form is reset. Note that for the initial render the value of the binding takes precedence if it's not `undefined`.

```svelte
<select bind:value={selected}>
	<option value={a}>a</option>
	<option value={b} selected>b</option>
	<option value={c}>c</option>
</select>
```

## `<audio>`


value00: docs/llms-full_sveltekit.txt
value01:
## The "lang" attribute

By default, SvelteKit's page template sets the default language of the document to English. If your content is not in English, you should update the `<html>` element in `src/app.html` to have the correct [`lang`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang#accessibility) attribute. This will ensure that any assistive technology reading the document uses the correct pronunciation. For example, if your content is in German, you should update `app.html` to the following:

```html
/// file: src/app.html
<html lang="de">
```

If your content is available in multiple languages, you should set the `lang` attribute based on the language of the current page. You can do this with SvelteKit's [handle hook](hooks#Server-hooks-handle):


value00: docs/llms-full_sveltekit.txt
value01:
We recognize that accessibility can be hard to get right. If you want to suggest improvements to how SvelteKit handles accessibility, please [open a GitHub issue](https://github.com/sveltejs/kit/issues).

## Route announcements


value00: docs/llms-full_sveltekit.txt
value01:
Using a content delivery network (CDN) can allow you to optimize these images dynamically, and provides more flexibility with regards to sizes, but it may involve some setup overhead and usage costs. Depending on caching strategy, the browser may not be able to use a cached copy of the asset until a [304 response](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/304) is received from the CDN. Building HTML to target CDNs allows using an `<img>` tag since the CDN can serve the appropriate format based on the `User-Agent` header, whereas build-time optimizations must produce `<picture>` tags with multiple sources. Finally, some CDNs may generate images lazily, which could have a negative performance impact for sites with low traffic and frequently changing images.


value00: docs/llms-full_sveltekit.txt
value01:
```svelte
<style>
	.hero-image img {
		width: var(--size);
		height: auto;
	}
</style>
```

### `srcset` and `sizes`

If you have a large image, such as a hero image taking the width of the design, you should specify `sizes` so that smaller versions are requested on smaller devices. E.g. if you have a 1280px image you may want to specify something like:

```svelte
<enhanced:img src="./image.png" sizes="min(1280px, 100vw)"/>
```

If `sizes` is specified, `<enhanced:img>` will generate small images for smaller devices and populate the `srcset` attribute.


value00: docs/llms-full_sveltekit.txt
value01:
Because of this behavior, every page in your app should have a unique, descriptive title. In SvelteKit, you can do this by placing a `<svelte:head>` element on each page:

```svelte
<!--- file: src/routes/+page.svelte --->
<svelte:head>
	<title>Todo List</title>
</svelte:head>
```

This will allow screen readers and other assistive technology to identify the new page after a navigation occurs. Providing a descriptive title is also important for [SEO](seo#Manual-setup-title-and-meta).

## Focus management

In traditional server-rendered applications, every navigation will reset focus to the top of the page. This ensures that people browsing the web with a keyboard or screen reader will start interacting with the page from the beginning.


value00: docs/llms-full_sveltekit.txt
value01:
 Give the image a container or styling so that it is constrained and does not jump around while the page is loading affecting your [cumulative layout shift (CLS)](https://web.dev/articles/cls). `width` and `height` help the browser to reserve space while the image is still loading, so `@sveltejs/enhanced-img` will add a `width` and `height` for you.
- Always provide a good `alt` text. The Svelte compiler will warn you if you don't do this.


value00: docs/llms-full_sveltekit.txt
value01:
export {};
```

### Testing locally

Cloudflare specific values in the `platform` property are emulated during dev and preview modes. Local [bindings](https://developers.cloudflare.com/workers/wrangler/configuration/#bindings) are created based on your [Wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/) and are used to populate `platform.env` during development and preview. Use the adapter config [`platformProxy` option](#Options-platformProxy) to change your preferences for the bindings.


value00: docs/llms-full_sveltekit.txt
value01:
SvelteKit 2 cleans this up by calling `handleError` hooks with two new properties: `status` and `message`. For errors thrown from your code (or library code called by your code) the status will be `500` and the message will be `Internal Error`. While `error.message` may contain sensitive information that should not be exposed to users, `message` is safe.

## Dynamic environment variables cannot be used during prerendering

The `$env/dynamic/public` and `$env/dynamic/private` modules provide access to _run time_ environment variables, as opposed to the _build time_ environment variables exposed by `$env/static/public` and `$env/static/private`.


value00: docs/llms-full_sveltekit.txt
value01:
# Accessibility

SvelteKit strives to provide an accessible platform for your app by default. Svelte's [compile-time accessibility checks](../svelte/compiler-warnings) will also apply to any SvelteKit application you build.

Here's how SvelteKit's built-in accessibility features work and what you need to do to help these features to work as well as possible. Keep in mind that while SvelteKit provides an accessible foundation, you are still responsible for making sure your application code is accessible. If you're new to accessibility, see the ["further reading"](accessibility#Further-reading) section of this guide for additional resources.


value00: docs/llms-full_sveltekit.txt
value01:
## Generated `tsconfig.json` is more strict

Previously, the generated `tsconfig.json` was trying its best to still produce a somewhat valid config when your `tsconfig.json` included `paths` or `baseUrl`. In SvelteKit 2, the validation is more strict and will warn when you use either `paths` or `baseUrl` in your `tsconfig.json`. These settings are used to generate path aliases and you should use [the `alias` config](configuration#alias) option in your `svelte.config.js` instead, to also create a corresponding alias for the bundler.

## `getRequest` no longer throws errors


value00: docs/llms-full_sveltekit.txt
value01:
### External scripts

Try to minimize the number of third-party scripts running in the browser. For example, instead of using JavaScript-based analytics consider using server-side implementations, such as those offered by many platforms with SvelteKit adapters including [Cloudflare](https://www.cloudflare.com/web-analytics/), [Netlify](https://docs.netlify.com/monitor-sites/site-analytics/), and [Vercel](https://vercel.com/docs/analytics).

To run third party scripts in a web worker (which avoids blocking the main thread), use [Partytown's SvelteKit integration](https://partytown.builder.io/sveltekit).

### Selective loading


value00: docs/llms-full_sveltekit.txt
value01:
```js
/// file: +page.js/+page.server.js/+server.js
export const prerender = false;
```

Routes with `prerender = true` will be excluded from manifests used for dynamic SSR, making your server (or serverless/edge functions) smaller. In some cases you might want to prerender a route but also include it in the manifest (for example, with a route like `/blog/[slug]` where you want to prerender your most recent/popular content but server-render the long tail) — for these cases, there's a third option, 'auto':

```js
/// file: +page.js/+page.server.js/+server.js
export const prerender = 'auto';
```

> [!NOTE] If your entire app is suitable for prerendering, you can use [`adapter-static`](adapter-static), which will output files suitable for use with any static webserver.


value00: docs/llms-full_sveltekit.txt
value01:
```svelte
<!--- file: src/routes/todos/+page.svelte --->
<script>
	import { getTodos, modifyTodo } from '../data.remote';
</script>

<h1>Todos</h1>

{#each await getTodos() as todo}
	{@const modify = modifyTodo.for(todo.id)}
	<form {...modify}>
		<!-- -->
		<button disabled={!!modify.pending}>save changes</button>
	</form>
{/each}
```

### Multiple submit buttons

It's possible for a `<form>` to have multiple submit buttons. For example, you might have a single form that allows you to log in or register depending on which button was clicked.

To accomplish this, add a field to your schema for the button value, and use `as('submit', value)` to bind it:

```svelte
<!--- file: src/routes/login/+page.svelte --->
<script>
	import { loginOrRegister } from '$lib/auth';
</script>


value00: docs/llms-full_sveltekit.txt
value01:
- [`clientWidth`](https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth)
- [`clientHeight`](https://developer.mozilla.org/en-US/docs/Web/API/Element/clientHeight)
- [`offsetWidth`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetWidth)
- [`offsetHeight`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetHeight)
- [`contentRect`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentRect)
- [`contentBoxSize`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentBoxSize)


value00: docs/llms-full_sveltekit.txt
value01:
let a = 1;
let b = 2;
let total = add(a, b);
console.log(total); // 3

a = 3;
b = 4;
console.log(total); // still 3!
```

If `add` wanted to have access to the _current_ values of `a` and `b`, and to return the current `total` value, you would need to use functions instead:

```js
/// file: index.js
// @filename: index.js
// ---cut---
/**
 * @param {() => number} getA
 * @param {() => number} getB
 */
function add(+++getA, getB+++) {
	return +++() => getA() + getB()+++;
}

let a = 1;
let b = 2;
let total = add+++(() => a, () => b)+++;
console.log(+++total()+++); // 3

a = 3;
b = 4;
console.log(+++total()+++); // 7
```

State in Svelte is no different — when you reference something declared with the `$state` rune...

```js
let a = +++$state(1)+++;
let b = +++$state(2)+++;
```


value00: docs/llms-full_sveltekit.txt
value01:
_Component Tests_: Validating that a Svelte component mounts and interacts as expected throughout its lifecycle requires a tool that provides a Document Object Model (DOM). Components can be compiled (since Svelte is a compiler and not a normal library) and mounted to allow asserting against element structure, listeners, state, and all the other capabilities provided by a Svelte component. Tools for component testing range from an in-memory implementation like jsdom paired with a test runner like [Vitest](https://vitest.dev/) to solutions that leverage an actual browser to provide a visual testing capability such as [Playwright](https://playwright.dev/docs/test-components) or [Cypress](https://www.cypress.io/).


value00: docs/llms-full_sveltekit.txt
value01:
```js
/// file: src/routes/api/add/+server.js
import { json } from '@sveltejs/kit';

/** @type {import('./$types').RequestHandler} */
export async function POST({ request }) {
	const { a, b } = await request.json();
	return json(a + b);
}
```

> [!NOTE] In general, [form actions](form-actions) are a better way to submit data from the browser to the server.

> [!NOTE] If a `GET` handler is exported, a `HEAD` request will return the `content-length` of the `GET` handler's response body.

### Fallback method handler

Exporting the `fallback` handler will match any unhandled request methods, including methods like `MOVE` which have no dedicated export from `+server.js`.

```js
/// file: src/routes/api/add/+server.js
import { json, text } from '@sveltejs/kit';


value00: docs/llms-full_sveltekit.txt
value01:
</div>

<div class="ts-block">

```dts
function on<
	Element extends MediaQueryList,
	Type extends keyof MediaQueryListEventMap
>(
	element: Element,
	type: Type,
	handler: (
		this: Element,
		event: MediaQueryListEventMap[Type] & {
			currentTarget: Element;
		}
	) => any,
	options?: AddEventListenerOptions | undefined
): () => void;
```

</div>

<div class="ts-block">

```dts
function on(
	element: EventTarget,
	type: string,
	handler: EventListener,
	options?: AddEventListenerOptions | undefined
): () => void;
```

</div>


value00: docs/llms-full_sveltekit.txt
value01:
## Route announcements

In traditional server-rendered applications, every navigation (e.g. clicking on an `<a>` tag) triggers a full page reload. When this happens, screen readers and other assistive technology will read out the new page's title so that users understand that the page has changed.

Since navigation between pages in SvelteKit happens without reloading the page (known as [client-side routing](glossary#Routing)), SvelteKit injects a [live region](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions) onto the page that will read out the new page name after each navigation. This determines the page name to announce by inspecting the `<title>` element.


value00: docs/llms-full_sveltekit.txt
value01:
- [`borderBoxSize`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/borderBoxSize)
- [`devicePixelContentBoxSize`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/devicePixelContentBoxSize)


value00: docs/llms-full_sveltekit.txt
value01:
...you're accessing its _current value_.

Note that 'functions' is broad — it encompasses properties of proxies and [`get`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get)/[`set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) properties...

```js
/// file: index.js
// @filename: index.js
// ---cut---
/**
 * @param {{ a: number, b: number }} input
 */
function add(input) {
	return {
		get value() {
			return input.a + input.b;
		}
	};
}

let input = $state({ a: 1, b: 2 });
let total = add(input);
console.log(total.value); // 3

input.a = 3;
input.b = 4;
console.log(total.value); // 7
```

...though if you find yourself writing code like that, consider using [classes](#Classes) instead.


value00: docs/llms-full_sveltekit.txt
value01:
</blockquote>

Takes the component function and returns a Svelte 4 compatible component constructor.

<div class="ts-block">

```dts
function asClassComponent<
	Props extends Record<string, any>,
	Exports extends Record<string, any>,
	Events extends Record<string, any>,
	Slots extends Record<string, any>
>(
	component:
		| SvelteComponent<Props, Events, Slots>
		| Component<Props>
): ComponentType<
	SvelteComponent<Props, Events, Slots> & Exports
>;
```

</div>



## createBubbler

<blockquote class="tag deprecated note">

Use this only as a temporary solution to migrate your automatically delegated events in Svelte 5.

</blockquote>

Function to create a `bubble` function that mimic the behavior of `on:click` without handler available in svelte 4.


value00: docs/llms-full_sveltekit.txt
value01:
</div>

<div class="ts-block">

```dts
function on<Type extends keyof DocumentEventMap>(
	document: Document,
	type: Type,
	handler: (
		this: Document,
		event: DocumentEventMap[Type] & {
			currentTarget: Document;
		}
	) => any,
	options?: AddEventListenerOptions | undefined
): () => void;
```

</div>

<div class="ts-block">

```dts
function on<
	Element extends HTMLElement,
	Type extends keyof HTMLElementEventMap
>(
	element: Element,
	type: Type,
	handler: (
		this: Element,
		event: HTMLElementEventMap[Type] & {
			currentTarget: Element;
		}
	) => any,
	options?: AddEventListenerOptions | undefined
): () => void;
```

</div>

<div class="ts-block">


value00: docs/llms-full_sveltekit.txt
value01:
As with `$state`, you can mark class fields as `$derived`.

> [!NOTE] Code in Svelte components is only executed once at creation. Without the `$derived` rune, `doubled` would maintain its original value even when `count` changes.

## `$derived.by`

Sometimes you need to create complex derivations that don't fit inside a short expression. In these cases, you can use `$derived.by` which accepts a function as its argument.

```svelte
<script>
	let numbers = $state([1, 2, 3]);
	let total = $derived.by(() => {
		let total = 0;
		for (const n of numbers) {
			total += n;
		}
		return total;
	});
</script>

<button onclick={() => numbers.push(numbers.length + 1)}>
	{numbers.join(' + ')} = {total}
</button>
```

In essence, `$derived(expression)` is equivalent to `$derived.by(() => expression)`.


value00: docs/llms-full_sveltekit.txt
value01:
```svelte
<script>
	let reset;
</script>

<button onclick={reset}>reset</button>

<svelte:boundary onerror={(e, r) => (reset = r)}>
	<!-- contents -->

	{#snippet failed(e)}
		<p>oops! {e.message}</p>
	{/snippet}
</svelte:boundary>
```


value00: docs/llms-full_sveltekit.txt
value01:
## `form` and `data` have been removed from `use:enhance` callbacks

If you provide a callback to [`use:enhance`](form-actions#Progressive-enhancement-use:enhance), it will be called with an object containing various useful properties.

In SvelteKit 1, those properties included `form` and `data`. These were deprecated some time ago in favour of `formElement` and `formData`, and have been removed altogether in SvelteKit 2.

## Forms containing file inputs must use `multipart/form-data`


value00: docs/llms-full_sveltekit.txt
value01:
- Do not use `em` or `rem` in `sizes` and change the default size of these measures. When used in `sizes` or `@media` queries, `em` and `rem` are both defined to mean the user's default `font-size`. For a `sizes` declaration like `sizes="(min-width: 768px) min(100vw, 108rem), 64rem"`, the actual `em` or `rem` that controls how the image is laid out on the page can be different if changed by CSS. For example, do not do something like `html { font-size: 62.5%; }` as the slot reserved by the browser preloader will now end up being larger than the actual slot of the CSS object model once it has been created.


value00: docs/llms-full_sveltekit.txt
value01:
---const path = base + resolvePath('/blog/[slug]', { slug });---
+++const path = resolveRoute('/blog/[slug]', { slug });+++
```

`svelte-migrate` will do the method replacement for you, though if you later prepend the result with `base`, you need to remove that yourself.

## Improved error handling

Errors are handled inconsistently in SvelteKit 1. Some errors trigger the `handleError` hook but there is no good way to discern their status (for example, the only way to tell a 404 from a 500 is by seeing if `event.route.id` is `null`), while others (such as 405 errors for `POST` requests to pages without actions) don't trigger `handleError` at all, but should. In the latter case, the resulting `$page.error` will deviate from the [`App.Error`](types#Error) type, if it is specified.


value00: docs/llms-full_sveltekit.txt
value01:
## Further reading

For the most part, building an accessible SvelteKit app is the same as building an accessible web app. You should be able to apply information from the following general accessibility resources to any web experience you build:

- [MDN Web Docs: Accessibility](https://developer.mozilla.org/en-US/docs/Learn/Accessibility)
- [The A11y Project](https://www.a11yproject.com/)
- [How to Meet WCAG (Quick Reference)](https://www.w3.org/WAI/WCAG21/quickref/)

# SEO

The most important aspect of SEO is to create high-quality content that is widely linked to from around the web. However, there are a few technical considerations for building sites that rank well.

## Out of the box

### SSR


value00: docs/llms-full_sveltekit.txt
value01:
### svelte_options_invalid_attribute_value

```
Value must be %list%, if specified
```

### svelte_options_invalid_customelement

```
"customElement" must be a string literal defining a valid custom element name or an object of the form { tag?: string; shadow?: "open" | "none" | `ShadowRootInit`; props?: { [key: string]: { attribute?: string; reflect?: boolean; type: .. } } }
```

### svelte_options_invalid_customelement_props

```
"props" must be a statically analyzable object literal of the form "{ [key: string]: { attribute?: string; reflect?: boolean; type?: "String" | "Boolean" | "Number" | "Array" | "Object" }"
```

### svelte_options_invalid_customelement_shadow


value00: docs/llms-full_sveltekit.txt
value01:
afterNavigate(() => {
	/** @type {HTMLElement | null} */
	const to_focus = document.querySelector('.focus-me');
	to_focus?.focus();
});
```

You can also programmatically navigate to a different page using the [`goto`]($app-navigation#goto) function. By default, this will have the same client-side routing behavior as clicking on a link. However, `goto` also accepts a `keepFocus` option that will preserve the currently-focused element instead of resetting focus. If you enable this option, make sure the currently-focused element still exists on the page after navigation. If the element no longer exists, the user's focus will be lost, making for a confusing experience for assistive technology users.

## The "lang" attribute


value00: docs/llms-full_sveltekit.txt
value01:
You can mix and match these options in different areas of your app. For example, you could prerender your marketing page for maximum speed, server-render your dynamic pages for SEO and accessibility and turn your admin section into an SPA by rendering it on the client only. This makes SvelteKit very versatile.

## prerender

It's likely that at least some routes of your app can be represented as a simple HTML file generated at build time. These routes can be [_prerendered_](glossary#Prerendering).

```js
/// file: +page.js/+page.server.js/+server.js
export const prerender = true;
```

Alternatively, you can set `export const prerender = true` in your root `+layout.js` or `+layout.server.js` and prerender everything except pages that are explicitly marked as _not_ prerenderable:


value00: docs/llms-full_sveltekit.txt
value01:
The override will be applied immediately, and released when the submission completes (or fails).

### Multiple instances of a form

Some forms may be repeated as part of a list. In this case you can create separate instances of a form function via `for(id)` to achieve isolation.

```svelte
<!--- file: src/routes/todos/+page.svelte --->
<script>
	import { getTodos, modifyTodo } from '../data.remote';
</script>


value00: docs/llms-full_sveltekit.txt
value01:
## `getRequest` no longer throws errors

The `@sveltejs/kit/node` module exports helper functions for use in Node environments, including `getRequest` which turns a Node [`ClientRequest`](https://nodejs.org/api/http.html#class-httpclientrequest) into a standard [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) object.

In SvelteKit 1, `getRequest` could throw if the `Content-Length` header exceeded the specified size limit. In SvelteKit 2, the error will not be thrown until later, when the request body (if any) is being read. This enables better diagnostics and simpler code.

## `vitePreprocess` is no longer exported from `@sveltejs/kit/vite`


value00: docs/llms-full_sveltekit.txt
value01:
## Out of the box

### SSR

While search engines have got better in recent years at indexing content that was rendered with client-side JavaScript, server-side rendered content is indexed more frequently and reliably. SvelteKit employs SSR by default, and while you can disable it in [`handle`](hooks#Server-hooks-handle), you should leave it on unless you have a good reason not to.

> [!NOTE] SvelteKit's rendering is highly configurable and you can implement [dynamic rendering](https://developers.google.com/search/docs/advanced/javascript/dynamic-rendering) if necessary. It's not generally recommended, since SSR has other benefits beyond SEO.

### Performance


value00: docs/llms-full_sveltekit.txt
value01:
### svelte.config.js

```js
// @errors: 2307
/// file: svelte.config.js
---import adapter from '@sveltejs/adapter-cloudflare-workers';---
+++import adapter from '@sveltejs/adapter-cloudflare';+++

/** @type {import('@sveltejs/kit').Config} */
const config = {
	kit: {
		adapter: adapter()
	}
};

export default config;
```


value00: docs/llms-full_sveltekit.txt
value01:
### Performance

Signals such as [Core Web Vitals](https://web.dev/vitals/#core-web-vitals) impact search engine ranking. Because Svelte and SvelteKit introduce minimal overhead, they make it easier to build high performance sites. You can test your site's performance using Google's [PageSpeed Insights](https://pagespeed.web.dev/) or [Lighthouse](https://developers.google.com/web/tools/lighthouse). With just a few key actions like using SvelteKit's default [hybrid rendering](glossary#Hybrid-app) mode and [optimizing your images](images), you can greatly improve your site's speed. Read [the performance page](performance) for more details.

### Normalized URLs


value00: docs/llms-full_sveltekit.txt
value01:
Since `@sveltejs/vite-plugin-svelte` is now a peer dependency, SvelteKit 2 no longer re-exports `vitePreprocess`. You should import it directly from `@sveltejs/vite-plugin-svelte`.

## Updated dependency requirements

SvelteKit 2 requires Node `18.13` or higher, and the following minimum dependency versions:

- `svelte@4`
- `vite@5`
- `typescript@5`
- `@sveltejs/vite-plugin-svelte@3` (this is now required as a `peerDependency` of SvelteKit — previously it was directly depended upon)
- `@sveltejs/adapter-cloudflare@3` (if you're using these adapters)
- `@sveltejs/adapter-cloudflare-workers@2`
- `@sveltejs/adapter-netlify@3`
- `@sveltejs/adapter-node@2`
- `@sveltejs/adapter-static@3`
- `@sveltejs/adapter-vercel@4`

`svelte-migrate` will update your `package.json` for you.


value00: docs/llms-full_sveltekit.txt
value01:
<form {...loginOrRegister}>
	<label>
		Your username
		<input {...loginOrRegister.fields.username.as('text')} />
	</label>

	<label>
		Your password
		<input {...loginOrRegister.fields._password.as('password')} />
	</label>

	<button {...loginOrRegister.fields.action.as('submit', 'login')}>login</button>
	<button {...loginOrRegister.fields.action.as('submit', 'register')}>register</button>
</form>
```

In your form handler, you can check which button was clicked:

```js
/// file: $lib/auth.js
import * as v from 'valibot';
import { form } from '$app/server';


value00: docs/llms-full_sveltekit.txt
value01:
## `preloadCode` arguments must be prefixed with `base`

SvelteKit exposes two functions, [`preloadCode`]($app-navigation#preloadCode) and [`preloadData`]($app-navigation#preloadData), for programmatically loading the code and data associated with a particular path. In version 1, there was a subtle inconsistency — the path passed to `preloadCode` did not need to be prefixed with the `base` path (if set), while the path passed to `preloadData` did.

This is fixed in SvelteKit 2 — in both cases, the path should be prefixed with `base` if it is set.

Additionally, `preloadCode` now takes a single argument rather than _n_ arguments.

## `resolvePath` has been removed


value00: docs/llms-full_sveltekit.txt
value01:
CDNs can generally be used without any need for a library. However, there are a number of libraries with Svelte support that make it easier. [`@unpic/svelte`](https://unpic.pics/img/svelte/) is a CDN-agnostic library with support for a large number of providers. You may also find that specific CDNs like [Cloudinary](https://svelte.cloudinary.dev/) have Svelte support. Finally, some content management systems (CMS) which support Svelte (such as [Contentful](https://www.contentful.com/sveltekit-starter-guide/), [Storyblok](https://github.com/storyblok/storyblok-svelte), and [Contentstack](https://www.contentstack.com/docs/developers/sample-apps/build-a-starter-website-with-sveltekit-and-contentstack)) have built-in support for image handling.

## Best practices


value00: docs/llms-full_sveltekit.txt
value01:
```js
/// file: src/hooks.server.js
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
	if (event.url.pathname.startsWith('/custom')) {
		return new Response('custom response');
	}

	const response = await resolve(event);
	return response;
}
```

> [!NOTE] Requests for static assets — which includes pages that were already prerendered — are _not_ handled by SvelteKit.

If unimplemented, defaults to `({ event, resolve }) => resolve(event)`.


value00: docs/llms-full_sveltekit.txt
value01:
Not all use cases are suited for layout grouping, nor should you feel compelled to use them. It might be that your use case would result in complex `(group)` nesting, or that you don't want to introduce a `(group)` for a single outlier. It's perfectly fine to use other means such as composition (reusable `load` functions or Svelte components) or if-statements to achieve what you want. The following example shows a layout that rewinds to the root layout and reuses components and functions that other layouts can also use:

```svelte
<!--- file: src/routes/nested/route/+layout@.svelte --->
<script>
	import ReusableLayout from '$lib/ReusableLayout.svelte';
	let { data, children } = $props();
</script>

<ReusableLayout {data}>
	{@render children()}
</ReusableLayout>
```


value00: docs/llms-full_sveltekit.txt
value01:
### src/service-worker.js

Most imports from `@sapper/service-worker` have equivalents in [`$service-worker`]($service-worker):

- `files` is unchanged
- `routes` has been removed
- `shell` is now `build`
- `timestamp` is now `version`

### src/template.html

The `src/template.html` file should be renamed `src/app.html`.

Remove `%sapper.base%`, `%sapper.scripts%` and `%sapper.styles%`. Replace `%sapper.head%` with `%sveltekit.head%` and `%sapper.html%` with `%sveltekit.body%`. The `<div id="sapper">` is no longer necessary.

### src/node_modules

A common pattern in Sapper apps is to put your internal library in a directory inside `src/node_modules`. This doesn't work with Vite, so we use [`src/lib`]($lib) instead.

## Pages and layouts


value00: docs/llms-full_sveltekit.txt
value01:
> [!NOTE] A common pattern is to return SEO-related `data` from page [`load`](load) functions, then use it (as [`page.data`]($app-state)) in a `<svelte:head>` in your root [layout](routing#layout).

### Sitemaps

[Sitemaps](https://developers.google.com/search/docs/advanced/sitemaps/build-sitemap) help search engines prioritize pages within your site, particularly when you have a large amount of content. You can create a sitemap dynamically using an endpoint:


value00: docs/llms-full_sveltekit.txt
value01:
Additionally, `preloadCode` now takes a single argument rather than _n_ arguments.

## `resolvePath` has been removed

SvelteKit 1 included a function called `resolvePath` which allows you to resolve a route ID (like `/blog/[slug]`) and a set of parameters (like `{ slug: 'hello' }`) to a pathname. Unfortunately the return value didn't include the `base` path, limiting its usefulness in cases where `base` was set.

For this reason, SvelteKit 2 replaces `resolvePath` with a (slightly better named) function called `resolveRoute`, which is imported from `$app/paths` and which takes `base` into account.

```js
---import { resolvePath } from '@sveltejs/kit';
import { base } from '$app/paths';---
+++import { resolveRoute } from '$app/paths';+++


value00: docs/llms-full_sveltekit.txt
value01:
<ReusableLayout {data}>
	{@render children()}
</ReusableLayout>
```

```js
/// file: src/routes/nested/route/+layout.js
// @filename: ambient.d.ts
declare module "$lib/reusable-load-function" {
	export function reusableLoad(event: import('@sveltejs/kit').LoadEvent): Promise<Record<string, any>>;
}
// @filename: index.js
// ---cut---
import { reusableLoad } from '$lib/reusable-load-function';

/** @type {import('./$types').PageLoad} */
export function load(event) {
	// Add additional logic here, if needed
	return reusableLoad(event);
}
```

## Further reading

- [Tutorial: Advanced Routing](/tutorial/kit/optional-params)


value00: docs/llms-full_sveltekit.txt
value01:
Function to create a `bubble` function that mimic the behavior of `on:click` without handler available in svelte 4.

<div class="ts-block">

```dts
function createBubbler(): (
	type: string
) => (event: Event) => boolean;
```

</div>



## createClassComponent

<blockquote class="tag deprecated note">

Use this only as a temporary solution to migrate your imperative component code to Svelte 5.

</blockquote>

Takes the same options as a Svelte 4 component and the component function and returns a Svelte 4 compatible component.

<div class="ts-block">


value00: docs/llms-full_sveltekit.txt
value01:
To simulate this behavior during client-side routing, SvelteKit focuses the `<body>` element after each navigation and [enhanced form submission](form-actions#Progressive-enhancement). There is one exception - if an element with the [`autofocus`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) attribute is present, SvelteKit will focus that element instead. Make sure to [consider the implications for assistive technology](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus#accessibility_considerations) when using that attribute.

If you want to customize SvelteKit's focus management, you can use the `afterNavigate` hook:

```js
/// <reference types="@sveltejs/kit" />
// ---cut---
import { afterNavigate } from '$app/navigation';


