Socket
Book a DemoInstallSign in
Socket

@loopkitchen/oats

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@loopkitchen/oats

๐ŸŒพ OATS - OpenAPI TypeScript Sync. The missing link between your OpenAPI specs and TypeScript applications. Automatically watch, generate, and sync TypeScript clients from your API definitions.

2.2.3
latest
Source
npmnpm
Version published
Weekly downloads
0
Maintainers
1
Weekly downloads
ย 
Created
Source

๐ŸŒพ OATS - OpenAPI TypeScript Sync

Stop manually syncing your OpenAPI specs with TypeScript clients. OATS watches your backend API changes and automatically regenerates TypeScript clients in real-time.

npm version License: MIT Node.js Version

๐Ÿ”ฅ Features

  • ๐Ÿ”„ Real-time Sync: Automatically syncs OpenAPI changes to TypeScript clients
  • ๐Ÿš€ Zero Manual Steps: No more copy-paste workflows
  • ๐Ÿ”Œ Port Conflict Resolution: Automatically frees up ports when needed
  • ๐Ÿ“ฆ Multiple Generators: Support for any OpenAPI TypeScript generator
  • ๐Ÿ› ๏ธ Smart Defaults: Minimal configuration required
  • ๐Ÿ“Š Intelligent Watching: Only rebuilds when necessary
  • ๐Ÿ”— Auto-linking: Seamlessly links packages in monorepos
  • ๐ŸŽฏ Framework Agnostic: Works with React, Vue, Angular, etc.
  • โšก 45% Faster Sync: Optimized performance with incremental builds
  • ๐Ÿ” Smart Polling: Efficient polling for runtime-generated API specs
  • ๐Ÿง  Hash-based Caching: Skip unnecessary regeneration with SHA-256 comparison
  • ๐Ÿ“ˆ Performance Tracking: Optional timing display for each sync step

๐ŸŽฏ The Problem

You're building a TypeScript full-stack app with:

  • A backend (Node.js or Python) that generates OpenAPI/Swagger specs
  • A TypeScript client generated from those specs
  • A frontend that uses the TypeScript client

Every time you change your backend API, you need to:

  • Wait for the backend to regenerate the OpenAPI spec
  • Manually copy it to your client generator
  • Run the generator
  • Build the client
  • Link it to your frontend
  • Restart your frontend

That's 6 manual steps for every API change! ๐Ÿ˜ฑ

โœจ The Solution: OATS

OATS automates this entire workflow. Just run:

npx @loopkitchen/oats start

Now when you change your backend API, OATS automatically:

  • โœ… Detects the OpenAPI spec change
  • โœ… Copies it to your client project
  • โœ… Runs your generator
  • โœ… Builds the client
  • โœ… Links it to your frontend
  • โœ… Your frontend hot-reloads with the new types!

๐ŸŒ Supported Technologies

Backend Frameworks

  • Node.js: Express, Fastify, NestJS, Koa, Hapi, Restify
  • Python: FastAPI, Flask, Django (with DRF)

Frontend Frameworks

  • React, Vue, Angular, Svelte, Next.js, Nuxt, Remix

TypeScript Client Generators

  • Custom generators (recommended)
  • @hey-api/openapi-ts
  • swagger-typescript-api
  • openapi-generator-cli

๐Ÿš€ Quick Start

1. Install OATS

# In your frontend project (or monorepo root)
npm install --save-dev @loopkitchen/oats
# or
yarn add -D @loopkitchen/oats

2. Create Configuration

Create oats.config.json in your project root:

{
  "services": {
    "backend": {
      "path": "./backend",
      "port": 8000,
      "startCommand": "npm run dev",
      "apiSpec": {
        "path": "/api/openapi.json"  // Runtime endpoint (recommended)
      }
    },
    "client": {
      "path": "./api-client",
      "generator": "@hey-api/openapi-ts",
      "packageName": "@myorg/api-client"
    },
    "frontend": {
      "path": "./frontend",
      "port": 3000,
      "startCommand": "npm run dev"
    }
  }
}

Minimal config example (OATS uses smart defaults for everything else):

{
  "services": {
    "backend": {
      "path": "./backend",
      "startCommand": "npm run dev",
      "apiSpec": { "path": "/api/openapi.json" }
    },
    "client": {
      "path": "./api-client",
      "generator": "@hey-api/openapi-ts"
    }
  }
}

Note: Frontend configuration is optional! If you're running @loopkitchen/oats from your frontend project, it will just sync the backend and client without starting another frontend server.

Why port and startCommand are required for frontend

When you do configure a frontend service, both port and startCommand are required because:

  • Different frameworks use different default ports (React: 3000, Vite: 5173, Angular: 4200)
  • Different frameworks use different start commands (npm start, yarn dev, ng serve)
  • This ensures OATS knows exactly how to start and monitor your frontend

3. Add Script to package.json

{
  "scripts": {
    "dev": "vite",
    "dev:oats": "@loopkitchen/oats start"    // Add this
  }
}

4. Start Development

yarn dev:oats

That's it! Your entire stack is now running with automatic API synchronization.

๐Ÿ“ฆ Installation

# npm
npm install --save-dev @loopkitchen/oats

# yarn
yarn add -D @loopkitchen/oats

# pnpm
pnpm add -D @loopkitchen/oats

๐ŸŽจ Features

๐Ÿง  Smart Change Detection

OATS uses intelligent comparison algorithms to detect meaningful changes in your OpenAPI specs:

  • โœ… New endpoints or schemas
  • โœ… Modified request/response types
  • โœ… Changed authentication requirements
  • โŒ Ignores formatting or property reordering

๐Ÿ”„ Complete Automation

  • Watches your OpenAPI/Swagger files
  • Detects meaningful changes
  • Copies swagger.json to client directory
  • Generates TypeScript clients
  • Builds the client package
  • Links to your frontend projects
  • Triggers frontend hot-reload via HMR

๐ŸŽฏ Developer Experience

  • Port-based service detection - More reliable than log parsing
  • Automatic port conflict resolution - Kills conflicting processes
  • Colored logs for easy tracking
  • Clear change reporting - know exactly what changed
  • Error recovery - automatic retry with exponential backoff
  • Concurrent sync prevention - No duplicate operations
  • Desktop notifications (optional)

๐Ÿ”ง Flexible Configuration

Works with any OpenAPI client generator:

  • @hey-api/openapi-ts
  • swagger-typescript-api
  • openapi-generator-cli
  • Custom generators

๐Ÿ“‹ Configuration

Complete Configuration Reference

{
  "services": {
    "backend": {
      "path": "../backend",           // Path to backend (relative or absolute)
      "port": 4000,                   // Backend dev server port (optional)
      "startCommand": "yarn dev",     // Command to start backend
      "runtime": "node",              // Runtime: "node" (default) or "python"
      "python": {                     // Python-specific config (only if runtime is "python")
        "virtualEnv": "venv",         // Virtual environment directory
        "packageManager": "pip",      // Package manager: "pip", "poetry", or "pipenv"
        "executable": "python"        // Python executable (default: "python")
      },
      "apiSpec": {
        "path": "src/swagger.json"    // Path to OpenAPI spec (relative to backend)
      }
    },
    "client": {
      "path": "../api-client",        // Path to TypeScript client project
      "packageName": "@myorg/api",    // NPM package name of the client
      "generator": "custom",           // Generator type (see below)
      "generateCommand": "yarn generate",  // Command to generate client
      "buildCommand": "yarn build",        // Command to build client
      "linkCommand": "yarn link"           // Command to link for local dev
    },
    "frontend": {                      // OPTIONAL - only if you want @loopkitchen/oats to start it
      "path": ".",                    // Path to frontend
      "port": 5173,                   // REQUIRED - Must match your dev server port
      "startCommand": "yarn dev",     // REQUIRED - Your dev server command
      "packageLinkCommand": "yarn link"  // Command to link packages
    }
  },
  "sync": {                           // OPTIONAL - defaults shown below
    "strategy": "smart",             // "smart" or "always" - smart skips if no changes
    "debounceMs": 1000,              // Wait time before regenerating (ms)
    "autoLink": true,                // Automatically link packages after generation
    "notifications": false,          // Desktop notifications for sync events
    "retryAttempts": 3,              // Retry failed operations
    "retryDelayMs": 2000,            // Delay between retries (ms)
    "runInitialGeneration": false,   // Generate client on startup
    "ignore": ["**/node_modules/**"] // Paths to ignore in file watching
  },
  "log": {                           // OPTIONAL - logging configuration
    "level": "info",                // Log level: debug, info, warn, error
    "colors": true,                 // Use colored output
    "timestamps": false,            // Show timestamps in logs
    "showServiceOutput": true,      // Show backend/frontend console output
    "quiet": false,                 // Quiet mode - only essential messages
    "file": "./oats.log"           // Optional log file path
  }
}

Port Conflict Handling

OATS automatically handles port conflicts by default. When a port is already in use:

  • Detects the conflicting process
  • Kills the process to free the port
  • Starts your service on the freed port

To disable automatic port killing:

{
  "sync": {
    "autoKillConflictingPorts": false  // Default: true
  }
}

Performance Options

Enable performance tracking and optimizations:

{
  "sync": {
    "showStepDurations": true,    // Show timing for each sync step
    "pollingInterval": 3000       // Polling interval for runtime specs (ms)
  }
}
  • showStepDurations: Display how long each step takes (detection, generation, build, linking)
  • pollingInterval: For runtime API specs (like FastAPI), how often to check for changes (default: 5000ms)

Python Backend Notes

For Python backends like FastAPI that generate OpenAPI specs at runtime:

  • Use runtime endpoints for the API spec path (recommended)
  • OATS will fetch the spec from the running server
  • Make sure your backend is configured to expose the OpenAPI spec

Example for FastAPI:

{
  "apiSpec": {
    "path": "/openapi.json"  // Fetched from http://localhost:8000/openapi.json
  }
}

Minimal Configuration

If you're running @loopkitchen/oats from your frontend project, here's the minimal config:

{
  "services": {
    "backend": {
      "path": "../backend",
      "startCommand": "yarn dev",
      "apiSpec": {
        "path": "src/swagger.json"
      }
    },
    "client": {
      "path": "../api-client",
      "packageName": "@myorg/api-client",
      "generator": "custom",
      "generateCommand": "yarn generate",
      "buildCommand": "yarn build"
    }
  }
}

Generator Types

{
  "client": {
    "generator": "custom",
    "generateCommand": "yarn generate",  // Your existing generate command
    "buildCommand": "yarn build"
  }
}

Using @hey-api/openapi-ts

{
  "client": {
    "generator": "@hey-api/openapi-ts",
    "generatorConfig": {
      "input": "./swagger.json",
      "output": "./src",
      "client": "axios"
    }
  }
}

๐Ÿ› ๏ธ CLI Commands

@loopkitchen/oats start

Start all services with automatic synchronization.

@loopkitchen/oats start [options]

Options:
  --init-gen        Run initial client generation on startup
  -c, --config      Path to config file (default: oats.config.json)
  --quiet           Quiet mode - only show essential messages
  --no-colors       Disable colored output

Examples:

# Start with default config
@loopkitchen/oats start

# Generate client before starting (useful for first run)
@loopkitchen/oats start --init-gen

# Use custom config file
@loopkitchen/oats start --config my-oats.config.json

# Quiet mode - only @loopkitchen/oats messages, no service output
@loopkitchen/oats start --quiet

# Disable colors
@loopkitchen/oats start --no-colors

@loopkitchen/oats init

Interactively create a configuration file.

@loopkitchen/oats init [options]

Options:
  -f, --force       Overwrite existing configuration
  -y, --yes         Use defaults without prompting

@loopkitchen/oats validate

Check if your configuration is valid.

@loopkitchen/oats validate [options]

Options:
  -c, --config      Path to config file

@loopkitchen/oats detect

Auto-detect your project structure and create config.

@loopkitchen/oats detect

Note: This will scan your project and try to find:

  • Backend with OpenAPI/Swagger specs
  • TypeScript client projects
  • Frontend applications

๐Ÿ“š Real-World Examples

Example 1: FastAPI (Python) + React + @hey-api/openapi-ts

Project Structure:

my-project/
โ”œโ”€โ”€ backend/          # FastAPI backend
โ”œโ”€โ”€ api-client/       # Generated TypeScript client
โ””โ”€โ”€ frontend/         # React app

oats.config.json:

{
  "services": {
    "backend": {
      "path": "../backend",
      "port": 8000,
      "runtime": "python",
      "python": {
        "virtualEnv": "venv"
      },
      "startCommand": "source venv/bin/activate && uvicorn main:app --reload --port 8000",
      "apiSpec": {
        "path": "runtime:/openapi.json"  // FastAPI generates at runtime
      }
    },
    "client": {
      "path": "../api-client",
      "packageName": "@myapp/api-client",
      "generator": "@hey-api/openapi-ts",
      "generateCommand": "npm run generate",
      "buildCommand": "npm run build"
    },
    "frontend": {
      "path": "./",
      "port": 3000,
      "startCommand": "npm start"
    }
  }
}

Example 2: Express + React + Custom Generator

Project Structure:

my-project/
โ”œโ”€โ”€ backend/          # Express API
โ”œโ”€โ”€ api-client/       # Generated TypeScript client
โ””โ”€โ”€ frontend/         # React app

oats.config.json:

{
  "services": {
    "backend": {
      "path": "../backend",
      "port": 4000,
      "startCommand": "npm run dev",
      "apiSpec": {
        "path": "src/swagger.json"
      }
    },
    "client": {
      "path": "../api-client",
      "packageName": "@myapp/api-client",
      "generator": "custom",
      "generateCommand": "npm run generate",
      "buildCommand": "npm run build",
      "linkCommand": "npm link"
    },
    "frontend": {
      "path": ".",
      "port": 3000,
      "startCommand": "npm start",
      "packageLinkCommand": "npm link"
    }
  }
}

Example 2: NestJS + Next.js + Monorepo

Project Structure:

my-monorepo/
โ”œโ”€โ”€ apps/
โ”‚   โ”œโ”€โ”€ api/          # NestJS backend
โ”‚   โ””โ”€โ”€ web/          # Next.js frontend
โ””โ”€โ”€ packages/
    โ””โ”€โ”€ api-client/   # Generated client

oats.config.json:

{
  "services": {
    "backend": {
      "path": "./apps/api",
      "port": 3333,
      "startCommand": "nx serve api",
      "apiSpec": {
        "path": "swagger.json"
      }
    },
    "client": {
      "path": "./packages/api-client",
      "packageName": "@myapp/api-client",
      "generator": "custom",
      "generateCommand": "yarn openapi-ts",
      "buildCommand": "yarn build"
    },
    "frontend": {
      "path": "./apps/web",
      "port": 4200,
      "startCommand": "nx serve web"
    }
  }
}

Example 3: Microservices with Multiple APIs

{
  "services": {
    "backend": {
      "path": "../services/main-api",
      "port": 4000,
      "startCommand": "docker-compose up api",
      "apiSpec": {
        "path": "docs/openapi.yaml"
      }
    },
    "client": {
      "path": "../packages/main-api-client",
      "packageName": "@company/main-api",
      "generator": "custom",
      "generateCommand": "yarn codegen",
      "buildCommand": "yarn tsc"
    },
    "frontend": {
      "path": "../apps/dashboard",
      "port": 8080,
      "startCommand": "yarn serve"
    }
  },
  "sync": {
    "debounceMs": 2000,  // Longer debounce for larger APIs
    "retryAttempts": 5
  }
}

๐Ÿค” Common Issues & Solutions

Issue: "Port already in use"

Solution: OATS now automatically kills processes using required ports! If you still have issues:

{
  "services": {
    "backend": { "port": 4001 },    // Change to available port
    "frontend": { "port": 5174 }    // Change to available port
  }
}

Issue: "Client not updating in frontend"

Solution: OATS now includes Vite HMR integration! Check that:

  • Your OpenAPI spec path is correct
  • The generator command works when run manually
  • The package is properly linked (yarn link or npm link)
  • For Vite users: Add to your vite.config.ts:
export default defineConfig({
  optimizeDeps: {
    exclude: ['@yourorg/api-client'] // Exclude linked packages
  }
})

Issue: "Command not found: @loopkitchen/oats"

Solution: Use npx or add to package.json scripts:

# Direct usage
npx @loopkitchen/oats start

# Or add to package.json
"scripts": {
  "dev:sync": "@loopkitchen/oats start"
}

๐Ÿค How OATS Works

1. Start: OATS starts your backend, frontend, and watches for changes
   โ†“
2. Port Detection: Uses port-based detection to know when services are ready
   โ†“
3. Watch: File watcher monitors your OpenAPI spec file
   โ†“
4. Detect: When spec changes, OATS compares with previous version
   โ†“
5. Copy: Copies swagger.json to client directory for local generation
   โ†“
6. Generate: Run your generator command with local spec
   โ†“
7. Build: Build the TypeScript client package
   โ†“
8. Link: Ensure client is linked to frontend (yarn/npm link)
   โ†“
9. HMR Trigger: Touch .oats-sync file to trigger Vite hot-reload
   โ†“
10. Reload: Frontend hot-reloads with new types

Robust Architecture:

  • โšก Port-based service detection (no flaky log parsing)
  • ๐Ÿ”’ Concurrent sync prevention with operation locking
  • ๐Ÿ”„ Automatic retry with exponential backoff (2s, 4s, 8s)
  • ๐Ÿงน Automatic port conflict resolution
  • ๐Ÿ“ Local swagger.json copy for reliable generation
  • ๐Ÿ”ฅ Vite HMR integration for instant updates

Smart Detection: OATS uses intelligent comparison to avoid unnecessary regeneration:

  • โœ… Detects real API changes (new endpoints, changed types)
  • โŒ Ignores formatting changes or timestamp updates
  • โœ… Uses file hashing for quick comparison

๐ŸŒŸ Why OATS?

Without OATS ๐Ÿ˜ซ

# Make API change
# Wait...
# Manually copy swagger.json
cp ../backend/swagger.json ../client/

# Generate client
cd ../client && yarn generate

# Build client
yarn build

# Link to frontend
yarn link
cd ../frontend && yarn link "@myorg/api-client"

# Restart frontend
# Repeat for every API change... ๐Ÿ”„

With OATS ๐Ÿš€

# Just run once
yarn dev:oats

# Make API changes
# Everything syncs automatically! โœจ

Feature Comparison

FeatureManual ProcessBuild ScriptsOATS
Automatic syncโŒโŒโœ…
Smart detectionโŒโŒโœ…
Zero configโŒโŒโœ…
Hot reloadโŒPartialโœ…
Error recoveryโŒโŒโœ…
Multi-serviceโŒComplexโœ…

๐Ÿ›ก๏ธ Reliability & Performance

OATS is built with production reliability in mind:

Robust Service Management

  • Port-based detection: Services are detected by port binding, not log parsing
  • Automatic port cleanup: Kills existing processes on required ports before starting
  • Health monitoring: Continuous port checking to ensure services stay alive
  • Graceful shutdown: Proper cleanup of all processes and resources

Intelligent Sync Engine

  • Concurrent operation prevention: Lock mechanism prevents duplicate syncs
  • Automatic retry: Failed operations retry with exponential backoff
  • Debounced file watching: Prevents rapid regeneration from multiple saves
  • Smart change detection: Only syncs when meaningful API changes occur

Error Recovery

  • Service crash recovery: Emits events when services crash after startup
  • Malformed spec handling: Graceful error messages for invalid swagger.json
  • Network resilience: Handles temporary network issues during generation
  • Resource cleanup: Proper cleanup of intervals, watchers, and child processes

Performance Optimizations

  • Minimal file I/O: Efficient file watching with chokidar
  • Smart caching: Change detection uses efficient hashing
  • Parallel operations: Services start concurrently when possible
  • Memory efficient: Proper event listener management

๐Ÿค Contributing

We welcome contributions! Please see our Contributing Guide for details.

# Clone the repository
git clone https://github.com/loopkitchen/oats.git

# Install dependencies
npm install

# Run tests
npm test

# Start development
npm run dev

๐Ÿ“„ License

MIT ยฉ Hari Shekhar

๐Ÿ™ Acknowledgments

OATS is inspired by the challenges faced by developers working with OpenAPI specifications and TypeScript in modern microservices architectures. Special thanks to:

  • The OpenAPI community
  • TypeScript ecosystem contributors
  • Developers who value their time and sanity

Made with โค๏ธ and ๐ŸŒพ for developers who deserve better tooling

GitHub โ€ข npm โ€ข Issues โ€ข Discussions

Keywords

oats

FAQs

Package last updated on 01 Jul 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with โšก๏ธ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.