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

clientforge

v1.0.0

Published

Front-end SDK generator from OpenAPI specifications — supports Angular, Vue, and React

Downloads

193

Readme

ClientForge

Front-end SDK generator from OpenAPI specifications — supports Angular, Vue, and React.

ClientForge reads your OpenAPI/Swagger document and generates fully-typed TypeScript models, HTTP services, and optional utilities (hooks, validators) for your front-end framework of choice.

License: MIT Node.js TypeScript


Table of Contents


Features

  • Multi-framework — generate SDKs for Angular, Vue, and React from a single config.
  • Multi-spec — Swagger 2.0, OpenAPI 3.0.x, and OpenAPI 3.1.x.
  • Type-safe — fully-typed TypeScript models, enums, unions, intersections, records, and generics.
  • Validators — optional validation functions generated alongside models for all targets.
  • Configurable output — choose model style (interface / type / class / auto), enum style (enum / union), date type, binary type, and more.
  • Smart clean — only removes auto-generated files; preserves HTTP clients, user-created models, and custom code.
  • Region preservation — regenerate only auto-generated regions; keep your custom code intact.
  • Diagnostics — structured warnings and errors during normalization and generation.
  • Extensible — plug-in architecture for targets via the TargetGenerator interface.
  • Zero runtime dependencies — generated code relies only on your framework and HTTP client.

Quick Start

# 1. Install
npm install -D clientforge

# 2. Initialize a config file
npx clientforge init

# 3. Edit clientforge.config.json — set your OpenAPI source and targets

# 4. Generate
npx clientforge generate

Installation

As a dev dependency (recommended)

npm install -D clientforge
# or
pnpm add -D clientforge
# or
yarn add -D clientforge

Then use it via npx, pnpm, or an npm script:

npx clientforge generate
pnpm clientforge generate

Global install

npm install -g clientforge

After a global install, both clientforge and the short alias cf are available:

clientforge generate
cf generate
cf -g          # shortcut for generate

npm scripts

Add a script to your package.json:

{
  "scripts": {
    "generate:api": "clientforge generate"
  }
}

CLI Commands

| Command | Alias | Description | | ---------------------- | ------ | ------------------------------------------------------------------------------ | | clientforge init | | Create a clientforge.config.json with sensible defaults | | clientforge generate | cf g | Generate models and services from the configured OpenAPI source | | clientforge validate | | Validate configuration, document access, version, and target setup | | clientforge inspect | | Print a summary of the parsed contract (schemas, operations, groups, warnings) |


Configuration

Running clientforge init creates a clientforge.config.json at the project root:

{
  "input": {
    "source": "http://localhost:5000/swagger/v1/swagger.json",
    "resolveRefs": true,
  },
  "output": {
    "rootDir": "./src/api-generated",
    "clean": false,
    "format": true,
  },
  "naming": {
    "groupStrategy": "tag", // "first-segment" | "tag" | "operationId-prefix"
    "modelStyle": "auto", // "interface" | "type" | "class" | "auto"
    "enumStyle": "enum", // "enum" | "union"
    "dateType": "string", // "string" | "Date"
    "binaryType": "Blob", // "Blob" | "File" | "string"
    "typeOnlyImports": false,
  },
  "features": {
    "validators": false,
    "regionPreservation": true,
    "emitDiagnostics": true,
  },
  "targets": [
    {
      "name": "angular",
      "enabled": true,
      "outputDir": "./src/app/api",
      "httpClient": "angular-http-client",
      "generateTests": true,
    },
  ],
}

Configuration Reference

input

| Field | Type | Default | Description | | ------------- | --------- | ------- | ------------------------------------------------------------------------------------------ | | source | string | — | Required. URL or local path to an OpenAPI/Swagger document (.json, .yaml, .yml). | | resolveRefs | boolean | true | Resolve $ref pointers before normalization. |

output

| Field | Type | Default | Description | | --------- | --------- | ----------------------- | ----------------------------------------------------------------------------------------------- | | rootDir | string | "./src/api-generated" | Output root directory. | | clean | boolean | false | Remove auto-generated files before regenerating. Preserves HTTP clients and user-created files. | | format | boolean | true | Apply formatting to generated files. |

naming

| Field | Type | Default | Description | | ----------------- | --------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------- | | groupStrategy | string | "tag" | How operations are grouped into services: "first-segment", "tag", or "operationId-prefix". | | modelStyle | string | "auto" | Generated model form: "interface", "type", "class", or "auto" (classes for request bodies, interfaces for the rest). | | enumStyle | string | "enum" | "enum" for TypeScript enums, "union" for string literal unions. | | dateType | string | "string" | TypeScript type for date/date-time fields. | | binaryType | string | "Blob" | TypeScript type for binary fields. | | typeOnlyImports | boolean | false | Use import type syntax. |

features

| Field | Type | Default | Description | | -------------------- | --------- | ------- | ------------------------------------------------------------- | | validators | boolean | false | Generate validation functions alongside models. | | regionPreservation | boolean | true | Preserve user-written code outside of auto-generated regions. | | emitDiagnostics | boolean | true | Print diagnostic messages during generation. |

targets[]

| Field | Type | Default | Description | | ------------------ | --------- | ------- | ------------------------------------------------------------------------ | | name | string | — | "angular", "vue", or "react". | | enabled | boolean | — | Enable or disable this target. | | outputDir | string | — | Target-specific output directory. | | httpClient | string | varies | HTTP client to use (e.g. "angular-http-client", "axios", "fetch"). | | generateTests | boolean | false | Generate unit test stubs (Angular). | | generateHooks | boolean | false | Generate query/mutation hooks (React). | | queryLibrary | string | — | Query library for hooks (e.g. "tanstack-query"). | | basePathVariable | string | — | Variable name for the API base URL (e.g. "environment.apiUrlBase"). | | basePathImport | string | — | Import path for the base URL variable. |


Target Reference

Angular

Generates Angular services with HttpClient, typed Observable<T> responses, @Injectable decorators, and a reusable base HTTP service.

{
  "name": "angular",
  "enabled": true,
  "outputDir": "./src/app/api",
  "httpClient": "angular-http-client",
  "generateTests": true, // generate .spec.ts stubs
}

Generated structure:

src/app/api/
├── models/
│   ├── user.model.ts
│   ├── order.model.ts
│   └── index.ts
├── services/
│   ├── base-api.service.ts
│   ├── users.service.ts
│   ├── users.service.spec.ts
│   └── orders.service.ts

Vue

Generates pure TypeScript services for Vue with a configurable HTTP client (axios or fetch).

{
  "name": "vue",
  "enabled": true,
  "outputDir": "./src/api",
  "httpClient": "axios",
}

Generated structure:

src/api/
├── models/
│   ├── user.model.ts
│   └── index.ts
├── http/
│   └── http-client.ts
└── services/
    ├── users.service.ts
    └── orders.service.ts

React

Generates async client functions and optional TanStack Query hooks.

{
  "name": "react",
  "enabled": true,
  "outputDir": "./src/api",
  "httpClient": "fetch",
  "generateHooks": true,
  "queryLibrary": "tanstack-query",
}

Generated structure:

src/api/
├── models/
│   ├── user.model.ts
│   └── index.ts
├── http/
│   └── http-client.ts
├── clients/
│   ├── users-client.ts
│   └── orders-client.ts
└── hooks/
    ├── use-users.hook.ts
    └── use-orders.hook.ts

Architecture

ClientForge follows a pipeline architecture that cleanly separates parsing, normalization, and code generation:

┌─────────────────────────────────────────────────────────┐
│                        CLI Layer                        │
│  init · generate · validate · inspect                   │
└────────────────────────┬────────────────────────────────┘
                         │
┌────────────────────────▼────────────────────────────────┐
│                    Core Pipeline                        │
│                                                         │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  │
│  │ Config Loader │  │ Doc Loader   │  │ Version      │  │
│  │              │  │ (JSON/YAML/  │  │ Detector     │  │
│  │              │  │  URL/local)  │  │              │  │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘  │
│         │                 │                 │           │
│         │          ┌──────▼───────┐         │           │
│         │          │ Ref Resolver │◄────────┘           │
│         │          └──────┬───────┘                     │
│         │                 │                             │
│         │    ┌────────────▼────────────┐                │
│         │    │    Spec Normalizer      │                │
│         │    │  (Swagger 2 / OA 3.0 / │                │
│         │    │   OA 3.1 → unified IR) │                │
│         │    └────────────┬────────────┘                │
│         │                 │                             │
│  ┌──────▼─────────────────▼──────────────────────────┐  │
│  │          Intermediate Representation (IR)         │  │
│  │  ApiContract · SchemaDefinition · TypeDefinition  │  │
│  │  OperationDefinition · ParameterDefinition · ...  │  │
│  └───────────────────────┬───────────────────────────┘  │
│                          │                              │
│  ┌───────────────────────▼───────────────────────────┐  │
│  │           Generation Pipeline                     │  │
│  │  NamingStrategy · NameConflictResolver            │  │
│  │                                                   │  │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────────┐    │  │
│  │  │ Angular  │  │   Vue    │  │    React     │    │  │
│  │  │ Target   │  │  Target  │  │   Target     │    │  │
│  │  └────┬─────┘  └────┬─────┘  └─────┬────────┘    │  │
│  │       └──────────────┼──────────────┘             │  │
│  └──────────────────────┼────────────────────────────┘  │
│                         │                               │
│  ┌──────────────────────▼────────────────────────────┐  │
│  │           File Writer + Region Preserver          │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘

Key Design Principles

  1. Intermediate Representation (IR) — The OpenAPI document is never used directly by generators. It is first normalized into a framework-agnostic IR (ApiContract), regardless of whether the input is Swagger 2.0, OpenAPI 3.0, or 3.1.

  2. Target-based generation — Each framework (Angular, Vue, React) is a self-contained TargetGenerator plugin. New targets can be added by implementing a single interface.

  3. Naming strategy — A centralized NamingStrategy drives all file names, class names, method names, and conflict resolution. Custom naming strategies can be plugged in.

  4. Region preservation — Generated files can use /* <auto-generated NAME> */ markers to protect hand-written code from being overwritten on regeneration.

  5. Diagnostics — Issues found during parsing, normalization, and generation are collected as structured DiagnosticMessage objects rather than throwing errors.

Project Structure

src/
├── cli/                      # CLI entry point and commands
│   ├── index.ts              # Commander setup
│   └── commands/
│       ├── init.command.ts
│       ├── generate.command.ts
│       ├── validate.command.ts
│       └── inspect.command.ts
├── core/
│   ├── config/               # Config loading, defaults, validation, types
│   ├── diagnostics/          # Diagnostic collector and types
│   ├── document/             # Document loader, version detector, ref resolver
│   ├── ir/                   # Intermediate Representation types
│   ├── naming/               # Naming strategy, conflict resolution, reserved words
│   ├── normalize/            # Swagger 2 / OA 3.0 / OA 3.1 normalizers + type resolver
│   ├── pipeline/             # Generation context, pipeline orchestrator, result types
│   └── render/               # File artifact, writer, region preserver
├── plugins/
│   └── target/               # TargetGenerator interface
├── shared/                   # Shared renderers (type-renderer, service-helpers)
├── targets/
│   ├── angular/              # Angular target + renderers
│   ├── vue/                  # Vue target + renderers
│   └── react/                # React target + renderers
└── utils/                    # Path and string utilities

Adding a New Target

  1. Create a new directory under src/targets/<name>/.
  2. Implement the TargetGenerator interface:
import type { FileArtifact } from "../../core/render/file-artifact.js";
import type { GenerationContext } from "../../core/pipeline/generation-context.js";
import type { TargetGenerator } from "../../plugins/target/target.interface.js";

export class MyFrameworkTarget implements TargetGenerator {
  readonly name = "my-framework";

  generate(context: GenerationContext): FileArtifact[] {
    // Access context.contract (IR), context.config, context.naming, etc.
    // Return an array of FileArtifact objects to be written to disk.
    return [];
  }
}
  1. Register the target in the pipeline's TARGET_REGISTRY in src/core/pipeline/generation-pipeline.ts.

Programmatic API

ClientForge can be used as a library in addition to the CLI:

import {
  loadConfig,
  loadDocument,
  detectVersion,
  normalizeDocument,
  runPipeline,
  writeArtifacts,
} from "clientforge";

// 1. Load config (reads clientforge.config.json)
const config = loadConfig();

// 2. Load the OpenAPI document
const document = await loadDocument(config.input.source);

// 3. Detect spec version
const version = detectVersion(document); // "swagger2" | "openapi3.0" | "openapi3.1"

// 4. Normalize to the Intermediate Representation
const contract = normalizeDocument(document);

// 5. Run the generation pipeline (without writing to disk)
const result = runPipeline(contract, config, { write: false });

// 6. Inspect artifacts
for (const artifact of result.artifacts) {
  console.log(artifact.path, artifact.kind);
}

// 7. Optionally write to disk
writeArtifacts(result.artifacts, process.cwd());

Exported Types

All IR types are exported for custom integrations:

  • ApiContract, ApiServer, OpenApiVersion
  • OperationDefinition, ParameterDefinition, RequestBodyDefinition, ResponseDefinition
  • SchemaDefinition, TypeDefinition, PropertyDefinition
  • ClientForgeConfig, TargetConfig, NamingConfig
  • FileArtifact, GenerationContext, GenerationResult
  • NamingStrategy, DefaultNamingStrategy

Region Preservation

When features.regionPreservation is enabled, ClientForge uses auto-generated markers to protect your custom code:

/* <auto-generated imports> */
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
/* </auto-generated imports> */

// Your custom imports here — these are preserved on regeneration

/* <auto-generated methods> */
getUsers(): Observable<User[]> {
  return this.http.get<User[]>(`${this.baseUrl}/users`);
}
/* </auto-generated methods> */

// Your custom methods here — these are preserved on regeneration

On subsequent runs, only content inside the <auto-generated> markers is updated. Everything outside is preserved.


OpenAPI Support

| Feature | Swagger 2.0 | OpenAPI 3.0 | OpenAPI 3.1 | | ------------------------ | :---------: | :---------: | :---------: | | JSON input | ✅ | ✅ | ✅ | | YAML input | ✅ | ✅ | ✅ | | URL source | ✅ | ✅ | ✅ | | Local file source | ✅ | ✅ | ✅ | | $ref resolution | ✅ | ✅ | ✅ | | allOf | ✅ | ✅ | ✅ | | oneOf | — | ✅ | ✅ | | anyOf | — | ✅ | ✅ | | discriminator | — | ✅ | ✅ | | nullable | — | ✅ | ✅ | | additionalProperties | ✅ | ✅ | ✅ | | readOnly / writeOnly | ✅ | ✅ | ✅ | | Security schemes | ✅ | ✅ | ✅ | | Multiple servers | — | ✅ | ✅ | | multipart/form-data | ✅ | ✅ | ✅ |


Contributing

Contributions are welcome! Here's how to get started:

Prerequisites

  • Node.js >= 18
  • npm, pnpm, or yarn

Setup

git clone https://github.com/your-username/clientforge.git
cd clientforge
npm install

Development

# Build
npm run build

# Watch mode
npm run dev

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Run tests with coverage
npm run test:coverage

# Type-check
npm run lint

Test Structure

test/
├── fixtures/openapi/       # OpenAPI spec fixtures for tests
├── unit/                   # Unit tests for individual modules
│   ├── naming-strategy.test.ts
│   ├── type-resolver.test.ts
│   ├── normalizers.test.ts
│   ├── region-preserver.test.ts
│   └── ...
└── integration/
    └── pipeline.test.ts    # End-to-end pipeline integration tests

Guidelines

  1. Write tests. Every new feature or bug fix should include tests.
  2. Use the IR. Never access the raw OpenAPI document in generators — always work through the Intermediate Representation.
  3. No hardcoded opinions. Generated base services should not embed authentication, routing, or app-specific logic.
  4. Follow existing patterns. Look at the Angular/Vue/React target implementations for reference.

License

MIT