npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

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

About

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

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

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

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

Open Software & Tools

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

© 2026 – Pkg Stats / Ryan Hefner

svelte-reflector

v1.2.2

Published

Reflects zod types from openAPI schemas

Readme

Svelte Reflector

Turn your OpenAPI into a first-class Svelte 5 DX.

Svelte Reflector is a developer-experience-first code generator that converts OpenAPI specs into fully typed, reactive Svelte 5 modules — ready for production, forms included.

npm version npm downloads npm total downloads TypeScript Svelte

Features

  • Automatic Type Generation - Generates TypeScript interfaces and classes from OpenAPI schemas
  • Svelte 5 Runes Integration - Uses $state and $derived for reactive state management
  • Abstract Modules - Generated modules are abstract classes, ready to be extended with custom logic
  • Per-Module Schemas - Each module gets its own schema file with only the types it needs (tree-shaking friendly)
  • Form Handling - Auto-generates form schemas with BuildedInput<T> wrappers and validation support
  • Type-Safe API Calls - Full TypeScript support for all API operations
  • Query Parameter Sync - QueryBuilder and EnumQueryBuilder keep state synced with URL searchParams
  • Enum Support - Auto-generates enum types and array enum query builders
  • OpenAPI/Swagger Compatible - Works with any backend that exposes OpenAPI specs
  • Development Mode - Smart regeneration based on environment
  • Validation Ready - Built-in support for custom field validators
  • Vite Plugin - Can be used as a Vite plugin for automatic generation on build

Installation

npm install svelte-reflector
# or
yarn add svelte-reflector
# or
pnpm add svelte-reflector

Note: prettier >= 3.0.0 is a required peer dependency. Make sure it's installed in your project.

Quick Start

1. Configure Environment Variables

Create a .env file in your project root:

# Required - Your backend URL
BACKEND_URL=https://api.example.com/
# or
PUBLIC_BACKEND=https://api.example.com/

# Optional - Environment (defaults to PROD)
ENVIRONMENT=DEV
# or
VITE_ENVIRONMENT=DEV

2. Create Reflector Config (Optional)

Create a src/reflector.config.ts to define custom validators:

export const validators = [
  {
    fields: ["email", "userEmail"],
    validator: "validateEmail",
  },
  {
    fields: ["phone", "mobile"],
    validator: "validatePhone",
  },
];

Validators are resolved from $lib/sanitizers/validateFormats — you need to implement and export them in your project.

3. Configure API Import Path (Optional)

Create a reflector.json in your project root to customize the API import path:

{
  "api": "$lib/api"
}

Defaults to $lib/api if not specified. This is the module that generated modules will import for making HTTP requests.

4. Run the Generator

# Manual generation
npx reflect

# Or programmatically as a Vite plugin
import { reflector } from "svelte-reflector";
await reflector(true); // true = force generation

5. Use Generated Modules

Generated modules are abstract classes. Extend them to add custom logic or simply to instantiate:

import { UserModule } from "$reflector/controllers/user/user.module.svelte";
import type { User } from "$reflector/controllers/user/user.schema.svelte";

// Extend the abstract module
class UserService extends UserModule {}

const userService = new UserService();

// Access reactive state
console.log(userService.loading); // $state<boolean>
console.log(userService.list);    // $state<User[]>

// Call API methods
await userService.listAll({
  behavior: {
    onSuccess: (response) => console.log(response),
    onError: (error) => console.error(error),
  },
});

// Work with forms
const userForm = userService.forms.createUser;
userForm.name.value = "John Doe";
userForm.email.value = "[email protected]";

// Submit form
await userService.createUser();

Generated Structure

src/reflector/
├── controllers/
│   └── user/
│       ├── user.module.svelte.ts      # Abstract API module with methods
│       └── user.schema.svelte.ts      # Schemas & types used by this module
├── reflector.svelte.ts                # Core utilities (build, isFormValid, QueryBuilder, etc.)
├── fields.ts                          # Field name constants
├── enums.ts                           # Enum type definitions
├── mocked-params.svelte.ts            # Mocked path parameters ($state)
└── backup.json                        # Cached OpenAPI spec

Each module gets its own schema file (*.schema.svelte.ts) containing only the schemas it uses, with transitive dependencies automatically resolved.

Generated Module API

Each generated module is an abstract class that provides:

State Properties

| Property | Type | Description | |----------|------|-------------| | loading | $state<boolean> | Request loading state | | list | $state<T[]> | List results (for list endpoints) | | forms | $state<Record<string, T>> | Form instances | | querys | Querys | Query parameter state (QueryBuilder instances) | | headers | Headers | Header state | | paths | Paths | Path parameter state |

Methods

// List all items (GET with page parameter)
async listAll(params?: { behavior?: Behavior }): Promise<T[]>

// Get single entity (GET without page parameter)
async get(params?: { behavior?: Behavior }): Promise<T>

// Create/Update (POST/PUT/PATCH)
async create(params?: { behavior?: Behavior }): Promise<T>
async update(params?: { behavior?: Behavior }): Promise<T>

// Delete (DELETE)
async delete(params?: { behavior?: Behavior }): Promise<void>

// Reset all state (protected)
protected reset(): void

// Clear forms (protected)
protected clearForms(): void

reset() and clearForms() are protected — override them in your subclass if you need custom reset behavior.

QueryBuilder

Query parameters are wrapped in QueryBuilder instances that sync with URL searchParams:

// Single value query parameter
const querys = module.querys;
querys.status.update("active"); // Updates URL searchParam and internal state

// Array enum query parameter
const enumQuery = module.querys.roles; // EnumQueryBuilder<RoleType>
enumQuery.selected = "admin";
enumQuery.add();      // Adds to URL searchParams
enumQuery.remove(0);  // Removes from URL searchParams
enumQuery.values;     // $derived from URL - always in sync

Configuration

Environment Variables

| Variable | Required | Description | |----------|----------|-------------| | BACKEND_URL | Yes* | Backend API URL | | PUBLIC_BACKEND | Yes* | Alternative to BACKEND_URL | | ENVIRONMENT | No | DEV/PROD (defaults to PROD) | | VITE_ENVIRONMENT | No | Vite-specific env var | | NODE_ENV | No | Node environment |

* At least one of BACKEND_URL or PUBLIC_BACKEND is required.

Behavior Pattern

All API methods accept a Behavior object for callbacks:

class Behavior<TSuccess, TError> {
  onSuccess?: (value: TSuccess) => Promise<void> | void;
  onError?: (error: TError) => Promise<void> | void;
}

// Usage
await userService.createUser({
  behavior: {
    onSuccess: (user) => console.log("Created:", user),
    onError: (err) => console.error("Failed:", err),
  },
});

Form Validation

Forms use BuildedInput class with validation:

class BuildedInput<T> {
  value: T;           // Current value ($state)
  display: T;         // Display value ($state)
  required: boolean;  // Is field required
  placeholder: T;     // Placeholder/example value
  readonly kind: 'builded';
  validator?: (v: T) => string | null; // Validation function
  validate(): string | null; // Run validation
}

// Check if all form fields are valid
import { isFormValid } from "$reflector/reflector.svelte";

if (isFormValid(userService.forms.createUser)) {
  await userService.createUser();
}

TypeScript Configuration

Add path aliases to your tsconfig.json:

{
  "compilerOptions": {
    "paths": {
      "$reflector/*": ["./src/reflector/*"],
      "$lib/*": ["./src/lib/*"]
    }
  }
}

For Vite projects, also update vite.config.ts:

export default defineConfig({
  resolve: {
    alias: {
      $reflector: path.resolve("./src/reflector"),
      $lib: path.resolve("./src/lib"),
    },
  },
});

Workflow

Development Mode

In ENVIRONMENT=DEV:

  • Schemas are NOT auto-regenerated on build
  • Use npx reflect to manually regenerate
  • Faster builds, manual control

Production Mode

In ENVIRONMENT=PROD:

  • Schemas are auto-regenerated on each build
  • Fresh types from latest OpenAPI spec
  • Fallback to backup.json if backend is unavailable

Advanced Usage

Extending Abstract Modules

Since modules are abstract, you can add custom logic:

import { UserModule } from "$reflector/controllers/user/user.module.svelte";

class UserService extends UserModule {
  // Add custom computed state
  get activeUsers() {
    return this.list.filter(u => u.active);
  }

  // Override protected methods for custom behavior
  protected override clearForms() {
    super.clearForms();
    // custom cleanup logic
  }

  // Add custom methods
  async fetchAndFilter(status: string) {
    this.querys.status.update(status);
    await this.listAll();
  }
}

Manual Schema Access

import { User } from "$reflector/controllers/user/user.schema.svelte";

// Create instance
const user = new User({ name: "John", email: "[email protected]" });

// Get data bundle
const data = user.bundle(); // { name: "John", email: "[email protected]" }

Batch Query Updates

import { setQueryGroup } from "$reflector/reflector.svelte";

// Update multiple query params at once
setQueryGroup([
  { key: "page", value: 1 },
  { key: "status", value: "active" },
  { key: "roles", value: ["admin", "editor"] }, // Array params supported
]);

Troubleshooting

"BACKEND_URL vazio" Error

Ensure you have set BACKEND_URL or PUBLIC_BACKEND in your .env file.

Schemas Not Updating

In DEV mode, run npx reflect manually. Check that your backend's OpenAPI spec is accessible at {BACKEND_URL}openapi.json.

Type Errors After Generation

  1. Restart your TypeScript language server
  2. Check path aliases in tsconfig.json
  3. Ensure $reflector/* alias is configured

License

MIT License - see LICENSE for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Links


Built with by the Pinaculo Digital team.