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

@techspokes/typescript-wsdl-client

v0.9.7

Published

TypeScript WSDL → SOAP client generator with full xs:attribute support, complex types, sequences, inheritance, and namespace-collision merging.

Readme

TypeScript WSDL Client

License: MIT CI npm version npm downloads GitHub Stars GitHub Forks TechSpokes Org Sponsor

Transform complex WSDL/XSD definitions into type-safe TypeScript SOAP clients with optional OpenAPI 3.1 specs and production-ready REST gateways.

Use This If You Need...

  • TypeScript-first SOAP clients — Strongly typed, ergonomic client generation from WSDL
  • OpenAPI 3.1 specs — Generate REST API documentation that mirrors your TypeScript types
  • REST gateway over SOAP — Production-ready Fastify handlers with automatic request/response transformation
  • CI-friendly determinism — Stable, diff-friendly output for safe regeneration in version control
  • Predictable modeling — Flattened attributes, consistent $value convention, inheritance resolution

Vendor: TechSpokes · Maintainer: Serge Liatko (@sergeliatko)


Table of Contents


Installation

npm install --save-dev @techspokes/typescript-wsdl-client
npm install soap   # Runtime dependency for SOAP calls

Requirements:

  • Node.js 20.0.0 or later
  • soap package (runtime dependency for generated clients)

Quick Start (60 Seconds)

Generate a complete SOAP-to-REST stack in one command:

# Generate client, OpenAPI spec, gateway, and runnable app
npx wsdl-tsc pipeline \
  --wsdl-source examples/minimal/weather.wsdl \
  --client-dir ./tmp/client \
  --openapi-file ./tmp/openapi.json \
  --gateway-dir ./tmp/gateway \
  --gateway-service-name weather \
  --gateway-version-prefix v1 \
  --generate-app

Start the server:

cd tmp/app
cp .env.example .env
# Edit .env to set WSDL_SOURCE if needed
npx tsx server.js

Test it:

# Health check
curl http://localhost:3000/health

# Get OpenAPI spec
curl http://localhost:3000/openapi.json | jq .

# Call a SOAP operation via REST
curl -X POST http://localhost:3000/get-weather-information \
  -H "Content-Type: application/json" \
  -d '{}'

What just happened?

  1. Parsed the WSDL and compiled types
  2. Generated a TypeScript SOAP client with full type safety
  3. Created an OpenAPI 3.1 spec matching the client types
  4. Built Fastify gateway handlers that call SOAP and return JSON
  5. Created a runnable Express-style app with health/OpenAPI endpoints

What You Get (Outputs)

TypeScript SOAP Client

client/
├── client.ts      # Strongly-typed SOAP client wrapper with methods
├── types.ts       # Flattened interfaces, type aliases, and enums
├── utils.ts       # Runtime metadata for JSON→SOAP conversion
└── catalog.json   # Compiled schema representation (reusable)

Example usage:

import { Weather } from './client/client.js';

const client = new Weather({
  source: 'https://example.com/weather.wsdl',
});

const result = await client.GetCityWeatherByZIP({ ZIP: '10001' });
console.log(result.GetCityWeatherByZIPResult);

OpenAPI 3.1 Specification

openapi.json   # or .yaml — Complete REST API documentation
  • Mirrors exact TypeScript type structure
  • All responses wrapped in standard envelope (status, message, data, error)
  • Deterministic ordering for version control
  • Validates with swagger-parser by default

Fastify REST Gateway

gateway/
├── schemas/
│   ├── models/         # JSON Schema components with URN IDs
│   └── operations/     # Request/response validation schemas
├── routes/             # Route handlers (fully implemented)
├── schemas.ts          # Schema registration module
├── routes.ts           # Route aggregator
├── runtime.ts          # Envelope builders, error handlers
└── plugin.ts           # Fastify plugin wrapper

Example integration:

import Fastify from 'fastify';
import weatherGateway from './gateway/plugin.js';
import { Weather } from './client/client.js';

const app = Fastify({ logger: true });
const client = new Weather({ source: 'weather.wsdl' });

await app.register(weatherGateway, { client });
await app.listen({ port: 3000 });

Runnable Application

app/
├── server.js       # Main entry point
├── config.js       # Configuration with env var support
├── .env.example    # Environment template
├── README.md       # Usage instructions
└── openapi.json    # OpenAPI spec (when --openapi-mode=copy)

Standard Response Envelope

All gateway responses follow this structure:

Success:

{
  "status": "SUCCESS",
  "message": null,
  "data": { /* SOAP response */ },
  "error": null
}

Error:

{
  "status": "ERROR",
  "message": "Request validation failed",
  "data": null,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": { /* validation errors */ }
  }
}

Core Concepts

Flattening and $value

Attributes and elements become peer properties — No nested wrapper noise:

<!-- WSDL -->
<xs:complexType name="Price">
  <xs:simpleContent>
    <xs:extension base="xs:decimal">
      <xs:attribute name="currency" type="xs:string"/>
    </xs:extension>
  </xs:simpleContent>
</xs:complexType>
// Generated TypeScript
interface Price {
  currency?: string;  // attribute
  $value: string;     // text content (decimal mapped to string by default)
}

Primitive Mapping Defaults (String-First Safety)

Prevents precision loss and parsing errors at the cost of convenience:

| XSD Type | Default | Override Options | When to Override | |---------------|----------|--------------------|----------------------------------------| | xs:long | string | number, bigint | Use number if values fit JS range | | xs:integer | string | number | Use string for arbitrary-size ints | | xs:decimal | string | number | Use string for precise decimals | | xs:dateTime | string | Date | Use Date if runtime parsing is okay |

Override with flags:

  • --client-int64-as number
  • --client-decimal-as string
  • --client-date-as Date

Deterministic Generation

All output is stable and diff-friendly for CI/CD:

  • ✅ Sorted type declarations
  • ✅ Sorted OpenAPI paths, schemas, parameters
  • ✅ Sorted JSON schema keys
  • ✅ Stable alias resolution
  • ✅ Consistent ordering of imports

Regenerate safely without spurious diffs in version control.

Catalog as Intermediate Artifact

catalog.json is the compiled representation of your WSDL:

  • Debuggable — Inspect types, operations, and metadata as JSON
  • Cacheable — Reuse across client/OpenAPI/gateway generation
  • Co-located — Automatically placed alongside generated output

Common locations:

  • client command: {client-dir}/catalog.json
  • openapi command: {openapi-dir}/catalog.json
  • pipeline command: First available output directory

Common Workflows

Which Command Should I Run?

| I Want... | Use Command | Example | |-----------------------------------------------|--------------|----------------------------------------------------------------------------------------------------------------------| | Everything (client + OpenAPI + gateway) | pipeline | npx wsdl-tsc pipeline --wsdl-source service.wsdl --client-dir ./client --openapi-file ./api.json --gateway-dir ./gateway --gateway-service-name svc --gateway-version-prefix v1 | | Only a TypeScript SOAP client | client | npx wsdl-tsc client --wsdl-source service.wsdl --client-dir ./client | | Only OpenAPI spec (for docs or SDKs) | openapi | npx wsdl-tsc openapi --wsdl-source service.wsdl --openapi-file ./api.json | | Only REST gateway (have OpenAPI already) | gateway | npx wsdl-tsc gateway --openapi-file ./api.json --client-dir ./client --gateway-dir ./gateway --gateway-service-name svc --gateway-version-prefix v1 | | Runnable server for testing | app | npx wsdl-tsc app --client-dir ./client --gateway-dir ./gateway --openapi-file ./api.json | | Debug/inspect WSDL compilation | compile | npx wsdl-tsc compile --wsdl-source service.wsdl --catalog-file ./catalog.json |

Workflow 1: Generate Everything (Recommended)

Use pipeline for complete stack generation:

npx wsdl-tsc pipeline \
  --wsdl-source examples/minimal/weather.wsdl \
  --client-dir ./src/services/weather \
  --openapi-file ./docs/weather-api.json \
  --gateway-dir ./src/gateway/weather \
  --gateway-service-name weather \
  --gateway-version-prefix v1

Output:

  • Client: ./src/services/weather/client.ts, types.ts, utils.ts, catalog.json
  • OpenAPI: ./docs/weather-api.json
  • Gateway: ./src/gateway/weather/ (routes, schemas, plugin)

Workflow 2: SOAP Client Only

Generate TypeScript client for direct SOAP integration:

npx wsdl-tsc client \
  --wsdl-source ./wsdl/Hotel.wsdl \
  --client-dir ./src/services/hotel

Usage:

import soap from 'soap';
import { Hotel } from './src/services/hotel/client.js';

const client = new Hotel({
  source: 'https://example.com/hotel.wsdl',
  security: new soap.WSSecurity('username', 'password'),
});

const result = await client.SearchAvailableRooms({
  checkIn: '2024-01-15',
  checkOut: '2024-01-20',
  guests: 2,
});

Workflow 3: OpenAPI for Documentation

Generate OpenAPI spec for API documentation or SDK generation:

npx wsdl-tsc openapi \
  --wsdl-source ./wsdl/Booking.wsdl \
  --openapi-file ./docs/booking-api.yaml \
  --openapi-format yaml \
  --openapi-title "Hotel Booking API" \
  --openapi-version "1.0.0" \
  --openapi-servers https://api.example.com/v1

Use the spec:

  • Import into Postman, Insomnia, or Swagger UI
  • Generate client SDKs with OpenAPI Generator
  • Share as REST API documentation

Workflow 4: REST Gateway Over SOAP

Build a REST API layer over legacy SOAP services:

# 1. Generate client + OpenAPI
npx wsdl-tsc pipeline \
  --wsdl-source ./wsdl/Legacy.wsdl \
  --client-dir ./src/services/legacy \
  --openapi-file ./docs/legacy-api.json

# 2. Generate gateway
npx wsdl-tsc gateway \
  --openapi-file ./docs/legacy-api.json \
  --client-dir ./src/services/legacy \
  --gateway-dir ./src/gateway/legacy \
  --gateway-service-name legacy \
  --gateway-version-prefix v1

Or in one command:

npx wsdl-tsc pipeline \
  --wsdl-source ./wsdl/Legacy.wsdl \
  --client-dir ./src/services/legacy \
  --openapi-file ./docs/legacy-api.json \
  --gateway-dir ./src/gateway/legacy \
  --gateway-service-name legacy \
  --gateway-version-prefix v1

Workflow 5: CI/CD Integration

Cache compiled catalog for faster multi-stage builds:

# Stage 1: Compile catalog (cacheable)
npx wsdl-tsc compile \
  --wsdl-source ./wsdl/Service.wsdl \
  --catalog-file ./build/service-catalog.json

# Stage 2: Generate client from catalog
npx wsdl-tsc client \
  --catalog-file ./build/service-catalog.json \
  --client-dir ./src/services/service

# Stage 3: Generate OpenAPI from catalog
npx wsdl-tsc openapi \
  --catalog-file ./build/service-catalog.json \
  --openapi-file ./docs/service-api.json

Workflow 6: Debugging Complex WSDL

Inspect compiled types and operations:

# Compile to catalog
npx wsdl-tsc compile \
  --wsdl-source ./wsdl/Complex.wsdl \
  --catalog-file ./debug/catalog.json

# Inspect types
cat ./debug/catalog.json | jq '.types'

# Inspect operations
cat ./debug/catalog.json | jq '.operations'

Command Reference

The tool provides six commands for different integration scenarios. Commands are listed in recommended order of use:

| Command | Purpose | Typical Use Case | |------------|----------------------------------------------------------------|-----------------------------------------------| | pipeline | Run full pipeline: client + OpenAPI + gateway (+ app optional) | CI/CD automation, complete stack generation (recommended) | | client | Generate TypeScript SOAP client from WSDL or catalog | Standard SOAP integration | | openapi | Generate OpenAPI 3.1 spec from WSDL or catalog | Documentation, REST proxies, API gateways | | gateway | Generate Fastify gateway with full handlers from OpenAPI spec | Production REST gateway with SOAP integration | | app | Generate runnable Fastify app from client + gateway + OpenAPI | Local testing, quick iteration, demos | | compile | Parse WSDL and emit catalog.json only | Debugging, inspection, or multi-stage builds (advanced) |


Command: pipeline (Recommended)

Purpose: Run the complete generation pipeline in a single pass: WSDL parsing → TypeScript client → OpenAPI spec → Fastify gateway (+ app optional).

When to use:

  • CI/CD automation
  • Complete stack generation
  • Ensuring all artifacts are generated from the same WSDL parse
  • One-command development workflows

Usage

npx wsdl-tsc pipeline \
  --wsdl-source <file|url> \
  [--catalog-file <path>] \
  [--client-dir <path>] \
  [--openapi-file <path>] \
  [--gateway-dir <path>] \
  [options]

Required Flags

| Flag | Description | |---------------------|----------------------------------------------------------------------| | --wsdl-source | Path or URL to WSDL file |

Output Flags

| Flag | Default | Description | |---------------------|---------------------------------------------|---------------------------------------------------| | --catalog-file | Co-located with first output (see below) | Output path for catalog.json (always generated) |

Catalog Default Location: The catalog is automatically placed alongside the first available output:

  • With --client-dir: {client-dir}/catalog.json
  • With --openapi-file only: {openapi-file-dir}/catalog.json
  • With --gateway-dir only: {gateway-dir}/catalog.json

Note: At least one of --client-dir, --openapi-file, or --gateway-dir must be provided.

Generation Control Flags

| Flag | Description | |-------------------------|------------------------------------------------| | --client-dir | Generate TypeScript client in this directory | | --openapi-file | Generate OpenAPI spec at this path | | --gateway-dir | Generate Fastify gateway in this directory | | --generate-app | Generate runnable app (requires gateway) |

Optional Flags

All flags from client, openapi, and gateway commands are supported. Key flags:

Client Flags:

  • --import-extensions (default: js)
  • --client-attributes-key (default: $attributes)
  • --client-class-name
  • --client-int64-as (default: string)
  • --client-bigint-as (default: string)
  • --client-decimal-as (default: string)
  • --client-date-as (default: string)
  • --client-choice-mode (default: all-optional)
  • --client-fail-on-unresolved (default: false)
  • --client-nillable-as-optional (default: false)

OpenAPI Flags:

  • --openapi-format (default: json)
  • --openapi-title
  • --openapi-version (default: 0.0.0)
  • --openapi-description
  • --openapi-servers (default: /)
  • --openapi-base-path
  • --openapi-path-style (default: kebab)
  • --openapi-method (default: post)
  • --openapi-tag-style (default: default)
  • --openapi-closed-schemas (default: false)
  • --openapi-prune-unused-schemas (default: false)
  • --openapi-envelope-namespace (default: ResponseEnvelope)
  • --openapi-error-namespace (default: ErrorObject)
  • --openapi-validate (default: true)
  • --openapi-security-config-file
  • --openapi-tags-file
  • --openapi-ops-file

Gateway Flags:

  • --gateway-service-name (required if --gateway-dir provided)
  • --gateway-version-prefix (required if --gateway-dir provided)
  • --gateway-default-status-codes
  • --gateway-stub-handlers (default: false)

Examples

Complete Stack Generation:

npx wsdl-tsc pipeline \
  --wsdl-source examples/minimal/weather.wsdl \
  --client-dir tmp/client \
  --openapi-file tmp/openapi.json \
  --gateway-dir tmp/gateway \
  --gateway-service-name weather \
  --gateway-version-prefix v1

With App Generation:

npx wsdl-tsc pipeline \
  --wsdl-source examples/minimal/weather.wsdl \
  --client-dir tmp/client \
  --openapi-file tmp/openapi.json \
  --gateway-dir tmp/gateway \
  --gateway-service-name weather \
  --gateway-version-prefix v1 \
  --generate-app

Client + OpenAPI Only:

npx wsdl-tsc pipeline \
  --wsdl-source https://example.com/Hotel.wsdl \
  --client-dir ./build/client \
  --openapi-file ./docs/hotel-api.json \
  --openapi-format both

With Full Configuration:

npx wsdl-tsc pipeline \
  --wsdl-source ./wsdl/Booking.wsdl \
  --client-dir ./build/client \
  --openapi-file ./docs/booking-api \
  --gateway-dir ./build/gateway \
  --openapi-format both \
  --openapi-servers https://api.example.com/v1 \
  --openapi-base-path /booking \
  --openapi-security-config-file ./config/security.json \
  --gateway-service-name booking \
  --gateway-version-prefix v1 \
  --client-int64-as number \
  --client-decimal-as string

Pipeline Workflow

The pipeline command executes these steps in order:

  1. Parse WSDL → Load and validate WSDL document
  2. Compile Catalog → Generate intermediate representation
  3. Emit Catalog → Write catalog.json (always)
  4. Generate Client → Emit TypeScript client files (if --client-dir)
  5. Generate OpenAPI → Create OpenAPI spec (if --openapi-file)
  6. Generate Gateway → Create Fastify gateway code (if --gateway-dir)
  7. Generate App → Create runnable application (if --generate-app)

All steps share the same parsed WSDL and compiled catalog, ensuring consistency.


Command: client

Purpose: Generate strongly-typed TypeScript SOAP client code from WSDL or a pre-compiled catalog.

When to use:

  • Standard SOAP integration (most common use case)
  • When you need TypeScript types and client methods for SOAP operations
  • When building applications that consume SOAP services

Usage

npx wsdl-tsc client --wsdl-source <file|url> --client-dir <path> [options]
# OR
npx wsdl-tsc client --catalog-file <path> --client-dir <path> [options]

Required Flags

| Flag | Description | |------------------|-------------------------------------------------| | --wsdl-source | Path or URL to WSDL file (see note below) | | --client-dir | Output directory for generated TypeScript files |

Optional Input Flags

| Flag | Default | Description | |------------------|-----------------------------|----------------------------------------------------------------------| | --catalog-file | {client-dir}/catalog.json | Path to pre-compiled catalog.json (when not using --wsdl-source) |

Note: Provide either --wsdl-source (to compile from WSDL) or --catalog-file (to use pre-compiled catalog). When using --wsdl-source, the catalog is automatically generated in the client directory unless you override with --catalog-file.

Generated Files

| File | Purpose | |----------------|------------------------------------------------------------------------------| | client.ts | Strongly-typed SOAP client wrapper with one method per operation | | types.ts | Flattened TypeScript interfaces, type aliases, and enums | | utils.ts | Runtime metadata for JSON to SOAP conversion (attribute mapping, occurrence) | | catalog.json | (When using --wsdl-source) Generated in client directory by default |

Optional Flags

All flags from compile command, plus:

| Flag | Default | Description | |---------------------------------|----------------|-------------------------------------| | --import-extensions | js | Import style: js, ts, or bare | | --client-attributes-key | $attributes | Attribute bag key | | --client-class-name | (derived) | Override client class name | | --client-int64-as | string | Map 64-bit integers | | --client-bigint-as | string | Map arbitrary-size integers | | --client-decimal-as | string | Map xs:decimal | | --client-date-as | string | Map date/time types | | --client-choice-mode | all-optional | Choice element strategy | | --client-fail-on-unresolved | false | Fail on unresolved references | | --client-nillable-as-optional | false | Treat nillable as optional |

Examples

Basic Generation (Default Catalog Location)

npx wsdl-tsc client \
  --wsdl-source examples/minimal/weather.wsdl \
  --client-dir tmp/client

Output: Generates client files and catalog at tmp/client/catalog.json.

With Custom Catalog Path

npx wsdl-tsc client \
  --wsdl-source examples/minimal/weather.wsdl \
  --client-dir tmp/client \
  --catalog-file build/shared-catalog.json

With Custom Numeric Mappings

npx wsdl-tsc client \
  --wsdl-source https://example.com/Hotel.wsdl \
  --client-dir ./src/integrations/soap/hotel \
  --client-int64-as number \
  --client-decimal-as string \
  --client-date-as string

Output: Catalog generated at ./src/integrations/soap/hotel/catalog.json.

From Pre-compiled Catalog

# First compile the catalog
npx wsdl-tsc compile --wsdl-source https://example.com/Hotel.wsdl --catalog-file build/hotel-catalog.json

# Then generate client from catalog
npx wsdl-tsc client \
  --catalog-file build/hotel-catalog.json \
  --client-dir ./src/services/hotel

Key Modeling Rules

  • Attributes & elements become peer properties (flattened)
  • Text content becomes $value property
  • Required attributes: use!="optional"; elements minOccurs>=1
  • Multiplicity: maxOccurs>1 or unbounded become arrays
  • Nillable: nillable="true" preserved (optionally model as optional with --client-nillable-as-optional)
  • Inheritance: extensions merged or emitted as extends; simpleContent base collapsed logically

Command: openapi

Purpose: Generate OpenAPI 3.1 specification from WSDL or a pre-compiled catalog, mirroring the exact TypeScript type structure.

When to use:

  • Creating REST API documentation for SOAP services
  • Building API gateways or proxies
  • Enabling REST-style access to SOAP operations
  • Generating client SDKs in other languages

Usage

npx wsdl-tsc openapi --wsdl-source <file|url> --openapi-file <path> [options]
# OR
npx wsdl-tsc openapi --catalog-file <path> --openapi-file <path> [options]

Required Flags

| Flag | Description | |---------------------|----------------------------------------------------| | --openapi-file | Output path for OpenAPI specification |

Input Source Flags (Mutually Exclusive)

| Flag | Default | Description | |---------------------|--------------------------------------|----------------------------------------------------| | --wsdl-source | (none) | Path or URL to WSDL file | | --catalog-file | {openapi-file-dir}/catalog.json | Path to pre-compiled catalog.json |

Note: Provide either --wsdl-source or --catalog-file. When neither is provided, defaults to reading from the OpenAPI output directory. When using --wsdl-source, the catalog is automatically written to the OpenAPI output directory unless overridden.

Core Optional Flags

| Flag | Default | Description | |-------------------------------|-----------|----------------------------------------------------------| | --openapi-format | json | Output format: json, yaml, or both | | --openapi-title | (derived) | API title in info section | | --openapi-version | 0.0.0 | API version in info.version | | --openapi-description | (empty) | API description in info section | | --openapi-servers | / | Comma-separated server URLs | | --openapi-base-path | (empty) | Base path prefix (e.g., /v1/soap) | | --openapi-validate | true | Validate spec with swagger-parser |

Path & Schema Customization

| Flag | Default | Description | |----------------------------------|-----------|--------------------------------------------------| | --openapi-path-style | kebab | Path transformation: kebab, asis, or lower | | --openapi-method | post | Default HTTP method for operations | | --openapi-tag-style | default | Tag inference: default, service, or first | | --openapi-closed-schemas | false | Add additionalProperties: false to all schemas | | --openapi-prune-unused-schemas | false | Emit only schemas referenced by operations |

Response Envelope Customization

| Flag | Default | Description | |--------------------------------|--------------------|---------------------------------------------| | --openapi-envelope-namespace | ResponseEnvelope | Override envelope component name suffix | | --openapi-error-namespace | ErrorObject | Override error object component name suffix |

Configuration Files

| Flag | Description | |-----------------------------------|-------------------------------------------------------| | --openapi-security-config-file | Path to security.json (schemes, headers, overrides) | | --openapi-tags-file | Path to tags.json (explicit operation → tag map) | | --openapi-ops-file | Path to ops.json (per-operation overrides) |

Examples

Basic JSON Output

npx wsdl-tsc openapi \
  --wsdl-source examples/minimal/weather.wsdl \
  --openapi-file ./docs/weather-api.json

Multi-Format with Validation

npx wsdl-tsc openapi \
  --wsdl-source https://example.com/Hotel.wsdl \
  --openapi-file ./docs/hotel-api \
  --openapi-format both \
  --openapi-servers https://api.example.com/v1,https://api-staging.example.com/v1 \
  --openapi-base-path /soap

From Pre-compiled Catalog

npx wsdl-tsc openapi \
  --catalog-file ./artifacts/hotel-catalog.json \
  --openapi-file ./docs/hotel-api.json \
  --openapi-format json

With Custom Configuration

npx wsdl-tsc openapi \
  --wsdl-source ./wsdl/Booking.wsdl \
  --openapi-file ./docs/booking-api.yaml \
  --openapi-format yaml \
  --openapi-title "Hotel Booking API" \
  --openapi-version "1.2.0" \
  --openapi-description "REST API for hotel booking SOAP service" \
  --openapi-security-config-file ./config/security.json \
  --openapi-tags-file ./config/tags.json \
  --openapi-path-style kebab \
  --openapi-method post \
  --openapi-tag-style service

Standard Response Envelope

All responses are wrapped in a standard envelope for consistency and debuggability (always-on since 0.7.1):

Base Envelope Structure

{
  status: string;           // e.g., "SUCCESS", "FAILURE", "PENDING"
  message: string | null;   // diagnostic message (not for end-user UI)
  data: T | null;          // operation payload (typed per operation)
  error: ErrorObject | null; // populated on failures
}

Error Object Structure

{
  code: string;              // stable machine error code
  message: string;           // brief description
  details: object | null;    // arbitrary extra info
}

Naming Rules

  • Base envelope: ${serviceName}ResponseEnvelope (override with --openapi-envelope-namespace)
  • Error object: ${serviceName}ErrorObject (override with --openapi-error-namespace)
  • Per-operation extension: <PayloadType|OperationName><EnvelopeNamespace> (refines data field)

Collision Avoidance

If the payload type already ends with the namespace prefix, an underscore is inserted:

  • Payload WeatherResponse + default ResponseEnvelopeWeatherResponse_ResponseEnvelope
  • Payload Booking + default ResponseEnvelopeBookingResponseEnvelope

Example

npx wsdl-tsc openapi \
  --wsdl-source ./wsdl/Hotel.wsdl \
  --openapi-file ./docs/hotel-api.json \
  --openapi-envelope-namespace ApiEnvelope \
  --openapi-error-namespace ApiError

Produces components:

  1. HotelApiEnvelope (base)
  2. <Payload>ApiEnvelope extension schemas (alphabetically sorted)
  3. HotelApiError (error object)
  4. Domain schemas

Tag Inference Strategies

| Strategy | Behavior | |-----------|------------------------------------------------------------------------------------| | default | Single tag = service name (fallback SOAP) | | service | Always service name (even if operation prefix differs) | | first | First lexical segment of CamelCase operation (e.g., GetCityWeatherByZIPGet) |

Use --openapi-tags-file for explicit mapping when heuristics are insufficient.

Output Determinism

All generated OpenAPI specs have deterministic ordering:

  • Path keys (alphabetically sorted)
  • HTTP methods within paths (alphabetically sorted)
  • Component schema names (alphabetically sorted)
  • Security schemes (alphabetically sorted)
  • Parameters (alphabetically sorted)
  • Operation tag arrays (alphabetically sorted)

This ensures diff-friendly output for version control.


Command: gateway

Purpose: Generate a production-ready Fastify gateway with fully functional route handlers from an OpenAPI 3.1 specification. This creates a complete REST API layer over your SOAP client with automatic request/response transformation and standardized envelope responses.

When to use:

  • Building a REST API gateway for legacy SOAP services
  • Creating a modern HTTP/JSON interface for SOAP operations
  • Setting up request/response validation with JSON Schema
  • Establishing Fastify routing structure with full handler implementations

What it generates:

  • Fastify route registration files with complete handler implementations
  • JSON Schema models with URN-based IDs
  • Operation schemas (request/response validation)
  • Schema and route registration modules
  • Runtime utilities (envelope builders, error handlers)
  • Fastify plugin wrapper for simplified integration

Usage

npx wsdl-tsc gateway \
  --openapi-file <path> \
  --client-dir <path> \
  --gateway-dir <path> \
  --gateway-service-name <slug> \
  --gateway-version-prefix <slug> \
  [options]

Required Flags

| Flag | Description | |----------------------------|--------------------------------------------------------------------------| | --openapi-file | Path to OpenAPI 3.1 JSON or YAML file | | --client-dir | Path to client directory (where client.ts is located) | | --gateway-dir | Output directory for generated gateway code | | --gateway-service-name | Service identifier for URN generation (e.g., weather, booking) | | --gateway-version-prefix | Version prefix for URN generation (e.g., v1, v2, urn:1.0.2:schema) |

Optional Flags

| Flag | Default | Description | |----------------------------------|---------------------------------------------------|-------------------------------------------------------------| | --import-extensions | js | Import style: js, ts, or bare | | --gateway-default-status-codes | 200,400,401,403,404,409,422,429,500,502,503,504 | Comma-separated status codes to backfill | | --catalog-file | (none) | Path to catalog.json for operation metadata | | --gateway-client-class-name | (auto-detected) | Override SOAP client class name | | --gateway-decorator-name | {serviceSlug}Client | Fastify decorator name for client instance | | --gateway-stub-handlers | false | Generate stub handlers instead of full implementations | | --gateway-skip-plugin | false | Skip generating plugin.ts wrapper | | --gateway-skip-runtime | false | Skip generating runtime.ts utilities |

Note: Route URLs are derived from the OpenAPI document paths, which already include any base path configured during OpenAPI generation (via --openapi-base-path). There is no separate route prefix option for the gateway.

Generated Output Structure

{gateway-dir}/
├── schemas/
│   ├── models/              # JSON Schema components with URN IDs
│   │   ├── <schema1>.json
│   │   ├── <schema2>.json
│   │   └── ...
│   └── operations/          # Fastify operation schemas
│       ├── <operation1>.json
│       ├── <operation2>.json
│       └── ...
├── routes/                  # Route registration files with full handlers
│   ├── <route1>.ts
│   ├── <route2>.ts
│   └── ...
├── schemas.ts               # Schema registration module
├── routes.ts                # Route aggregator module
├── runtime.ts               # Envelope builders and error handler
└── plugin.ts                # Fastify plugin wrapper (recommended entry point)

URN-Based Schema IDs

All generated JSON Schemas use deterministic URN identifiers:

urn:services:{serviceSlug}:{versionSlug}:schemas:{models|operations}:{schemaSlug}

Example: urn:services:weather:v1:schemas:models:getcityweatherbyzipresponse

Contract Assumptions

The gateway generator enforces strict OpenAPI contract validation:

  • All request/response bodies must use $ref to components.schemas (no inline schemas)
  • Every operation must have a default response with application/json content
  • All schemas referenced by operations must exist in components.schemas

Examples

Basic Gateway Generation

npx wsdl-tsc gateway \
  --openapi-file ./docs/weather-api.json \
  --client-dir ./src/services/weather \
  --gateway-dir ./src/gateway/weather \
  --gateway-service-name weather \
  --gateway-version-prefix v1

With Custom Status Codes

npx wsdl-tsc gateway \
  --openapi-file ./docs/hotel-api.json \
  --client-dir ./src/services/hotel \
  --gateway-dir ./src/gateway/hotel \
  --gateway-service-name hotel \
  --gateway-version-prefix v2 \
  --gateway-default-status-codes 200,400,401,404,500

From YAML OpenAPI

npx wsdl-tsc gateway \
  --openapi-file ./docs/booking-api.yaml \
  --client-dir ./src/services/booking \
  --gateway-dir ./src/gateway/booking \
  --gateway-service-name booking \
  --gateway-version-prefix v1

Integration Pattern

The generated gateway provides a Fastify plugin for simplified integration.

Prerequisites

Your host application needs these dependencies:

npm install fastify fastify-plugin

Using the Generated Plugin (Recommended)

import Fastify from 'fastify';
import weatherGateway from './gateway/plugin.js';
import { Weather } from './client/client.js';

const app = Fastify({ logger: true });

// Create and configure SOAP client
const weatherClient = new Weather({
  source: 'https://example.com/weather.wsdl',
  // security: new soap.WSSecurity('user', 'pass'), // if needed
});

// Register gateway plugin with client
await app.register(weatherGateway, {
  client: weatherClient,
  // Note: Route paths are determined by --openapi-base-path during generation.
  // The prefix option here adds an ADDITIONAL runtime prefix on top of generated paths.
  // Only use if you need to mount routes under a different sub-path at runtime.
});

await app.listen({ port: 3000 });

The plugin automatically:

  • Decorates Fastify with the SOAP client (fastify.weatherClient)
  • Registers all JSON schemas for validation
  • Installs a centralized error handler
  • Registers all routes with full handler implementations

Using Individual Components (Advanced)

For more control, you can use the individual modules:

import Fastify from 'fastify';
import { registerSchemas_v1_weather } from './gateway/schemas.js';
import { registerRoutes_v1_weather } from './gateway/routes.js';
import { createGatewayErrorHandler_v1_weather } from './gateway/runtime.js';
import { Weather } from './client/client.js';

const app = Fastify({ logger: true });

// Manual setup
const weatherClient = new Weather({ source: 'weather.wsdl' });
app.decorate('weatherClient', weatherClient);

// Register schemas
await registerSchemas_v1_weather(app);

// Install error handler
app.setErrorHandler(createGatewayErrorHandler_v1_weather());

// Register routes (paths already include --openapi-base-path if configured)
await registerRoutes_v1_weather(app);

await app.listen({ port: 3000 });

Generated Handler Implementation

Route handlers are fully implemented and call the SOAP client automatically:

// Generated: routes/get-city-forecast-by-zip.ts
import type { FastifyInstance } from "fastify";
import schema from "../schemas/operations/getcityforecastbyzip.json" with { type: "json" };
import { buildSuccessEnvelope } from "../runtime.js";

export async function registerRoute_v1_weather_getcityforecastbyzip(fastify: FastifyInstance) {
  fastify.route({
    method: "POST",
    url: "/get-city-forecast-by-zip",
    schema,
    handler: async (request) => {
      const client = fastify.weatherClient;
      const result = await client.GetCityForecastByZIP(request.body);
      return buildSuccessEnvelope(result.response);
    },
  });
}

Response Envelope

All responses are wrapped in a standard envelope format:

Success Response:

{
  "status": "SUCCESS",
  "message": null,
  "data": { /* SOAP response data */ },
  "error": null
}

Error Response:

{
  "status": "ERROR",
  "message": "Request validation failed",
  "data": null,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": { /* validation errors */ }
  }
}

Error Handling

The centralized error handler (runtime.ts) automatically classifies errors:

| Error Type | HTTP Status | Error Code | |-----------------------|-------------|-----------------------| | Validation errors | 400 | VALIDATION_ERROR | | SOAP faults | 502 | SOAP_FAULT | | Connection refused | 503 | SERVICE_UNAVAILABLE | | Timeout | 504 | GATEWAY_TIMEOUT | | Other errors | 500 | INTERNAL_ERROR |

Stub Handler Mode (Backward Compatible)

If you prefer to implement handler logic manually or need custom transformation logic beyond the standard SOAP-to-REST mapping, use stub mode:

npx wsdl-tsc gateway \
  --openapi-file ./docs/weather-api.json \
  --client-dir ./src/services/weather \
  --gateway-dir ./src/gateway/weather \
  --gateway-service-name weather \
  --gateway-version-prefix v1 \
  --gateway-stub-handlers

This generates minimal handler stubs that throw "Not implemented" errors, allowing you to implement fully custom logic while keeping the routing and validation infrastructure.


Command: app

Purpose: Generate a runnable Fastify application that integrates the generated client, gateway, and OpenAPI spec. This provides an immediately executable server for testing, development, and demonstrations.

When to use:

  • Local testing and development
  • Quick iteration on gateway configurations
  • Demonstrating the generated API
  • CI smoke testing

Usage

npx wsdl-tsc app \
  --client-dir <path> \
  --gateway-dir <path> \
  --openapi-file <path> \
  [--catalog-file <path>] \
  [--app-dir <path>] \
  [options]

Required Flags

| Flag | Description | |------------------|----------------------------------------------------------| | --client-dir | Path to client directory (where client.ts is located) | | --gateway-dir | Path to gateway directory (where plugin.ts is located) | | --openapi-file | Path to OpenAPI specification file |

Optional Flags

| Flag | Default | Description | |-----------------------|-------------------------------|---------------------------------------------------| | --catalog-file | {client-dir}/catalog.json | Path to catalog.json (for metadata extraction) | | --app-dir | {gateway-dir}/../app | Output directory for generated app | | --import-extensions | Inferred from catalog or js | Import-extension mode: js, ts, or bare | | --host | 127.0.0.1 | Default server host | | --port | 3000 | Default server port | | --prefix | "" (empty) | Route prefix | | --logger | true | Enable Fastify logger | | --openapi-mode | copy | How to handle OpenAPI file: copy or reference |

Examples

Generate App After Pipeline

# First generate client, OpenAPI, and gateway
npx wsdl-tsc pipeline \
  --wsdl-source weather.wsdl \
  --client-dir ./client \
  --openapi-file ./openapi.json \
  --gateway-dir ./gateway \
  --gateway-service-name weather \
  --gateway-version-prefix v1

# Then generate runnable app
npx wsdl-tsc app \
  --client-dir ./client \
  --gateway-dir ./gateway \
  --openapi-file ./openapi.json \
  --app-dir ./app

Generate App with Custom Configuration

npx wsdl-tsc app \
  --client-dir ./client \
  --gateway-dir ./gateway \
  --openapi-file ./openapi.json \
  --app-dir ./my-app \
  --host 0.0.0.0 \
  --port 8080 \
  --prefix /api/v1

Generated App Structure

The app command generates the following files:

app/
├── server.js (or .ts)    # Main application entry point
├── config.js (or .ts)    # Configuration loader with env support
├── .env.example          # Environment variable template
├── README.md             # Usage instructions
└── openapi.json          # OpenAPI spec (when --openapi-mode=copy)

Running the Generated App

# Copy environment template
cd app
cp .env.example .env

# Edit .env to configure WSDL source and other settings
# vim .env

# Run the server
npx tsx server.js  # For TypeScript files
# or
node server.js     # For JavaScript files

Configuration

The generated app loads configuration from environment variables with the following precedence:

  1. Environment variables (runtime overrides)
  2. Catalog defaults (from generation-time)
  3. Hard defaults (in config file)

Environment Variables

| Variable | Default (from catalog or flags) | Description | |-----------------|---------------------------------|--------------------------------------| | WSDL_SOURCE | From catalog or required | WSDL URL or local file path | | HOST | 127.0.0.1 | Server bind address | | PORT | 3000 | Server listen port | | PREFIX | "" (empty) | Route prefix | | LOGGER | true | Enable Fastify logger |

Endpoints

The generated app serves the following endpoints:

Health Check

GET /health

Returns: { "ok": true }

OpenAPI Specification

GET /openapi.json

Returns: Complete OpenAPI 3.1 specification

Gateway Routes

All SOAP operations are exposed as REST endpoints. See the OpenAPI spec for complete API documentation.

Example Usage

# Start the server
cd app
npx tsx server.js

# Test health endpoint
curl http://localhost:3000/health

# Get OpenAPI spec
curl http://localhost:3000/openapi.json | jq .

# Call a gateway operation (example)
curl -X POST http://localhost:3000/get-weather-information \
  -H "Content-Type: application/json" \
  -d '{}'

Integration with Pipeline

The app command can also be used via the pipeline with the --generate-app flag:

npx wsdl-tsc pipeline \
  --wsdl-source weather.wsdl \
  --client-dir ./client \
  --openapi-file ./openapi.json \
  --gateway-dir ./gateway \
  --gateway-service-name weather \
  --gateway-version-prefix v1 \
  --generate-app

This generates all artifacts including the runnable app in a single command.


Command: compile (Advanced)

Purpose: Parse WSDL and generate only the intermediate catalog.json representation without TypeScript client code.

When to use:

  • Multi-stage builds where you want to cache the parsed WSDL
  • Debugging or inspecting the compiled schema structure
  • Sharing a compiled catalog across multiple generation targets

Usage

npx wsdl-tsc compile --wsdl-source <file|url> --catalog-file <path> [options]

Required Flags

| Flag | Description | |---------------------|------------------------------------------| | --wsdl-source | Path or URL to the WSDL file | | --catalog-file | Output path for catalog.json |

Optional Flags

| Flag | Default | Description | |------------------------------------|----------------|--------------------------------------------------------------| | --import-extensions | js | Import specifier style: js, ts, or bare | | --client-attributes-key | $attributes | Attribute bag key for runtime mapper | | --client-class-name | (derived) | Override generated client class name | | --client-int64-as | string | Map 64-bit integers: string, number, or bigint | | --client-bigint-as | string | Map arbitrary-size integers: string or number | | --client-decimal-as | string | Map xs:decimal: string or number | | --client-date-as | string | Map date/time types: string or Date | | --client-choice-mode | all-optional | Choice element strategy: all-optional or union | | --client-fail-on-unresolved | false | Fail build on unresolved type references | | --client-nillable-as-optional | false | Treat nillable elements as optional properties |

Examples

Basic Compilation:

npx wsdl-tsc compile \
  --wsdl-source examples/minimal/weather.wsdl \
  --catalog-file tmp/catalog.json

With Custom Mapping Options:

npx wsdl-tsc compile \
  --wsdl-source https://example.com/Hotel.wsdl \
  --catalog-file ./build/hotel-catalog.json \
  --client-int64-as number \
  --client-decimal-as string

For Debugging:

# Compile to inspect types and operations
npx wsdl-tsc compile \
  --wsdl-source ./wsdl/ComplexService.wsdl \
  --catalog-file ./debug/catalog.json \
  --client-fail-on-unresolved false

# Inspect types
cat ./debug/catalog.json | jq '.types'

# Inspect operations
cat ./debug/catalog.json | jq '.operations'

Output

  • catalog.json - Compiled schema representation including types, operations, and metadata

Catalog Structure

The catalog.json file contains the compiled WSDL representation:

{
  "wsdlUri": "path/to/service.wsdl",
  "targetNamespace": "http://example.com/service",
  "serviceName": "WeatherService",
  "types": [
    {
      "name": "GetWeatherRequest",
      "properties": []
    }
  ],
  "operations": [
    {
      "name": "GetWeather",
      "input": "GetWeatherRequest",
      "output": "GetWeatherResponse"
    }
  ],
  "options": {
    "imports": "js",
    "catalog": true
  }
}

Key sections:

  • types - All compiled type definitions with properties and inheritance
  • operations - SOAP operations with input/output type references
  • options - Compiler options used during generation

This catalog can be reused with the client and openapi commands via --catalog-file.

Catalog Co-location

Default behavior: Catalog files are co-located with their primary output files for better organization and discoverability.

Catalog Location by Command:

  • compile: Always requires explicit --catalog-file (no default)
  • client: Defaults to {client-dir}/catalog.json
  • openapi: Defaults to {openapi-file-dir}/catalog.json
  • pipeline: Intelligent cascade - first available: {client-dir} > {openapi-dir} > {gateway-dir} > tmp/

Common patterns:

  1. Co-located with client (recommended for most projects):

    npx wsdl-tsc client --wsdl-source service.wsdl --client-dir src/services/weather

    Creates src/services/weather/catalog.json automatically.

  2. Shared catalog for multiple commands (custom location):

    npx wsdl-tsc compile --wsdl-source service.wsdl --catalog-file build/shared-catalog.json
    npx wsdl-tsc client --catalog-file build/shared-catalog.json --client-dir src/client
    npx wsdl-tsc openapi --catalog-file build/shared-catalog.json --openapi-file docs/api.json

Working With Generated Clients

Client Construction

import soap from "soap";
import { Weather } from "./src/services/weather/client.js";

const client = new Weather({
  source: "https://example.com/WeatherService?wsdl",
  security: new soap.WSSecurity("username", "password")
});

Calling Operations

// Operation with input
const forecast = await client.GetCityForecastByZIP({
  ZIP: "10001"
});

console.log(forecast.GetCityForecastByZIPResult.Success);
console.log(forecast.GetCityForecastByZIPResult.ForecastResult);

// Operation without input
const info = await client.GetWeatherInformation({});
console.log(info.GetWeatherInformationResult.WeatherDescriptions);

Attributes & Text Content

When an element has both attributes and text content, use the $value convention:

const price = {
  currencyCode: "USD",  // attribute
  $value: "123.45"      // text content
};

Working With Arrays

Repeated elements are automatically typed as arrays:

interface ForecastReturn {
  Forecast: Forecast[];  // maxOccurs > 1
}

Type Safety

All operations and types are fully typed:

// TypeScript knows the exact shape
const result: GetCityWeatherByZIPResponse = await client.GetCityWeatherByZIP({
  ZIP: "10001"
});

// Autocomplete and type checking work
result.GetCityWeatherByZIPResult.Temperature;  // number | string (depends on mapping)

Configuration Files

Security Configuration (security.json)

Define security schemes, headers, and per-operation overrides:

{
  "global": {
    "scheme": "bearer",
    "bearer": { "bearerFormat": "JWT" },
    "headers": [
      {
        "name": "X-Correlation-Id",
        "required": false,
        "schema": { "type": "string" }
      }
    ]
  },
  "overrides": {
    "CancelBooking": { "scheme": "apiKey" }
  }
}

Supported schemes: none, basic, bearer, apiKey, oauth2

Tags Configuration (tags.json)

Explicit operation → tag mapping:

{
  "GetCityWeatherByZIP": ["Weather", "Forecast"],
  "GetWeatherInformation": ["Weather", "Info"],
  "CancelBooking": ["Booking", "Cancellation"]
}

Operations Configuration (ops.json)

Per-operation overrides for method, summary, description, and deprecation:

{
  "GetCityWeatherByZIP": {
    "method": "get",
    "summary": "Get weather forecast by ZIP code",
    "description": "Returns a detailed weather forecast for the specified US ZIP code",
    "deprecated": false
  },
  "LegacyOperation": {
    "deprecated": true
  }
}

Production Concerns

Deterministic Output Guarantees

All generated code and specifications have stable, deterministic ordering for version control:

  • TypeScript files: Sorted type declarations, imports, and exports
  • OpenAPI specs: Sorted paths, HTTP methods, schemas, parameters, security schemes, tags
  • JSON Schemas: Sorted property keys and component names
  • Gateway routes: Alphabetically organized route files
  • Catalog JSON: Consistent ordering of types and operations

Benefit: Safe regeneration in CI/CD without spurious diffs.

Validation Behavior

OpenAPI Validation (enabled by default):

  • Uses @apidevtools/swagger-parser
  • Validates schema structure
  • Resolves all $ref references
  • Catches missing schemas and circular dependencies
  • Disable with --openapi-validate false

Gateway Contract Validation:

  • All request/response bodies must use $ref to components.schemas
  • Every operation must have a default response with application/json content
  • All referenced schemas must exist in components.schemas

Error Handling

Gateway Error Classification:

| Error Type | HTTP Status | Error Code | When It Occurs | |-----------------------|-------------|-----------------------|---------------------------------------| | Validation errors | 400 | VALIDATION_ERROR | Request doesn't match JSON Schema | | SOAP faults | 502 | SOAP_FAULT | SOAP service returned a fault | | Connection refused | 503 | SERVICE_UNAVAILABLE | Cannot reach SOAP endpoint | | Timeout | 504 | GATEWAY_TIMEOUT | SOAP request exceeded timeout | | Other errors | 500 | INTERNAL_ERROR | Unexpected errors |

All errors are wrapped in the standard envelope format with error object populated.

SOAP Wire Logging

Enable SOAP request/response debugging:

NODE_DEBUG=soap node app.js

This logs full XML request/response payloads to console.

CI/CD Tips

Caching Strategy:

# Step 1: Compile catalog (cacheable artifact)
npx wsdl-tsc compile \
  --wsdl-source ./wsdl/Service.wsdl \
  --catalog-file ./build/catalog.json

# Step 2: Generate code from cached catalog
npx wsdl-tsc client --catalog-file ./build/catalog.json --client-dir ./src/client
npx wsdl-tsc openapi --catalog-file ./build/catalog.json --openapi-file ./docs/api.json

Recommended Build Script (package.json):

{
  "scripts": {
    "generate": "npx wsdl-tsc pipeline --wsdl-source ./wsdl/service.wsdl --client-dir ./src/client --openapi-file ./docs/api.json --gateway-dir ./src/gateway --gateway-service-name svc --gateway-version-prefix v1",
    "build": "npm run generate && tsc",
    "typecheck": "tsc --noEmit"
  }
}

Known Limitations

Choice Elements:

  • Current strategy: all-optional (all branches optional)
  • Future: Discriminated union support (planned)

Union Types:

  • Experimental --client-choice-mode union available
  • May require manual refinement for complex patterns

WS-Policy:

  • Security hints extracted from policies
  • Custom policies may require manual security configuration

Array Wrapper Flattening:

  • Single-child sequences with maxOccurs>1 become array schemas
  • Sequences with multiple children preserve wrapper

Programmatic API

All CLI commands are available as TypeScript functions for programmatic usage.

compileWsdlToProject

Generate TypeScript SOAP client from WSDL.

import { compileWsdlToProject } from "@techspokes/typescript-wsdl-client";

await compileWsdlToProject({
  wsdl: "./wsdl/Hotel.wsdl",
  outDir: "./src/services/hotel",
  options: {
    imports: "js",
    catalog: true,
    primitive: {
      int64As: "number",
      bigIntegerAs: "string",
      decimalAs: "string",
      dateAs: "string"
    },
    choice: "all-optional",
    clientName: "HotelClient",
    nillableAsOptional: false
  }
});

Type Signature:

// noinspection JSAnnotator
function compileWsdlToProject(input: {
  wsdl: string;
  outDir: string;
  options?: Partial<CompilerOptions>;
}): Promise<void>;

Options (CompilerOptions):

interface CompilerOptions {
  wsdl: string;
  out: string;
  imports: "js" | "ts" | "bare";
  catalog: boolean;
  primitive: PrimitiveOptions;
  choice?: "all-optional" | "union";
  failOnUnresolved?: boolean;
  attributesKey?: string;
  clientName?: string;
  nillableAsOptional?: boolean;
}

interface PrimitiveOptions {
  int64As?: "string" | "number" | "bigint";
  bigIntegerAs?: "string" | "number";
  decimalAs?: "string" | "number";
  dateAs?: "string" | "Date";
}

generateOpenAPI

Generate OpenAPI 3.1 specification from WSDL or catalog.

import { generateOpenAPI } from "@techspokes/typescript-wsdl-client";

const { doc, jsonPath, yamlPath } = await generateOpenAPI({
  wsdl: "./wsdl/Hotel.wsdl",
  outFile: "./docs/hotel-api",
  format: "both",
  title: "Hotel Booking API",
  version: "1.0.0",
  servers: ["https://api.example.com/v1"],
  basePath: "/booking",
  pathStyle: "kebab",
  tagStyle: "service",
  validate: true
});

Type Signature:

// noinspection JSAnnotator
function generateOpenAPI(opts: GenerateOpenAPIOptions): Promise<{
  doc: any;
  jsonPath?: string;
  yamlPath?: string;
}>;

Options (GenerateOpenAPIOptions):

interface GenerateOpenAPIOptions {
  // Input sources (mutually exclusive)
  wsdl?: string;
  catalogFile?: string;
  compiledCatalog?: CompiledCatalog;
  
  // Output
  outFile?: string;
  format?: "json" | "yaml" | "both";
  
  // Metadata
  title?: string;
  version?: string;
  description?: string;
  servers?: string[];
  
  // Path configuration
  basePath?: string;
  pathStyle?: "kebab" | "asis" | "lower";
  defaultMethod?: string;
  
  // Schema configuration
  closedSchemas?: boolean;
  pruneUnusedSchemas?: boolean;
  
  // Tag configuration
  tagStyle?: "default" | "first" | "service";
  tagsFile?: string;
  
  // Security & operations
  securityConfigFile?: string;
  opsFile?: string;
  
  // Envelope customization
  envelopeNamespace?: string;
  errorNamespace?: string;
  
  // Validation
  validate?: boolean;
  skipValidate?: boolean;
  
  // Deprecated
  asYaml?: boolean;
}

generateGateway

Generate Fastify gateway code from OpenAPI specification.

import { generateGateway } from "@techspokes/typescript-wsdl-client";

await generateGateway({
  openapiFile: "./docs/hotel-api.json",
  outDir: "./src/gateway/hotel",
  clientDir: "./src/services/hotel",
  versionSlug: "v1",
  serviceSlug: "hotel",
  defaultResponseStatusCodes: [200, 400, 401, 403, 404, 409, 422, 429, 500, 502, 503, 504],
  imports: "js"
});

Type Signature:

// noinspection JSAnnotator
function generateGateway(opts: GenerateGatewayOptions): Promise<void>;

Options (GenerateGatewayOptions):

interface GenerateGatewayOptions {
  // Input sources (mutually exclusive)
  openapiFile?: string;
  openapiDocument?: any;
  
  // Output
  outDir: string;
  
  // Client integration
  clientDir?: string;
  
  // URN configuration
  versionSlug?: string;
  serviceSlug?: string;
  
  // Schema configuration
  defaultResponseStatusCodes?: number[];
  
  // Import style
  imports?: "js" | "ts" | "bare";
}

runGenerationPipeline

Run complete pipeline: client + OpenAPI + gateway in one pass.

import { runGenerationPipeline } from "@techspokes/typescript-wsdl-client";

const { compiled, openapiDoc } = await runGenerationPipeline({
  wsdl: "./wsdl/Hotel.wsdl",
  catalogOut: "./build/hotel-catalog.json",
  clientOutDir: "./src/services/hotel",
  compiler: {
    imports: "js",
    primitive: {
      int64As: "number",
      decimalAs: "string"
    }
  },
  openapi: {
    outFile: "./docs/hotel-api.json",
    format: "both",
    servers: ["https://api.example.com/v1"],
    tagStyle: "service"
  },
  gateway: {
    outDir: "./src/gateway/hotel",
    versionSlug: "v1",
    serviceSlug: "hotel"
  }
});

Type Signature:

// noinspection JSAnnotator
function runGenerationPipeline(opts: PipelineOptions): Promise<{
  compiled: CompiledCatalog;
  openapiDoc?: any;
}>;

Options (PipelineOptions):

interface PipelineOptions {
  // Input
  wsdl: string;
  
  // Catalog (always generated)
  catalogOut: string;
  
  // Client generation (optional)
  clientOutDir?: string;
  compiler?: Partial<CompilerOptions>;
  
  // OpenAPI generation (optional)
  openapi?: Omit<GenerateOpenAPIOptions, "wsdl" | "catalogFile" | "compiledCatalog"> &