@techspokes/typescript-wsdl-client 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,69 +4,30 @@
4
4
  [![CI](https://github.com/techspokes/typescript-wsdl-client/actions/workflows/ci.yml/badge.svg)](https://github.com/techspokes/typescript-wsdl-client/actions/workflows/ci.yml)
5
5
  [![npm version](https://img.shields.io/npm/v/@techspokes%2Ftypescript-wsdl-client.svg)](https://www.npmjs.com/package/@techspokes/typescript-wsdl-client)
6
6
  [![npm downloads](https://img.shields.io/npm/dm/@techspokes%2Ftypescript-wsdl-client.svg)](https://www.npmjs.com/package/@techspokes/typescript-wsdl-client)
7
- [![GitHub Stars](https://img.shields.io/github/stars/techspokes/typescript-wsdl-client?style=social)](https://github.com/techspokes/typescript-wsdl-client/stargazers)
8
- [![GitHub Forks](https://img.shields.io/github/forks/techspokes/typescript-wsdl-client?style=social)](https://github.com/techspokes/typescript-wsdl-client/network/members)
9
- [![TechSpokes Org](https://img.shields.io/badge/org-techspokes-181717?logo=github)](https://github.com/techspokes)
10
- [![Sponsor](https://img.shields.io/badge/sponsor-GitHub-blue?logo=github-sponsors)](https://github.com/sponsors/TechSpokes)
11
7
 
12
- > **Transform complex WSDL/XSD definitions into type-safe TypeScript SOAP clients with optional OpenAPI 3.1 specs and production-ready REST gateways.**
8
+ Generate type-safe TypeScript SOAP clients, OpenAPI 3.1 specs, and production-ready Fastify REST gateways from WSDL/XSD definitions.
13
9
 
14
- ## Use This If You Need...
10
+ ## Use This If You Need
15
11
 
16
- - ✅ **TypeScript-first SOAP clients** Strongly typed, ergonomic client generation from WSDL
17
- - ✅ **OpenAPI 3.1 specs** — Generate REST API documentation that mirrors your TypeScript types
18
- - ✅ **REST gateway over SOAP** — Production-ready Fastify handlers with automatic request/response transformation
19
- - ✅ **CI-friendly determinism** — Stable, diff-friendly output for safe regeneration in version control
20
- - ✅ **Predictable modeling** — Flattened attributes, consistent `$value` convention, inheritance resolution
12
+ - TypeScript-first SOAP clients with full type safety
13
+ - OpenAPI 3.1 specs that mirror your TypeScript types
14
+ - REST gateway over SOAP with automatic request/response transformation
15
+ - CI-friendly deterministic output for safe regeneration in version control
21
16
 
22
- **Vendor**: [TechSpokes](https://www.techspokes.com) · **Maintainer**: Serge Liatko ([@sergeliatko](https://github.com/sergeliatko))
17
+ ## Quick Start
23
18
 
24
- ---
25
-
26
- ## Table of Contents
27
-
28
- - [Installation](#installation)
29
- - [Quick Start (60 Seconds)](#quick-start-60-seconds)
30
- - [What You Get (Outputs)](#what-you-get-outputs)
31
- - [Core Concepts](#core-concepts)
32
- - [Common Workflows](#common-workflows)
33
- - [Command Reference](#command-reference)
34
- - [pipeline (Recommended)](#command-pipeline-recommended)
35
- - [client](#command-client)
36
- - [openapi](#command-openapi)
37
- - [gateway](#command-gateway)
38
- - [app](#command-app)
39
- - [compile (Advanced)](#command-compile-advanced)
40
- - [Configuration Files](#configuration-files)
41
- - [Working With Generated Clients](#working-with-generated-clients)
42
- - [Production Concerns](#production-concerns)
43
- - [Programmatic API](#programmatic-api)
44
- - [Troubleshooting](#troubleshooting)
45
- - [Contributing](#contributing)
46
- - [License](#license)
47
- - [Support](#support)
48
-
49
- ---
50
-
51
- ## Installation
19
+ ### Installation
52
20
 
53
21
  ```bash
54
22
  npm install --save-dev @techspokes/typescript-wsdl-client
55
- npm install soap # Runtime dependency for SOAP calls
23
+ npm install soap
56
24
  ```
57
25
 
58
- **Requirements**:
59
- - Node.js 20.0.0 or later
60
- - `soap` package (runtime dependency for generated clients)
26
+ Requirements: Node.js 20+ and the `soap` package as a runtime dependency.
61
27
 
62
- ---
63
-
64
- ## Quick Start (60 Seconds)
65
-
66
- Generate a complete SOAP-to-REST stack in one command:
28
+ ### Generate a Complete Stack
67
29
 
68
30
  ```bash
69
- # Generate client, OpenAPI spec, gateway, and runnable app
70
31
  npx wsdl-tsc pipeline \
71
32
  --wsdl-source examples/minimal/weather.wsdl \
72
33
  --client-dir ./tmp/client \
@@ -77,2223 +38,75 @@ npx wsdl-tsc pipeline \
77
38
  --generate-app
78
39
  ```
79
40
 
80
- **Start the server:**
41
+ This parses the WSDL, generates a typed SOAP client, creates an OpenAPI 3.1 spec, builds Fastify gateway handlers, and creates a runnable application.
42
+
43
+ ### Run and Test
81
44
 
82
45
  ```bash
83
- cd tmp/app
84
- cp .env.example .env
85
- # Edit .env to set WSDL_SOURCE if needed
86
- npx tsx server.js
46
+ cd tmp/app && cp .env.example .env && npx tsx server.js
87
47
  ```
88
48
 
89
- **Test it:**
90
-
91
49
  ```bash
92
- # Health check
93
50
  curl http://localhost:3000/health
94
-
95
- # Get OpenAPI spec
96
51
  curl http://localhost:3000/openapi.json | jq .
97
-
98
- # Call a SOAP operation via REST
99
52
  curl -X POST http://localhost:3000/get-weather-information \
100
- -H "Content-Type: application/json" \
101
- -d '{}'
102
- ```
103
-
104
- **What just happened?**
105
- 1. Parsed the WSDL and compiled types
106
- 2. Generated a TypeScript SOAP client with full type safety
107
- 3. Created an OpenAPI 3.1 spec matching the client types
108
- 4. Built Fastify gateway handlers that call SOAP and return JSON
109
- 5. Created a runnable Express-style app with health/OpenAPI endpoints
110
-
111
- ---
112
-
113
- ## What You Get (Outputs)
114
-
115
- ### TypeScript SOAP Client
116
-
117
- ```
118
- client/
119
- ├── client.ts # Strongly-typed SOAP client wrapper with methods
120
- ├── types.ts # Flattened interfaces, type aliases, and enums
121
- ├── utils.ts # Runtime metadata for JSON→SOAP conversion
122
- └── catalog.json # Compiled schema representation (reusable)
123
- ```
124
-
125
- **Example usage:**
126
-
127
- ```typescript
128
- import { Weather } from './client/client.js';
129
-
130
- const client = new Weather({
131
- source: 'https://example.com/weather.wsdl',
132
- });
133
-
134
- const result = await client.GetCityWeatherByZIP({ ZIP: '10001' });
135
- console.log(result.GetCityWeatherByZIPResult);
136
- ```
137
-
138
- ### OpenAPI 3.1 Specification
139
-
140
- ```
141
- openapi.json # or .yaml — Complete REST API documentation
142
- ```
143
-
144
- - Mirrors exact TypeScript type structure
145
- - All responses wrapped in standard envelope (status, message, data, error)
146
- - Deterministic ordering for version control
147
- - Validates with `swagger-parser` by default
148
-
149
- ### Fastify REST Gateway
150
-
151
- ```
152
- gateway/
153
- ├── schemas/
154
- │ ├── models/ # JSON Schema components with URN IDs
155
- │ └── operations/ # Request/response validation schemas
156
- ├── routes/ # Route handlers (fully implemented)
157
- ├── schemas.ts # Schema registration module
158
- ├── routes.ts # Route aggregator
159
- ├── runtime.ts # Envelope builders, error handlers
160
- └── plugin.ts # Fastify plugin wrapper
161
- ```
162
-
163
- **Example integration:**
164
-
165
- ```typescript
166
- import Fastify from 'fastify';
167
- import weatherGateway from './gateway/plugin.js';
168
- import { Weather } from './client/client.js';
169
-
170
- const app = Fastify({ logger: true });
171
- const client = new Weather({ source: 'weather.wsdl' });
172
-
173
- await app.register(weatherGateway, { client });
174
- await app.listen({ port: 3000 });
175
- ```
176
-
177
- ### Runnable Application
178
-
179
- ```
180
- app/
181
- ├── server.js # Main entry point
182
- ├── config.js # Configuration with env var support
183
- ├── .env.example # Environment template
184
- ├── README.md # Usage instructions
185
- └── openapi.json # OpenAPI spec (when --openapi-mode=copy)
186
- ```
187
-
188
- ### Standard Response Envelope
189
-
190
- All gateway responses follow this structure:
191
-
192
- **Success:**
193
- ```json
194
- {
195
- "status": "SUCCESS",
196
- "message": null,
197
- "data": { /* SOAP response */ },
198
- "error": null
199
- }
200
- ```
201
-
202
- **Error:**
203
- ```json
204
- {
205
- "status": "ERROR",
206
- "message": "Request validation failed",
207
- "data": null,
208
- "error": {
209
- "code": "VALIDATION_ERROR",
210
- "message": "Request validation failed",
211
- "details": { /* validation errors */ }
212
- }
213
- }
214
- ```
215
-
216
- ---
217
-
218
- ## Core Concepts
219
-
220
- ### Flattening and `$value`
221
-
222
- **Attributes and elements become peer properties** — No nested wrapper noise:
223
-
224
- ```xml
225
- <!-- WSDL -->
226
- <xs:complexType name="Price">
227
- <xs:simpleContent>
228
- <xs:extension base="xs:decimal">
229
- <xs:attribute name="currency" type="xs:string"/>
230
- </xs:extension>
231
- </xs:simpleContent>
232
- </xs:complexType>
233
- ```
234
-
235
- ```typescript
236
- // Generated TypeScript
237
- interface Price {
238
- currency?: string; // attribute
239
- $value: string; // text content (decimal mapped to string by default)
240
- }
241
- ```
242
-
243
- ### Primitive Mapping Defaults (String-First Safety)
244
-
245
- Prevents precision loss and parsing errors at the cost of convenience:
246
-
247
- | XSD Type | Default | Override Options | When to Override |
248
- |---------------|----------|--------------------|----------------------------------------|
249
- | `xs:long` | `string` | `number`, `bigint` | Use `number` if values fit JS range |
250
- | `xs:integer` | `string` | `number` | Use `string` for arbitrary-size ints |
251
- | `xs:decimal` | `string` | `number` | Use `string` for precise decimals |
252
- | `xs:dateTime` | `string` | `Date` | Use `Date` if runtime parsing is okay |
253
-
254
- **Override with flags:**
255
- - `--client-int64-as number`
256
- - `--client-decimal-as string`
257
- - `--client-date-as Date`
258
-
259
- ### Deterministic Generation
260
-
261
- All output is **stable and diff-friendly** for CI/CD:
262
-
263
- - ✅ Sorted type declarations
264
- - ✅ Sorted OpenAPI paths, schemas, parameters
265
- - ✅ Sorted JSON schema keys
266
- - ✅ Stable alias resolution
267
- - ✅ Consistent ordering of imports
268
-
269
- Regenerate safely without spurious diffs in version control.
270
-
271
- ### Catalog as Intermediate Artifact
272
-
273
- `catalog.json` is the compiled representation of your WSDL:
274
-
275
- - **Debuggable** — Inspect types, operations, and metadata as JSON
276
- - **Cacheable** — Reuse across client/OpenAPI/gateway generation
277
- - **Co-located** — Automatically placed alongside generated output
278
-
279
- **Common locations:**
280
- - `client` command: `{client-dir}/catalog.json`
281
- - `openapi` command: `{openapi-dir}/catalog.json`
282
- - `pipeline` command: First available output directory
283
-
284
- ---
285
-
286
- ## Common Workflows
287
-
288
- ### Which Command Should I Run?
289
-
290
- | I Want... | Use Command | Example |
291
- |-----------------------------------------------|--------------|----------------------------------------------------------------------------------------------------------------------|
292
- | **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` |
293
- | **Only a TypeScript SOAP client** | `client` | `npx wsdl-tsc client --wsdl-source service.wsdl --client-dir ./client` |
294
- | **Only OpenAPI spec (for docs or SDKs)** | `openapi` | `npx wsdl-tsc openapi --wsdl-source service.wsdl --openapi-file ./api.json` |
295
- | **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` |
296
- | **Runnable server for testing** | `app` | `npx wsdl-tsc app --client-dir ./client --gateway-dir ./gateway --openapi-file ./api.json` |
297
- | **Debug/inspect WSDL compilation** | `compile` | `npx wsdl-tsc compile --wsdl-source service.wsdl --catalog-file ./catalog.json` |
298
-
299
- ### Workflow 1: Generate Everything (Recommended)
300
-
301
- Use `pipeline` for complete stack generation:
302
-
303
- ```bash
304
- npx wsdl-tsc pipeline \
305
- --wsdl-source examples/minimal/weather.wsdl \
306
- --client-dir ./src/services/weather \
307
- --openapi-file ./docs/weather-api.json \
308
- --gateway-dir ./src/gateway/weather \
309
- --gateway-service-name weather \
310
- --gateway-version-prefix v1
311
- ```
312
-
313
- **Output:**
314
- - Client: `./src/services/weather/client.ts`, `types.ts`, `utils.ts`, `catalog.json`
315
- - OpenAPI: `./docs/weather-api.json`
316
- - Gateway: `./src/gateway/weather/` (routes, schemas, plugin)
317
-
318
- ### Workflow 2: SOAP Client Only
319
-
320
- Generate TypeScript client for direct SOAP integration:
321
-
322
- ```bash
323
- npx wsdl-tsc client \
324
- --wsdl-source ./wsdl/Hotel.wsdl \
325
- --client-dir ./src/services/hotel
326
- ```
327
-
328
- **Usage:**
329
-
330
- ```typescript
331
- import soap from 'soap';
332
- import { Hotel } from './src/services/hotel/client.js';
333
-
334
- const client = new Hotel({
335
- source: 'https://example.com/hotel.wsdl',
336
- security: new soap.WSSecurity('username', 'password'),
337
- });
338
-
339
- const result = await client.SearchAvailableRooms({
340
- checkIn: '2024-01-15',
341
- checkOut: '2024-01-20',
342
- guests: 2,
343
- });
344
- ```
345
-
346
- ### Workflow 3: OpenAPI for Documentation
347
-
348
- Generate OpenAPI spec for API documentation or SDK generation:
349
-
350
- ```bash
351
- npx wsdl-tsc openapi \
352
- --wsdl-source ./wsdl/Booking.wsdl \
353
- --openapi-file ./docs/booking-api.yaml \
354
- --openapi-format yaml \
355
- --openapi-title "Hotel Booking API" \
356
- --openapi-version "1.0.0" \
357
- --openapi-servers https://api.example.com/v1
358
- ```
359
-
360
- **Use the spec:**
361
- - Import into Postman, Insomnia, or Swagger UI
362
- - Generate client SDKs with OpenAPI Generator
363
- - Share as REST API documentation
364
-
365
- ### Workflow 4: REST Gateway Over SOAP
366
-
367
- Build a REST API layer over legacy SOAP services:
368
-
369
- ```bash
370
- # 1. Generate client + OpenAPI
371
- npx wsdl-tsc pipeline \
372
- --wsdl-source ./wsdl/Legacy.wsdl \
373
- --client-dir ./src/services/legacy \
374
- --openapi-file ./docs/legacy-api.json
375
-
376
- # 2. Generate gateway
377
- npx wsdl-tsc gateway \
378
- --openapi-file ./docs/legacy-api.json \
379
- --client-dir ./src/services/legacy \
380
- --gateway-dir ./src/gateway/legacy \
381
- --gateway-service-name legacy \
382
- --gateway-version-prefix v1
383
- ```
384
-
385
- **Or in one command:**
386
-
387
- ```bash
388
- npx wsdl-tsc pipeline \
389
- --wsdl-source ./wsdl/Legacy.wsdl \
390
- --client-dir ./src/services/legacy \
391
- --openapi-file ./docs/legacy-api.json \
392
- --gateway-dir ./src/gateway/legacy \
393
- --gateway-service-name legacy \
394
- --gateway-version-prefix v1
395
- ```
396
-
397
- ### Workflow 5: CI/CD Integration
398
-
399
- Cache compiled catalog for faster multi-stage builds:
400
-
401
- ```bash
402
- # Stage 1: Compile catalog (cacheable)
403
- npx wsdl-tsc compile \
404
- --wsdl-source ./wsdl/Service.wsdl \
405
- --catalog-file ./build/service-catalog.json
406
-
407
- # Stage 2: Generate client from catalog
408
- npx wsdl-tsc client \
409
- --catalog-file ./build/service-catalog.json \
410
- --client-dir ./src/services/service
411
-
412
- # Stage 3: Generate OpenAPI from catalog
413
- npx wsdl-tsc openapi \
414
- --catalog-file ./build/service-catalog.json \
415
- --openapi-file ./docs/service-api.json
416
- ```
417
-
418
- ### Workflow 6: Debugging Complex WSDL
419
-
420
- Inspect compiled types and operations:
421
-
422
- ```bash
423
- # Compile to catalog
424
- npx wsdl-tsc compile \
425
- --wsdl-source ./wsdl/Complex.wsdl \
426
- --catalog-file ./debug/catalog.json
427
-
428
- # Inspect types
429
- cat ./debug/catalog.json | jq '.types'
430
-
431
- # Inspect operations
432
- cat ./debug/catalog.json | jq '.operations'
433
- ```
434
-
435
- ---
436
-
437
- ## Command Reference
438
-
439
- The tool provides **six commands** for different integration scenarios. Commands are listed in **recommended order of use**:
440
-
441
- | Command | Purpose | Typical Use Case |
442
- |------------|----------------------------------------------------------------|-----------------------------------------------|
443
- | `pipeline` | Run full pipeline: client + OpenAPI + gateway (+ app optional) | **CI/CD automation, complete stack generation (recommended)** |
444
- | `client` | Generate TypeScript SOAP client from WSDL or catalog | Standard SOAP integration |
445
- | `openapi` | Generate OpenAPI 3.1 spec from WSDL or catalog | Documentation, REST proxies, API gateways |
446
- | `gateway` | Generate Fastify gateway with full handlers from OpenAPI spec | Production REST gateway with SOAP integration |
447
- | `app` | Generate runnable Fastify app from client + gateway + OpenAPI | Local testing, quick iteration, demos |
448
- | `compile` | Parse WSDL and emit `catalog.json` only | Debugging, inspection, or multi-stage builds (advanced) |
449
-
450
- ---
451
-
452
- ### Command: `pipeline` (Recommended)
53
+ -H "Content-Type: application/json" -d '{}'
54
+ ```
55
+
56
+ ## What You Get
57
+
58
+ | Output | Files | Purpose |
59
+ |--------|-------|---------|
60
+ | TypeScript Client | client.ts, types.ts, utils.ts | Typed SOAP operations |
61
+ | OpenAPI 3.1 Spec | openapi.json or .yaml | REST API documentation |
62
+ | Fastify Gateway | plugin.ts, routes/, schemas/ | Production REST handlers |
63
+ | Catalog | catalog.json | Compiled WSDL (debuggable, cacheable) |
64
+
65
+ ## Commands
66
+
67
+ | Command | Purpose |
68
+ |---------|---------|
69
+ | `pipeline` | Full stack generation (recommended) |
70
+ | `client` | TypeScript SOAP client only |
71
+ | `openapi` | OpenAPI 3.1 spec only |
72
+ | `gateway` | Fastify REST gateway from OpenAPI |
73
+ | `app` | Runnable Fastify application |
74
+ | `compile` | Parse WSDL to catalog.json (advanced) |
75
+
76
+ See [CLI Reference](docs/cli-reference.md) for all flags and examples.
77
+
78
+ ## Documentation
79
+
80
+ | Guide | Description |
81
+ |-------|-------------|
82
+ | [CLI Reference](docs/cli-reference.md) | All 6 commands with flags and examples |
83
+ | [Programmatic API](docs/api-reference.md) | TypeScript functions for build tools |
84
+ | [Core Concepts](docs/concepts.md) | Flattening, $value, primitives, determinism |
85
+ | [Gateway Guide](docs/gateway-guide.md) | Fastify integration and error handling |
86
+ | [Configuration](docs/configuration.md) | Security, tags, operations config files |
87
+ | [Production Guide](docs/production.md) | CI/CD, validation, logging, limitations |
88
+ | [Troubleshooting](docs/troubleshooting.md) | Common issues and debugging |
89
+ | [Working With Generated Code](docs/generated-code.md) | Using clients and types |
90
+ | [Architecture](docs/architecture.md) | Internal pipeline for contributors |
91
+ | [Migration Guide](docs/migration.md) | Upgrading between versions |
453
92
 
454
- **Purpose**: Run the complete generation pipeline in a single pass: WSDL parsing → TypeScript client → OpenAPI spec → Fastify gateway (+ app optional).
455
-
456
- **When to use**:
457
- - CI/CD automation
458
- - Complete stack generation
459
- - Ensuring all artifacts are generated from the same WSDL parse
460
- - One-command development workflows
461
-
462
- #### Usage
463
-
464
- ```bash
465
- npx wsdl-tsc pipeline \
466
- --wsdl-source <file|url> \
467
- [--catalog-file <path>] \
468
- [--client-dir <path>] \
469
- [--openapi-file <path>] \
470
- [--gateway-dir <path>] \
471
- [options]
472
- ```
473
-
474
- #### Required Flags
475
-
476
- | Flag | Description |
477
- |---------------------|----------------------------------------------------------------------|
478
- | `--wsdl-source` | Path or URL to WSDL file |
479
-
480
- #### Output Flags
481
-
482
- | Flag | Default | Description |
483
- |---------------------|---------------------------------------------|---------------------------------------------------|
484
- | `--catalog-file` | Co-located with first output (see below) | Output path for `catalog.json` (always generated) |
485
-
486
- **Catalog Default Location**: The catalog is automatically placed alongside the first available output:
487
- - With `--client-dir`: `{client-dir}/catalog.json`
488
- - With `--openapi-file` only: `{openapi-file-dir}/catalog.json`
489
- - With `--gateway-dir` only: `{gateway-dir}/catalog.json`
490
-
491
- **Note**: At least one of `--client-dir`, `--openapi-file`, or `--gateway-dir` must be provided.
492
-
493
- #### Generation Control Flags
494
-
495
- | Flag | Description |
496
- |-------------------------|------------------------------------------------|
497
- | `--client-dir` | Generate TypeScript client in this directory |
498
- | `--openapi-file` | Generate OpenAPI spec at this path |
499
- | `--gateway-dir` | Generate Fastify gateway in this directory |
500
- | `--generate-app` | Generate runnable app (requires gateway) |
501
-
502
- #### Optional Flags
503
-
504
- All flags from `client`, `openapi`, and `gateway` commands are supported. Key flags:
505
-
506
- **Client Flags:**
507
- - `--import-extensions` (default: `js`)
508
- - `--client-attributes-key` (default: `$attributes`)
509
- - `--client-class-name`
510
- - `--client-int64-as` (default: `string`)
511
- - `--client-bigint-as` (default: `string`)
512
- - `--client-decimal-as` (default: `string`)
513
- - `--client-date-as` (default: `string`)
514
- - `--client-choice-mode` (default: `all-optional`)
515
- - `--client-fail-on-unresolved` (default: `false`)
516
- - `--client-nillable-as-optional` (default: `false`)
517
-
518
- **OpenAPI Flags:**
519
- - `--openapi-format` (default: `json`)
520
- - `--openapi-title`
521
- - `--openapi-version` (default: `0.0.0`)
522
- - `--openapi-description`
523
- - `--openapi-servers` (default: `/`)
524
- - `--openapi-base-path`
525
- - `--openapi-path-style` (default: `kebab`)
526
- - `--openapi-method` (default: `post`)
527
- - `--openapi-tag-style` (default: `default`)
528
- - `--openapi-closed-schemas` (default: `false`)
529
- - `--openapi-prune-unused-schemas` (default: `false`)
530
- - `--openapi-envelope-namespace` (default: `ResponseEnvelope`)
531
- - `--openapi-error-namespace` (default: `ErrorObject`)
532
- - `--openapi-validate` (default: `true`)
533
- - `--openapi-security-config-file`
534
- - `--openapi-tags-file`
535
- - `--openapi-ops-file`
536
-
537
- **Gateway Flags:**
538
- - `--gateway-service-name` (required if `--gateway-dir` provided)
539
- - `--gateway-version-prefix` (required if `--gateway-dir` provided)
540
- - `--gateway-default-status-codes`
541
- - `--gateway-stub-handlers` (default: `false`)
542
-
543
- #### Examples
544
-
545
- **Complete Stack Generation:**
546
-
547
- ```bash
548
- npx wsdl-tsc pipeline \
549
- --wsdl-source examples/minimal/weather.wsdl \
550
- --client-dir tmp/client \
551
- --openapi-file tmp/openapi.json \
552
- --gateway-dir tmp/gateway \
553
- --gateway-service-name weather \
554
- --gateway-version-prefix v1
555
- ```
556
-
557
- **With App Generation:**
558
-
559
- ```bash
560
- npx wsdl-tsc pipeline \
561
- --wsdl-source examples/minimal/weather.wsdl \
562
- --client-dir tmp/client \
563
- --openapi-file tmp/openapi.json \
564
- --gateway-dir tmp/gateway \
565
- --gateway-service-name weather \
566
- --gateway-version-prefix v1 \
567
- --generate-app
568
- ```
569
-
570
- **Client + OpenAPI Only:**
571
-
572
- ```bash
573
- npx wsdl-tsc pipeline \
574
- --wsdl-source https://example.com/Hotel.wsdl \
575
- --client-dir ./build/client \
576
- --openapi-file ./docs/hotel-api.json \
577
- --openapi-format both
578
- ```
579
-
580
- **With Full Configuration:**
581
-
582
- ```bash
583
- npx wsdl-tsc pipeline \
584
- --wsdl-source ./wsdl/Booking.wsdl \
585
- --client-dir ./build/client \
586
- --openapi-file ./docs/booking-api \
587
- --gateway-dir ./build/gateway \
588
- --openapi-format both \
589
- --openapi-servers https://api.example.com/v1 \
590
- --openapi-base-path /booking \
591
- --openapi-security-config-file ./config/security.json \
592
- --gateway-service-name booking \
593
- --gateway-version-prefix v1 \
594
- --client-int64-as number \
595
- --client-decimal-as string
596
- ```
597
-
598
- #### Pipeline Workflow
599
-
600
- The pipeline command executes these steps in order:
601
-
602
- 1. **Parse WSDL** → Load and validate WSDL document
603
- 2. **Compile Catalog** → Generate intermediate representation
604
- 3. **Emit Catalog** → Write `catalog.json` (always)
605
- 4. **Generate Client** → Emit TypeScript client files (if `--client-dir`)
606
- 5. **Generate OpenAPI** → Create OpenAPI spec (if `--openapi-file`)
607
- 6. **Generate Gateway** → Create Fastify gateway code (if `--gateway-dir`)
608
- 7. **Generate App** → Create runnable application (if `--generate-app`)
609
-
610
- All steps share the same parsed WSDL and compiled catalog, ensuring consistency.
611
-
612
- ---
613
-
614
- ### Command: `client`
615
-
616
- **Purpose**: Generate strongly-typed TypeScript SOAP client code from WSDL or a pre-compiled catalog.
617
-
618
- **When to use**:
619
- - Standard SOAP integration (most common use case)
620
- - When you need TypeScript types and client methods for SOAP operations
621
- - When building applications that consume SOAP services
622
-
623
- ### Usage
624
-
625
- ```bash
626
- npx wsdl-tsc client --wsdl-source <file|url> --client-dir <path> [options]
627
- # OR
628
- npx wsdl-tsc client --catalog-file <path> --client-dir <path> [options]
629
- ```
630
-
631
- ### Required Flags
632
-
633
- | Flag | Description |
634
- |------------------|-------------------------------------------------|
635
- | `--wsdl-source` | Path or URL to WSDL file (see note below) |
636
- | `--client-dir` | Output directory for generated TypeScript files |
637
-
638
- ### Optional Input Flags
639
-
640
- | Flag | Default | Description |
641
- |------------------|-----------------------------|----------------------------------------------------------------------|
642
- | `--catalog-file` | `{client-dir}/catalog.json` | Path to pre-compiled `catalog.json` (when not using `--wsdl-source`) |
643
-
644
- **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`.
645
-
646
- ### Generated Files
647
-
648
- | File | Purpose |
649
- |----------------|------------------------------------------------------------------------------|
650
- | `client.ts` | Strongly-typed SOAP client wrapper with one method per operation |
651
- | `types.ts` | Flattened TypeScript interfaces, type aliases, and enums |
652
- | `utils.ts` | Runtime metadata for JSON to SOAP conversion (attribute mapping, occurrence) |
653
- | `catalog.json` | (When using `--wsdl-source`) Generated in client directory by default |
654
-
655
- ### Optional Flags
656
-
657
- All flags from `compile` command, plus:
658
-
659
- | Flag | Default | Description |
660
- |---------------------------------|----------------|-------------------------------------|
661
- | `--import-extensions` | `js` | Import style: `js`, `ts`, or `bare` |
662
- | `--client-attributes-key` | `$attributes` | Attribute bag key |
663
- | `--client-class-name` | (derived) | Override client class name |
664
- | `--client-int64-as` | `string` | Map 64-bit integers |
665
- | `--client-bigint-as` | `string` | Map arbitrary-size integers |
666
- | `--client-decimal-as` | `string` | Map `xs:decimal` |
667
- | `--client-date-as` | `string` | Map date/time types |
668
- | `--client-choice-mode` | `all-optional` | Choice element strategy |
669
- | `--client-fail-on-unresolved` | `false` | Fail on unresolved references |
670
- | `--client-nillable-as-optional` | `false` | Treat nillable as optional |
671
-
672
- ### Examples
673
-
674
- #### Basic Generation (Default Catalog Location)
675
-
676
- ```bash
677
- npx wsdl-tsc client \
678
- --wsdl-source examples/minimal/weather.wsdl \
679
- --client-dir tmp/client
680
- ```
681
-
682
- **Output**: Generates client files and catalog at `tmp/client/catalog.json`.
683
-
684
- #### With Custom Catalog Path
685
-
686
- ```bash
687
- npx wsdl-tsc client \
688
- --wsdl-source examples/minimal/weather.wsdl \
689
- --client-dir tmp/client \
690
- --catalog-file build/shared-catalog.json
691
- ```
692
-
693
- #### With Custom Numeric Mappings
694
-
695
- ```bash
696
- npx wsdl-tsc client \
697
- --wsdl-source https://example.com/Hotel.wsdl \
698
- --client-dir ./src/integrations/soap/hotel \
699
- --client-int64-as number \
700
- --client-decimal-as string \
701
- --client-date-as string
702
- ```
703
-
704
- **Output**: Catalog generated at `./src/integrations/soap/hotel/catalog.json`.
705
-
706
- #### From Pre-compiled Catalog
707
-
708
- ```bash
709
- # First compile the catalog
710
- npx wsdl-tsc compile --wsdl-source https://example.com/Hotel.wsdl --catalog-file build/hotel-catalog.json
711
-
712
- # Then generate client from catalog
713
- npx wsdl-tsc client \
714
- --catalog-file build/hotel-catalog.json \
715
- --client-dir ./src/services/hotel
716
- ```
717
-
718
- ### Key Modeling Rules
719
-
720
- - **Attributes & elements** become peer properties (flattened)
721
- - **Text content** becomes `$value` property
722
- - **Required attributes**: `use!="optional"`; elements `minOccurs>=1`
723
- - **Multiplicity**: `maxOccurs>1` or `unbounded` become arrays
724
- - **Nillable**: `nillable="true"` preserved (optionally model as optional with `--client-nillable-as-optional`)
725
- - **Inheritance**: extensions merged or emitted as `extends`; simpleContent base collapsed logically
726
-
727
- ---
728
-
729
- ### Command: `openapi`
730
-
731
- **Purpose**: Generate OpenAPI 3.1 specification from WSDL or a pre-compiled catalog, mirroring the exact TypeScript type structure.
732
-
733
- **When to use**:
734
- - Creating REST API documentation for SOAP services
735
- - Building API gateways or proxies
736
- - Enabling REST-style access to SOAP operations
737
- - Generating client SDKs in other languages
738
-
739
- ### Usage
740
-
741
- ```bash
742
- npx wsdl-tsc openapi --wsdl-source <file|url> --openapi-file <path> [options]
743
- # OR
744
- npx wsdl-tsc openapi --catalog-file <path> --openapi-file <path> [options]
745
- ```
746
-
747
- ### Required Flags
748
-
749
- | Flag | Description |
750
- |---------------------|----------------------------------------------------|
751
- | `--openapi-file` | Output path for OpenAPI specification |
752
-
753
- ### Input Source Flags (Mutually Exclusive)
754
-
755
- | Flag | Default | Description |
756
- |---------------------|--------------------------------------|----------------------------------------------------|
757
- | `--wsdl-source` | (none) | Path or URL to WSDL file |
758
- | `--catalog-file` | `{openapi-file-dir}/catalog.json` | Path to pre-compiled `catalog.json` |
759
-
760
- **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.
761
-
762
- ### Core Optional Flags
763
-
764
- | Flag | Default | Description |
765
- |-------------------------------|-----------|----------------------------------------------------------|
766
- | `--openapi-format` | `json` | Output format: `json`, `yaml`, or `both` |
767
- | `--openapi-title` | (derived) | API title in `info` section |
768
- | `--openapi-version` | `0.0.0` | API version in `info.version` |
769
- | `--openapi-description` | (empty) | API description in `info` section |
770
- | `--openapi-servers` | `/` | Comma-separated server URLs |
771
- | `--openapi-base-path` | (empty) | Base path prefix (e.g., `/v1/soap`) |
772
- | `--openapi-validate` | `true` | Validate spec with `swagger-parser` |
773
-
774
- ### Path & Schema Customization
775
-
776
- | Flag | Default | Description |
777
- |----------------------------------|-----------|--------------------------------------------------|
778
- | `--openapi-path-style` | `kebab` | Path transformation: `kebab`, `asis`, or `lower` |
779
- | `--openapi-method` | `post` | Default HTTP method for operations |
780
- | `--openapi-tag-style` | `default` | Tag inference: `default`, `service`, or `first` |
781
- | `--openapi-closed-schemas` | `false` | Add `additionalProperties: false` to all schemas |
782
- | `--openapi-prune-unused-schemas` | `false` | Emit only schemas referenced by operations |
783
-
784
- ### Response Envelope Customization
785
-
786
- | Flag | Default | Description |
787
- |--------------------------------|--------------------|---------------------------------------------|
788
- | `--openapi-envelope-namespace` | `ResponseEnvelope` | Override envelope component name suffix |
789
- | `--openapi-error-namespace` | `ErrorObject` | Override error object component name suffix |
790
-
791
- ### Configuration Files
792
-
793
- | Flag | Description |
794
- |-----------------------------------|-------------------------------------------------------|
795
- | `--openapi-security-config-file` | Path to `security.json` (schemes, headers, overrides) |
796
- | `--openapi-tags-file` | Path to `tags.json` (explicit operation → tag map) |
797
- | `--openapi-ops-file` | Path to `ops.json` (per-operation overrides) |
798
-
799
- ### Examples
800
-
801
- #### Basic JSON Output
802
-
803
- ```bash
804
- npx wsdl-tsc openapi \
805
- --wsdl-source examples/minimal/weather.wsdl \
806
- --openapi-file ./docs/weather-api.json
807
- ```
808
-
809
- #### Multi-Format with Validation
810
-
811
- ```bash
812
- npx wsdl-tsc openapi \
813
- --wsdl-source https://example.com/Hotel.wsdl \
814
- --openapi-file ./docs/hotel-api \
815
- --openapi-format both \
816
- --openapi-servers https://api.example.com/v1,https://api-staging.example.com/v1 \
817
- --openapi-base-path /soap
818
- ```
819
-
820
- #### From Pre-compiled Catalog
93
+ ## Contributing
821
94
 
822
- ```bash
823
- npx wsdl-tsc openapi \
824
- --catalog-file ./artifacts/hotel-catalog.json \
825
- --openapi-file ./docs/hotel-api.json \
826
- --openapi-format json
827
- ```
828
-
829
- #### With Custom Configuration
830
-
831
- ```bash
832
- npx wsdl-tsc openapi \
833
- --wsdl-source ./wsdl/Booking.wsdl \
834
- --openapi-file ./docs/booking-api.yaml \
835
- --openapi-format yaml \
836
- --openapi-title "Hotel Booking API" \
837
- --openapi-version "1.2.0" \
838
- --openapi-description "REST API for hotel booking SOAP service" \
839
- --openapi-security-config-file ./config/security.json \
840
- --openapi-tags-file ./config/tags.json \
841
- --openapi-path-style kebab \
842
- --openapi-method post \
843
- --openapi-tag-style service
844
- ```
845
-
846
- ### Standard Response Envelope
847
-
848
- All responses are wrapped in a **standard envelope** for consistency and debuggability (always-on since 0.7.1):
849
-
850
- #### Base Envelope Structure
851
-
852
- ```typescript
853
- {
854
- status: string; // e.g., "SUCCESS", "FAILURE", "PENDING"
855
- message: string | null; // diagnostic message (not for end-user UI)
856
- data: T | null; // operation payload (typed per operation)
857
- error: ErrorObject | null; // populated on failures
858
- }
859
- ```
860
-
861
- #### Error Object Structure
862
-
863
- ```typescript
864
- {
865
- code: string; // stable machine error code
866
- message: string; // brief description
867
- details: object | null; // arbitrary extra info
868
- }
869
- ```
870
-
871
- #### Naming Rules
872
-
873
- - **Base envelope**: `${serviceName}ResponseEnvelope` (override with `--openapi-envelope-namespace`)
874
- - **Error object**: `${serviceName}ErrorObject` (override with `--openapi-error-namespace`)
875
- - **Per-operation extension**: `<PayloadType|OperationName><EnvelopeNamespace>` (refines `data` field)
876
-
877
- #### Collision Avoidance
878
-
879
- If the payload type already ends with the namespace prefix, an underscore is inserted:
880
-
881
- - Payload `WeatherResponse` + default `ResponseEnvelope` → `WeatherResponse_ResponseEnvelope`
882
- - Payload `Booking` + default `ResponseEnvelope` → `BookingResponseEnvelope`
883
-
884
- #### Example
885
-
886
- ```bash
887
- npx wsdl-tsc openapi \
888
- --wsdl-source ./wsdl/Hotel.wsdl \
889
- --openapi-file ./docs/hotel-api.json \
890
- --openapi-envelope-namespace ApiEnvelope \
891
- --openapi-error-namespace ApiError
892
- ```
893
-
894
- Produces components:
895
- 1. `HotelApiEnvelope` (base)
896
- 2. `<Payload>ApiEnvelope` extension schemas (alphabetically sorted)
897
- 3. `HotelApiError` (error object)
898
- 4. Domain schemas
899
-
900
- ### Tag Inference Strategies
901
-
902
- | Strategy | Behavior |
903
- |-----------|------------------------------------------------------------------------------------|
904
- | `default` | Single tag = service name (fallback `SOAP`) |
905
- | `service` | Always service name (even if operation prefix differs) |
906
- | `first` | First lexical segment of CamelCase operation (e.g., `GetCityWeatherByZIP` → `Get`) |
907
-
908
- Use `--openapi-tags-file` for explicit mapping when heuristics are insufficient.
909
-
910
- ### Output Determinism
911
-
912
- All generated OpenAPI specs have **deterministic ordering**:
913
- - Path keys (alphabetically sorted)
914
- - HTTP methods within paths (alphabetically sorted)
915
- - Component schema names (alphabetically sorted)
916
- - Security schemes (alphabetically sorted)
917
- - Parameters (alphabetically sorted)
918
- - Operation tag arrays (alphabetically sorted)
919
-
920
- This ensures diff-friendly output for version control.
921
-
922
- ---
923
-
924
- ### Command: `gateway`
925
-
926
- **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.
927
-
928
- **When to use**:
929
- - Building a REST API gateway for legacy SOAP services
930
- - Creating a modern HTTP/JSON interface for SOAP operations
931
- - Setting up request/response validation with JSON Schema
932
- - Establishing Fastify routing structure with full handler implementations
933
-
934
- **What it generates**:
935
- - Fastify route registration files with complete handler implementations
936
- - JSON Schema models with URN-based IDs
937
- - Operation schemas (request/response validation)
938
- - Schema and route registration modules
939
- - Runtime utilities (envelope builders, error handlers)
940
- - Fastify plugin wrapper for simplified integration
941
-
942
- ### Usage
943
-
944
- ```bash
945
- npx wsdl-tsc gateway \
946
- --openapi-file <path> \
947
- --client-dir <path> \
948
- --gateway-dir <path> \
949
- --gateway-service-name <slug> \
950
- --gateway-version-prefix <slug> \
951
- [options]
952
- ```
953
-
954
- ### Required Flags
955
-
956
- | Flag | Description |
957
- |----------------------------|--------------------------------------------------------------------------|
958
- | `--openapi-file` | Path to OpenAPI 3.1 JSON or YAML file |
959
- | `--client-dir` | Path to client directory (where `client.ts` is located) |
960
- | `--gateway-dir` | Output directory for generated gateway code |
961
- | `--gateway-service-name` | Service identifier for URN generation (e.g., `weather`, `booking`) |
962
- | `--gateway-version-prefix` | Version prefix for URN generation (e.g., `v1`, `v2`, `urn:1.0.2:schema`) |
963
-
964
- ### Optional Flags
965
-
966
- | Flag | Default | Description |
967
- |----------------------------------|---------------------------------------------------|-------------------------------------------------------------|
968
- | `--import-extensions` | `js` | Import style: `js`, `ts`, or `bare` |
969
- | `--gateway-default-status-codes` | `200,400,401,403,404,409,422,429,500,502,503,504` | Comma-separated status codes to backfill |
970
- | `--catalog-file` | *(none)* | Path to `catalog.json` for operation metadata |
971
- | `--gateway-client-class-name` | *(auto-detected)* | Override SOAP client class name |
972
- | `--gateway-decorator-name` | `{serviceSlug}Client` | Fastify decorator name for client instance |
973
- | `--gateway-stub-handlers` | `false` | Generate stub handlers instead of full implementations |
974
- | `--gateway-skip-plugin` | `false` | Skip generating `plugin.ts` wrapper |
975
- | `--gateway-skip-runtime` | `false` | Skip generating `runtime.ts` utilities |
976
-
977
- > **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.
978
-
979
- ### Generated Output Structure
980
-
981
- ```
982
- {gateway-dir}/
983
- ├── schemas/
984
- │ ├── models/ # JSON Schema components with URN IDs
985
- │ │ ├── <schema1>.json
986
- │ │ ├── <schema2>.json
987
- │ │ └── ...
988
- │ └── operations/ # Fastify operation schemas
989
- │ ├── <operation1>.json
990
- │ ├── <operation2>.json
991
- │ └── ...
992
- ├── routes/ # Route registration files with full handlers
993
- │ ├── <route1>.ts
994
- │ ├── <route2>.ts
995
- │ └── ...
996
- ├── schemas.ts # Schema registration module
997
- ├── routes.ts # Route aggregator module
998
- ├── runtime.ts # Envelope builders and error handler
999
- └── plugin.ts # Fastify plugin wrapper (recommended entry point)
1000
- ```
1001
-
1002
- ### URN-Based Schema IDs
1003
-
1004
- All generated JSON Schemas use deterministic URN identifiers:
1005
-
1006
- ```
1007
- urn:services:{serviceSlug}:{versionSlug}:schemas:{models|operations}:{schemaSlug}
1008
- ```
1009
-
1010
- **Example**: `urn:services:weather:v1:schemas:models:getcityweatherbyzipresponse`
1011
-
1012
- ### Contract Assumptions
1013
-
1014
- The gateway generator enforces strict OpenAPI contract validation:
1015
-
1016
- - All request/response bodies must use `$ref` to `components.schemas` (no inline schemas)
1017
- - Every operation must have a default response with `application/json` content
1018
- - All schemas referenced by operations must exist in `components.schemas`
1019
-
1020
- ### Examples
1021
-
1022
- #### Basic Gateway Generation
1023
-
1024
- ```bash
1025
- npx wsdl-tsc gateway \
1026
- --openapi-file ./docs/weather-api.json \
1027
- --client-dir ./src/services/weather \
1028
- --gateway-dir ./src/gateway/weather \
1029
- --gateway-service-name weather \
1030
- --gateway-version-prefix v1
1031
- ```
1032
-
1033
- #### With Custom Status Codes
1034
-
1035
- ```bash
1036
- npx wsdl-tsc gateway \
1037
- --openapi-file ./docs/hotel-api.json \
1038
- --client-dir ./src/services/hotel \
1039
- --gateway-dir ./src/gateway/hotel \
1040
- --gateway-service-name hotel \
1041
- --gateway-version-prefix v2 \
1042
- --gateway-default-status-codes 200,400,401,404,500
1043
- ```
1044
-
1045
- #### From YAML OpenAPI
1046
-
1047
- ```bash
1048
- npx wsdl-tsc gateway \
1049
- --openapi-file ./docs/booking-api.yaml \
1050
- --client-dir ./src/services/booking \
1051
- --gateway-dir ./src/gateway/booking \
1052
- --gateway-service-name booking \
1053
- --gateway-version-prefix v1
1054
- ```
1055
-
1056
- ### Integration Pattern
1057
-
1058
- The generated gateway provides a Fastify plugin for simplified integration.
1059
-
1060
- #### Prerequisites
1061
-
1062
- Your host application needs these dependencies:
1063
-
1064
- ```bash
1065
- npm install fastify fastify-plugin
1066
- ```
1067
-
1068
- #### Using the Generated Plugin (Recommended)
1069
-
1070
- ```typescript
1071
- import Fastify from 'fastify';
1072
- import weatherGateway from './gateway/plugin.js';
1073
- import { Weather } from './client/client.js';
1074
-
1075
- const app = Fastify({ logger: true });
1076
-
1077
- // Create and configure SOAP client
1078
- const weatherClient = new Weather({
1079
- source: 'https://example.com/weather.wsdl',
1080
- // security: new soap.WSSecurity('user', 'pass'), // if needed
1081
- });
1082
-
1083
- // Register gateway plugin with client
1084
- await app.register(weatherGateway, {
1085
- client: weatherClient,
1086
- // Note: Route paths are determined by --openapi-base-path during generation.
1087
- // The prefix option here adds an ADDITIONAL runtime prefix on top of generated paths.
1088
- // Only use if you need to mount routes under a different sub-path at runtime.
1089
- });
1090
-
1091
- await app.listen({ port: 3000 });
1092
- ```
1093
-
1094
- The plugin automatically:
1095
- - Decorates Fastify with the SOAP client (`fastify.weatherClient`)
1096
- - Registers all JSON schemas for validation
1097
- - Installs a centralized error handler
1098
- - Registers all routes with full handler implementations
1099
-
1100
- #### Using Individual Components (Advanced)
1101
-
1102
- For more control, you can use the individual modules:
1103
-
1104
- ```typescript
1105
- import Fastify from 'fastify';
1106
- import { registerSchemas_v1_weather } from './gateway/schemas.js';
1107
- import { registerRoutes_v1_weather } from './gateway/routes.js';
1108
- import { createGatewayErrorHandler_v1_weather } from './gateway/runtime.js';
1109
- import { Weather } from './client/client.js';
1110
-
1111
- const app = Fastify({ logger: true });
1112
-
1113
- // Manual setup
1114
- const weatherClient = new Weather({ source: 'weather.wsdl' });
1115
- app.decorate('weatherClient', weatherClient);
1116
-
1117
- // Register schemas
1118
- await registerSchemas_v1_weather(app);
1119
-
1120
- // Install error handler
1121
- app.setErrorHandler(createGatewayErrorHandler_v1_weather());
1122
-
1123
- // Register routes (paths already include --openapi-base-path if configured)
1124
- await registerRoutes_v1_weather(app);
1125
-
1126
- await app.listen({ port: 3000 });
1127
- ```
1128
-
1129
- ### Generated Handler Implementation
1130
-
1131
- Route handlers are fully implemented and call the SOAP client automatically:
1132
-
1133
- ```typescript
1134
- // Generated: routes/get-city-forecast-by-zip.ts
1135
- import type { FastifyInstance } from "fastify";
1136
- import schema from "../schemas/operations/getcityforecastbyzip.json" with { type: "json" };
1137
- import { buildSuccessEnvelope } from "../runtime.js";
1138
-
1139
- export async function registerRoute_v1_weather_getcityforecastbyzip(fastify: FastifyInstance) {
1140
- fastify.route({
1141
- method: "POST",
1142
- url: "/get-city-forecast-by-zip",
1143
- schema,
1144
- handler: async (request) => {
1145
- const client = fastify.weatherClient;
1146
- const result = await client.GetCityForecastByZIP(request.body);
1147
- return buildSuccessEnvelope(result.response);
1148
- },
1149
- });
1150
- }
1151
- ```
1152
-
1153
- ### Response Envelope
1154
-
1155
- All responses are wrapped in a standard envelope format:
1156
-
1157
- **Success Response:**
1158
- ```
1159
- {
1160
- "status": "SUCCESS",
1161
- "message": null,
1162
- "data": { /* SOAP response data */ },
1163
- "error": null
1164
- }
1165
- ```
1166
-
1167
- **Error Response:**
1168
- ```
1169
- {
1170
- "status": "ERROR",
1171
- "message": "Request validation failed",
1172
- "data": null,
1173
- "error": {
1174
- "code": "VALIDATION_ERROR",
1175
- "message": "Request validation failed",
1176
- "details": { /* validation errors */ }
1177
- }
1178
- }
1179
- ```
1180
-
1181
- ### Error Handling
1182
-
1183
- The centralized error handler (`runtime.ts`) automatically classifies errors:
1184
-
1185
- | Error Type | HTTP Status | Error Code |
1186
- |-----------------------|-------------|-----------------------|
1187
- | Validation errors | 400 | `VALIDATION_ERROR` |
1188
- | SOAP faults | 502 | `SOAP_FAULT` |
1189
- | Connection refused | 503 | `SERVICE_UNAVAILABLE` |
1190
- | Timeout | 504 | `GATEWAY_TIMEOUT` |
1191
- | Other errors | 500 | `INTERNAL_ERROR` |
1192
-
1193
- ### Stub Handler Mode (Backward Compatible)
1194
-
1195
- If you prefer to implement handler logic manually or need custom transformation logic beyond the standard SOAP-to-REST mapping, use stub mode:
1196
-
1197
- ```bash
1198
- npx wsdl-tsc gateway \
1199
- --openapi-file ./docs/weather-api.json \
1200
- --client-dir ./src/services/weather \
1201
- --gateway-dir ./src/gateway/weather \
1202
- --gateway-service-name weather \
1203
- --gateway-version-prefix v1 \
1204
- --gateway-stub-handlers
1205
- ```
1206
-
1207
- This generates minimal handler stubs that throw "Not implemented" errors, allowing you to implement fully custom logic while keeping the routing and validation infrastructure.
1208
-
1209
- ---
1210
-
1211
- ### Command: `app`
1212
-
1213
- **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.
1214
-
1215
- **When to use**:
1216
- - Local testing and development
1217
- - Quick iteration on gateway configurations
1218
- - Demonstrating the generated API
1219
- - CI smoke testing
1220
-
1221
- ### Usage
1222
-
1223
- ```bash
1224
- npx wsdl-tsc app \
1225
- --client-dir <path> \
1226
- --gateway-dir <path> \
1227
- --openapi-file <path> \
1228
- [--catalog-file <path>] \
1229
- [--app-dir <path>] \
1230
- [options]
1231
- ```
1232
-
1233
- ### Required Flags
1234
-
1235
- | Flag | Description |
1236
- |------------------|----------------------------------------------------------|
1237
- | `--client-dir` | Path to client directory (where `client.ts` is located) |
1238
- | `--gateway-dir` | Path to gateway directory (where `plugin.ts` is located) |
1239
- | `--openapi-file` | Path to OpenAPI specification file |
1240
-
1241
- ### Optional Flags
1242
-
1243
- | Flag | Default | Description |
1244
- |-----------------------|-------------------------------|---------------------------------------------------|
1245
- | `--catalog-file` | `{client-dir}/catalog.json` | Path to catalog.json (for metadata extraction) |
1246
- | `--app-dir` | `{gateway-dir}/../app` | Output directory for generated app |
1247
- | `--import-extensions` | Inferred from catalog or `js` | Import-extension mode: `js`, `ts`, or `bare` |
1248
- | `--host` | `127.0.0.1` | Default server host |
1249
- | `--port` | `3000` | Default server port |
1250
- | `--prefix` | `""` (empty) | Route prefix |
1251
- | `--logger` | `true` | Enable Fastify logger |
1252
- | `--openapi-mode` | `copy` | How to handle OpenAPI file: `copy` or `reference` |
1253
-
1254
- ### Examples
1255
-
1256
- #### Generate App After Pipeline
1257
-
1258
- ```bash
1259
- # First generate client, OpenAPI, and gateway
1260
- npx wsdl-tsc pipeline \
1261
- --wsdl-source weather.wsdl \
1262
- --client-dir ./client \
1263
- --openapi-file ./openapi.json \
1264
- --gateway-dir ./gateway \
1265
- --gateway-service-name weather \
1266
- --gateway-version-prefix v1
1267
-
1268
- # Then generate runnable app
1269
- npx wsdl-tsc app \
1270
- --client-dir ./client \
1271
- --gateway-dir ./gateway \
1272
- --openapi-file ./openapi.json \
1273
- --app-dir ./app
1274
- ```
1275
-
1276
- #### Generate App with Custom Configuration
1277
-
1278
- ```bash
1279
- npx wsdl-tsc app \
1280
- --client-dir ./client \
1281
- --gateway-dir ./gateway \
1282
- --openapi-file ./openapi.json \
1283
- --app-dir ./my-app \
1284
- --host 0.0.0.0 \
1285
- --port 8080 \
1286
- --prefix /api/v1
1287
- ```
1288
-
1289
- ### Generated App Structure
1290
-
1291
- The `app` command generates the following files:
1292
-
1293
- ```
1294
- app/
1295
- ├── server.js (or .ts) # Main application entry point
1296
- ├── config.js (or .ts) # Configuration loader with env support
1297
- ├── .env.example # Environment variable template
1298
- ├── README.md # Usage instructions
1299
- └── openapi.json # OpenAPI spec (when --openapi-mode=copy)
1300
- ```
1301
-
1302
- ### Running the Generated App
1303
-
1304
- ```bash
1305
- # Copy environment template
1306
- cd app
1307
- cp .env.example .env
1308
-
1309
- # Edit .env to configure WSDL source and other settings
1310
- # vim .env
1311
-
1312
- # Run the server
1313
- npx tsx server.js # For TypeScript files
1314
- # or
1315
- node server.js # For JavaScript files
1316
- ```
1317
-
1318
- ### Configuration
1319
-
1320
- The generated app loads configuration from environment variables with the following precedence:
1321
-
1322
- 1. **Environment variables** (runtime overrides)
1323
- 2. **Catalog defaults** (from generation-time)
1324
- 3. **Hard defaults** (in config file)
1325
-
1326
- #### Environment Variables
1327
-
1328
- | Variable | Default (from catalog or flags) | Description |
1329
- |-----------------|---------------------------------|--------------------------------------|
1330
- | `WSDL_SOURCE` | From catalog or **required** | WSDL URL or local file path |
1331
- | `HOST` | `127.0.0.1` | Server bind address |
1332
- | `PORT` | `3000` | Server listen port |
1333
- | `PREFIX` | `""` (empty) | Route prefix |
1334
- | `LOGGER` | `true` | Enable Fastify logger |
1335
-
1336
- ### Endpoints
1337
-
1338
- The generated app serves the following endpoints:
1339
-
1340
- #### Health Check
1341
- ```bash
1342
- GET /health
1343
- ```
1344
- Returns: `{ "ok": true }`
1345
-
1346
- #### OpenAPI Specification
1347
- ```bash
1348
- GET /openapi.json
1349
- ```
1350
- Returns: Complete OpenAPI 3.1 specification
1351
-
1352
- #### Gateway Routes
1353
- All SOAP operations are exposed as REST endpoints. See the OpenAPI spec for complete API documentation.
1354
-
1355
- ### Example Usage
1356
-
1357
- ```bash
1358
- # Start the server
1359
- cd app
1360
- npx tsx server.js
1361
-
1362
- # Test health endpoint
1363
- curl http://localhost:3000/health
1364
-
1365
- # Get OpenAPI spec
1366
- curl http://localhost:3000/openapi.json | jq .
1367
-
1368
- # Call a gateway operation (example)
1369
- curl -X POST http://localhost:3000/get-weather-information \
1370
- -H "Content-Type: application/json" \
1371
- -d '{}'
1372
- ```
1373
-
1374
- ### Integration with Pipeline
1375
-
1376
- The `app` command can also be used via the pipeline with the `--generate-app` flag:
1377
-
1378
- ```bash
1379
- npx wsdl-tsc pipeline \
1380
- --wsdl-source weather.wsdl \
1381
- --client-dir ./client \
1382
- --openapi-file ./openapi.json \
1383
- --gateway-dir ./gateway \
1384
- --gateway-service-name weather \
1385
- --gateway-version-prefix v1 \
1386
- --generate-app
1387
- ```
1388
-
1389
- This generates all artifacts including the runnable app in a single command.
1390
-
1391
- ---
1392
-
1393
- ### Command: `compile` (Advanced)
1394
-
1395
- **Purpose**: Parse WSDL and generate only the intermediate `catalog.json` representation without TypeScript client code.
1396
-
1397
- **When to use**:
1398
- - Multi-stage builds where you want to cache the parsed WSDL
1399
- - Debugging or inspecting the compiled schema structure
1400
- - Sharing a compiled catalog across multiple generation targets
1401
-
1402
- #### Usage
1403
-
1404
- ```bash
1405
- npx wsdl-tsc compile --wsdl-source <file|url> --catalog-file <path> [options]
1406
- ```
1407
-
1408
- #### Required Flags
1409
-
1410
- | Flag | Description |
1411
- |---------------------|------------------------------------------|
1412
- | `--wsdl-source` | Path or URL to the WSDL file |
1413
- | `--catalog-file` | Output path for `catalog.json` |
1414
-
1415
- #### Optional Flags
1416
-
1417
- | Flag | Default | Description |
1418
- |------------------------------------|----------------|--------------------------------------------------------------|
1419
- | `--import-extensions` | `js` | Import specifier style: `js`, `ts`, or `bare` |
1420
- | `--client-attributes-key` | `$attributes` | Attribute bag key for runtime mapper |
1421
- | `--client-class-name` | (derived) | Override generated client class name |
1422
- | `--client-int64-as` | `string` | Map 64-bit integers: `string`, `number`, or `bigint` |
1423
- | `--client-bigint-as` | `string` | Map arbitrary-size integers: `string` or `number` |
1424
- | `--client-decimal-as` | `string` | Map `xs:decimal`: `string` or `number` |
1425
- | `--client-date-as` | `string` | Map date/time types: `string` or `Date` |
1426
- | `--client-choice-mode` | `all-optional` | Choice element strategy: `all-optional` or `union` |
1427
- | `--client-fail-on-unresolved` | `false` | Fail build on unresolved type references |
1428
- | `--client-nillable-as-optional` | `false` | Treat nillable elements as optional properties |
1429
-
1430
- #### Examples
1431
-
1432
- **Basic Compilation:**
1433
-
1434
- ```bash
1435
- npx wsdl-tsc compile \
1436
- --wsdl-source examples/minimal/weather.wsdl \
1437
- --catalog-file tmp/catalog.json
1438
- ```
1439
-
1440
- **With Custom Mapping Options:**
1441
-
1442
- ```bash
1443
- npx wsdl-tsc compile \
1444
- --wsdl-source https://example.com/Hotel.wsdl \
1445
- --catalog-file ./build/hotel-catalog.json \
1446
- --client-int64-as number \
1447
- --client-decimal-as string
1448
- ```
1449
-
1450
- **For Debugging:**
1451
-
1452
- ```bash
1453
- # Compile to inspect types and operations
1454
- npx wsdl-tsc compile \
1455
- --wsdl-source ./wsdl/ComplexService.wsdl \
1456
- --catalog-file ./debug/catalog.json \
1457
- --client-fail-on-unresolved false
1458
-
1459
- # Inspect types
1460
- cat ./debug/catalog.json | jq '.types'
1461
-
1462
- # Inspect operations
1463
- cat ./debug/catalog.json | jq '.operations'
1464
- ```
1465
-
1466
- #### Output
1467
-
1468
- - `catalog.json` - Compiled schema representation including types, operations, and metadata
1469
-
1470
- #### Catalog Structure
1471
-
1472
- The catalog.json file contains the compiled WSDL representation:
1473
-
1474
- ```json
1475
- {
1476
- "wsdlUri": "path/to/service.wsdl",
1477
- "targetNamespace": "http://example.com/service",
1478
- "serviceName": "WeatherService",
1479
- "types": [
1480
- {
1481
- "name": "GetWeatherRequest",
1482
- "properties": []
1483
- }
1484
- ],
1485
- "operations": [
1486
- {
1487
- "name": "GetWeather",
1488
- "input": "GetWeatherRequest",
1489
- "output": "GetWeatherResponse"
1490
- }
1491
- ],
1492
- "options": {
1493
- "imports": "js",
1494
- "catalog": true
1495
- }
1496
- }
1497
- ```
1498
-
1499
- **Key sections**:
1500
- - `types` - All compiled type definitions with properties and inheritance
1501
- - `operations` - SOAP operations with input/output type references
1502
- - `options` - Compiler options used during generation
1503
-
1504
- This catalog can be reused with the `client` and `openapi` commands via `--catalog-file`.
1505
-
1506
- #### Catalog Co-location
1507
-
1508
- **Default behavior**: Catalog files are **co-located** with their primary output files for better organization and discoverability.
1509
-
1510
- **Catalog Location by Command**:
1511
- - `compile`: Always requires explicit `--catalog-file` (no default)
1512
- - `client`: Defaults to `{client-dir}/catalog.json`
1513
- - `openapi`: Defaults to `{openapi-file-dir}/catalog.json`
1514
- - `pipeline`: Intelligent cascade - first available: `{client-dir}` > `{openapi-dir}` > `{gateway-dir}` > `tmp/`
1515
-
1516
- **Common patterns**:
1517
-
1518
- 1. **Co-located with client** (recommended for most projects):
1519
- ```bash
1520
- npx wsdl-tsc client --wsdl-source service.wsdl --client-dir src/services/weather
1521
- ```
1522
-
1523
- Creates `src/services/weather/catalog.json` automatically.
1524
-
1525
- 2. **Shared catalog for multiple commands** (custom location):
1526
- ```bash
1527
- npx wsdl-tsc compile --wsdl-source service.wsdl --catalog-file build/shared-catalog.json
1528
- npx wsdl-tsc client --catalog-file build/shared-catalog.json --client-dir src/client
1529
- npx wsdl-tsc openapi --catalog-file build/shared-catalog.json --openapi-file docs/api.json
1530
- ```
1531
-
1532
- ---
1533
-
1534
- ## Working With Generated Clients
1535
-
1536
- ### Client Construction
1537
-
1538
- ```typescript
1539
- import soap from "soap";
1540
- import { Weather } from "./src/services/weather/client.js";
1541
-
1542
- const client = new Weather({
1543
- source: "https://example.com/WeatherService?wsdl",
1544
- security: new soap.WSSecurity("username", "password")
1545
- });
1546
- ```
1547
-
1548
- ### Calling Operations
1549
-
1550
- ```typescript
1551
- // Operation with input
1552
- const forecast = await client.GetCityForecastByZIP({
1553
- ZIP: "10001"
1554
- });
1555
-
1556
- console.log(forecast.GetCityForecastByZIPResult.Success);
1557
- console.log(forecast.GetCityForecastByZIPResult.ForecastResult);
1558
-
1559
- // Operation without input
1560
- const info = await client.GetWeatherInformation({});
1561
- console.log(info.GetWeatherInformationResult.WeatherDescriptions);
1562
- ```
1563
-
1564
- ### Attributes & Text Content
1565
-
1566
- When an element has both attributes and text content, use the `$value` convention:
1567
-
1568
- ```typescript
1569
- const price = {
1570
- currencyCode: "USD", // attribute
1571
- $value: "123.45" // text content
1572
- };
1573
- ```
1574
-
1575
- ### Working With Arrays
1576
-
1577
- Repeated elements are automatically typed as arrays:
1578
-
1579
- ```typescript
1580
- interface ForecastReturn {
1581
- Forecast: Forecast[]; // maxOccurs > 1
1582
- }
1583
- ```
1584
-
1585
- ### Type Safety
1586
-
1587
- All operations and types are fully typed:
1588
-
1589
- ```typescript
1590
- // TypeScript knows the exact shape
1591
- const result: GetCityWeatherByZIPResponse = await client.GetCityWeatherByZIP({
1592
- ZIP: "10001"
1593
- });
1594
-
1595
- // Autocomplete and type checking work
1596
- result.GetCityWeatherByZIPResult.Temperature; // number | string (depends on mapping)
1597
- ```
1598
-
1599
- ---
1600
-
1601
- ## Configuration Files
1602
-
1603
- ### Security Configuration (`security.json`)
1604
-
1605
- Define security schemes, headers, and per-operation overrides:
1606
-
1607
- ```json
1608
- {
1609
- "global": {
1610
- "scheme": "bearer",
1611
- "bearer": { "bearerFormat": "JWT" },
1612
- "headers": [
1613
- {
1614
- "name": "X-Correlation-Id",
1615
- "required": false,
1616
- "schema": { "type": "string" }
1617
- }
1618
- ]
1619
- },
1620
- "overrides": {
1621
- "CancelBooking": { "scheme": "apiKey" }
1622
- }
1623
- }
1624
- ```
1625
-
1626
- **Supported schemes**: `none`, `basic`, `bearer`, `apiKey`, `oauth2`
1627
-
1628
- ### Tags Configuration (`tags.json`)
1629
-
1630
- Explicit operation → tag mapping:
1631
-
1632
- ```json
1633
- {
1634
- "GetCityWeatherByZIP": ["Weather", "Forecast"],
1635
- "GetWeatherInformation": ["Weather", "Info"],
1636
- "CancelBooking": ["Booking", "Cancellation"]
1637
- }
1638
- ```
1639
-
1640
- ### Operations Configuration (`ops.json`)
1641
-
1642
- Per-operation overrides for method, summary, description, and deprecation:
1643
-
1644
- ```json
1645
- {
1646
- "GetCityWeatherByZIP": {
1647
- "method": "get",
1648
- "summary": "Get weather forecast by ZIP code",
1649
- "description": "Returns a detailed weather forecast for the specified US ZIP code",
1650
- "deprecated": false
1651
- },
1652
- "LegacyOperation": {
1653
- "deprecated": true
1654
- }
1655
- }
1656
- ```
1657
-
1658
- ---
1659
-
1660
- ## Production Concerns
1661
-
1662
- ### Deterministic Output Guarantees
1663
-
1664
- All generated code and specifications have **stable, deterministic ordering** for version control:
1665
-
1666
- - ✅ **TypeScript files**: Sorted type declarations, imports, and exports
1667
- - ✅ **OpenAPI specs**: Sorted paths, HTTP methods, schemas, parameters, security schemes, tags
1668
- - ✅ **JSON Schemas**: Sorted property keys and component names
1669
- - ✅ **Gateway routes**: Alphabetically organized route files
1670
- - ✅ **Catalog JSON**: Consistent ordering of types and operations
1671
-
1672
- **Benefit**: Safe regeneration in CI/CD without spurious diffs.
1673
-
1674
- ### Validation Behavior
1675
-
1676
- **OpenAPI Validation** (enabled by default):
1677
- - Uses `@apidevtools/swagger-parser`
1678
- - Validates schema structure
1679
- - Resolves all `$ref` references
1680
- - Catches missing schemas and circular dependencies
1681
- - Disable with `--openapi-validate false`
1682
-
1683
- **Gateway Contract Validation**:
1684
- - All request/response bodies must use `$ref` to `components.schemas`
1685
- - Every operation must have a default response with `application/json` content
1686
- - All referenced schemas must exist in `components.schemas`
1687
-
1688
- ### Error Handling
1689
-
1690
- **Gateway Error Classification**:
1691
-
1692
- | Error Type | HTTP Status | Error Code | When It Occurs |
1693
- |-----------------------|-------------|-----------------------|---------------------------------------|
1694
- | Validation errors | 400 | `VALIDATION_ERROR` | Request doesn't match JSON Schema |
1695
- | SOAP faults | 502 | `SOAP_FAULT` | SOAP service returned a fault |
1696
- | Connection refused | 503 | `SERVICE_UNAVAILABLE` | Cannot reach SOAP endpoint |
1697
- | Timeout | 504 | `GATEWAY_TIMEOUT` | SOAP request exceeded timeout |
1698
- | Other errors | 500 | `INTERNAL_ERROR` | Unexpected errors |
1699
-
1700
- All errors are wrapped in the standard envelope format with `error` object populated.
1701
-
1702
- ### SOAP Wire Logging
1703
-
1704
- Enable SOAP request/response debugging:
1705
-
1706
- ```bash
1707
- NODE_DEBUG=soap node app.js
1708
- ```
1709
-
1710
- This logs full XML request/response payloads to console.
1711
-
1712
- ### CI/CD Tips
1713
-
1714
- **Caching Strategy:**
1715
-
1716
- ```bash
1717
- # Step 1: Compile catalog (cacheable artifact)
1718
- npx wsdl-tsc compile \
1719
- --wsdl-source ./wsdl/Service.wsdl \
1720
- --catalog-file ./build/catalog.json
1721
-
1722
- # Step 2: Generate code from cached catalog
1723
- npx wsdl-tsc client --catalog-file ./build/catalog.json --client-dir ./src/client
1724
- npx wsdl-tsc openapi --catalog-file ./build/catalog.json --openapi-file ./docs/api.json
1725
- ```
1726
-
1727
- **Recommended Build Script** (`package.json`):
1728
-
1729
- ```json
1730
- {
1731
- "scripts": {
1732
- "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",
1733
- "build": "npm run generate && tsc",
1734
- "typecheck": "tsc --noEmit"
1735
- }
1736
- }
1737
- ```
1738
-
1739
- ### Known Limitations
1740
-
1741
- **Choice Elements**:
1742
- - Current strategy: `all-optional` (all branches optional)
1743
- - Future: Discriminated union support (planned)
1744
-
1745
- **Union Types**:
1746
- - Experimental `--client-choice-mode union` available
1747
- - May require manual refinement for complex patterns
1748
-
1749
- **WS-Policy**:
1750
- - Security hints extracted from policies
1751
- - Custom policies may require manual security configuration
1752
-
1753
- **Array Wrapper Flattening**:
1754
- - Single-child sequences with `maxOccurs>1` become array schemas
1755
- - Sequences with multiple children preserve wrapper
1756
-
1757
- ---
1758
-
1759
- ## Programmatic API
1760
-
1761
- All CLI commands are available as TypeScript functions for programmatic usage.
1762
-
1763
- ### `compileWsdlToProject`
1764
-
1765
- Generate TypeScript SOAP client from WSDL.
1766
-
1767
- ```typescript
1768
- import { compileWsdlToProject } from "@techspokes/typescript-wsdl-client";
1769
-
1770
- await compileWsdlToProject({
1771
- wsdl: "./wsdl/Hotel.wsdl",
1772
- outDir: "./src/services/hotel",
1773
- options: {
1774
- imports: "js",
1775
- catalog: true,
1776
- primitive: {
1777
- int64As: "number",
1778
- bigIntegerAs: "string",
1779
- decimalAs: "string",
1780
- dateAs: "string"
1781
- },
1782
- choice: "all-optional",
1783
- clientName: "HotelClient",
1784
- nillableAsOptional: false
1785
- }
1786
- });
1787
- ```
1788
-
1789
- **Type Signature**:
1790
-
1791
- ```typescript
1792
- // noinspection JSAnnotator
1793
- function compileWsdlToProject(input: {
1794
- wsdl: string;
1795
- outDir: string;
1796
- options?: Partial<CompilerOptions>;
1797
- }): Promise<void>;
1798
- ```
1799
-
1800
- **Options** (`CompilerOptions`):
1801
-
1802
- ```typescript
1803
- interface CompilerOptions {
1804
- wsdl: string;
1805
- out: string;
1806
- imports: "js" | "ts" | "bare";
1807
- catalog: boolean;
1808
- primitive: PrimitiveOptions;
1809
- choice?: "all-optional" | "union";
1810
- failOnUnresolved?: boolean;
1811
- attributesKey?: string;
1812
- clientName?: string;
1813
- nillableAsOptional?: boolean;
1814
- }
1815
-
1816
- interface PrimitiveOptions {
1817
- int64As?: "string" | "number" | "bigint";
1818
- bigIntegerAs?: "string" | "number";
1819
- decimalAs?: "string" | "number";
1820
- dateAs?: "string" | "Date";
1821
- }
1822
- ```
1823
-
1824
- ### `generateOpenAPI`
1825
-
1826
- Generate OpenAPI 3.1 specification from WSDL or catalog.
1827
-
1828
- ```typescript
1829
- import { generateOpenAPI } from "@techspokes/typescript-wsdl-client";
1830
-
1831
- const { doc, jsonPath, yamlPath } = await generateOpenAPI({
1832
- wsdl: "./wsdl/Hotel.wsdl",
1833
- outFile: "./docs/hotel-api",
1834
- format: "both",
1835
- title: "Hotel Booking API",
1836
- version: "1.0.0",
1837
- servers: ["https://api.example.com/v1"],
1838
- basePath: "/booking",
1839
- pathStyle: "kebab",
1840
- tagStyle: "service",
1841
- validate: true
1842
- });
1843
- ```
1844
-
1845
- **Type Signature**:
1846
-
1847
- ```typescript
1848
- // noinspection JSAnnotator
1849
- function generateOpenAPI(opts: GenerateOpenAPIOptions): Promise<{
1850
- doc: any;
1851
- jsonPath?: string;
1852
- yamlPath?: string;
1853
- }>;
1854
- ```
1855
-
1856
- **Options** (`GenerateOpenAPIOptions`):
1857
-
1858
- ```typescript
1859
- interface GenerateOpenAPIOptions {
1860
- // Input sources (mutually exclusive)
1861
- wsdl?: string;
1862
- catalogFile?: string;
1863
- compiledCatalog?: CompiledCatalog;
1864
-
1865
- // Output
1866
- outFile?: string;
1867
- format?: "json" | "yaml" | "both";
1868
-
1869
- // Metadata
1870
- title?: string;
1871
- version?: string;
1872
- description?: string;
1873
- servers?: string[];
1874
-
1875
- // Path configuration
1876
- basePath?: string;
1877
- pathStyle?: "kebab" | "asis" | "lower";
1878
- defaultMethod?: string;
1879
-
1880
- // Schema configuration
1881
- closedSchemas?: boolean;
1882
- pruneUnusedSchemas?: boolean;
1883
-
1884
- // Tag configuration
1885
- tagStyle?: "default" | "first" | "service";
1886
- tagsFile?: string;
1887
-
1888
- // Security & operations
1889
- securityConfigFile?: string;
1890
- opsFile?: string;
1891
-
1892
- // Envelope customization
1893
- envelopeNamespace?: string;
1894
- errorNamespace?: string;
1895
-
1896
- // Validation
1897
- validate?: boolean;
1898
- skipValidate?: boolean;
1899
-
1900
- // Deprecated
1901
- asYaml?: boolean;
1902
- }
1903
- ```
1904
-
1905
- ### `generateGateway`
1906
-
1907
- Generate Fastify gateway code from OpenAPI specification.
1908
-
1909
- ```typescript
1910
- import { generateGateway } from "@techspokes/typescript-wsdl-client";
1911
-
1912
- await generateGateway({
1913
- openapiFile: "./docs/hotel-api.json",
1914
- outDir: "./src/gateway/hotel",
1915
- clientDir: "./src/services/hotel",
1916
- versionSlug: "v1",
1917
- serviceSlug: "hotel",
1918
- defaultResponseStatusCodes: [200, 400, 401, 403, 404, 409, 422, 429, 500, 502, 503, 504],
1919
- imports: "js"
1920
- });
1921
- ```
1922
-
1923
- **Type Signature**:
1924
-
1925
- ```typescript
1926
- // noinspection JSAnnotator
1927
- function generateGateway(opts: GenerateGatewayOptions): Promise<void>;
1928
- ```
1929
-
1930
- **Options** (`GenerateGatewayOptions`):
1931
-
1932
- ```typescript
1933
- interface GenerateGatewayOptions {
1934
- // Input sources (mutually exclusive)
1935
- openapiFile?: string;
1936
- openapiDocument?: any;
1937
-
1938
- // Output
1939
- outDir: string;
1940
-
1941
- // Client integration
1942
- clientDir?: string;
1943
-
1944
- // URN configuration
1945
- versionSlug?: string;
1946
- serviceSlug?: string;
1947
-
1948
- // Schema configuration
1949
- defaultResponseStatusCodes?: number[];
1950
-
1951
- // Import style
1952
- imports?: "js" | "ts" | "bare";
1953
- }
1954
- ```
1955
-
1956
- ### `runGenerationPipeline`
1957
-
1958
- Run complete pipeline: client + OpenAPI + gateway in one pass.
1959
-
1960
- ```typescript
1961
- import { runGenerationPipeline } from "@techspokes/typescript-wsdl-client";
1962
-
1963
- const { compiled, openapiDoc } = await runGenerationPipeline({
1964
- wsdl: "./wsdl/Hotel.wsdl",
1965
- catalogOut: "./build/hotel-catalog.json",
1966
- clientOutDir: "./src/services/hotel",
1967
- compiler: {
1968
- imports: "js",
1969
- primitive: {
1970
- int64As: "number",
1971
- decimalAs: "string"
1972
- }
1973
- },
1974
- openapi: {
1975
- outFile: "./docs/hotel-api.json",
1976
- format: "both",
1977
- servers: ["https://api.example.com/v1"],
1978
- tagStyle: "service"
1979
- },
1980
- gateway: {
1981
- outDir: "./src/gateway/hotel",
1982
- versionSlug: "v1",
1983
- serviceSlug: "hotel"
1984
- }
1985
- });
1986
- ```
1987
-
1988
- **Type Signature**:
1989
-
1990
- ```typescript
1991
- // noinspection JSAnnotator
1992
- function runGenerationPipeline(opts: PipelineOptions): Promise<{
1993
- compiled: CompiledCatalog;
1994
- openapiDoc?: any;
1995
- }>;
1996
- ```
1997
-
1998
- **Options** (`PipelineOptions`):
1999
-
2000
- ```typescript
2001
- interface PipelineOptions {
2002
- // Input
2003
- wsdl: string;
2004
-
2005
- // Catalog (always generated)
2006
- catalogOut: string;
2007
-
2008
- // Client generation (optional)
2009
- clientOutDir?: string;
2010
- compiler?: Partial<CompilerOptions>;
2011
-
2012
- // OpenAPI generation (optional)
2013
- openapi?: Omit<GenerateOpenAPIOptions, "wsdl" | "catalogFile" | "compiledCatalog"> & {
2014
- outFile?: string;
2015
- };
2016
-
2017
- // Gateway generation (optional, requires openapi)
2018
- gateway?: Omit<GenerateGatewayOptions, "openapiFile" | "openapiDocument"> & {
2019
- outDir?: string;
2020
- };
2021
- }
2022
- ```
2023
-
2024
- ---
2025
-
2026
- ## Advanced Topics
2027
-
2028
- ### Primitive Mapping Philosophy
2029
-
2030
- **Default: String-first safety** — Prevents precision loss and parsing errors at the cost of convenience.
2031
-
2032
- | XSD Type | Default | Alternatives | Recommendation |
2033
- |---------------|----------|--------------------|-------------------------------------------------|
2034
- | `xs:long` | `string` | `number`, `bigint` | Use `number` if values fit safely in JS range |
2035
- | `xs:integer` | `string` | `number` | Use `string` for arbitrary-size integers |
2036
- | `xs:decimal` | `string` | `number` | Use `string` for precise decimal representation |
2037
- | `xs:dateTime` | `string` | `Date` | Use `Date` if runtime parsing is acceptable |
2038
-
2039
- ### Choice Element Handling
2040
-
2041
- **Current strategy**: `all-optional` — All choice branches are emitted as optional properties.
2042
-
2043
- ```typescript
2044
- // WSDL: <xs:choice>
2045
- interface MyType {
2046
- optionA?: string;
2047
- optionB?: number;
2048
- }
2049
- ```
2050
-
2051
- **Future**: Discriminated unions for type-safe choice validation.
2052
-
2053
- ### Array Wrapper Flattening
2054
-
2055
- Single repeated child without attributes collapses to array schema in OpenAPI:
2056
-
2057
- ```xml
2058
- <xs:complexType name="ArrayOfForecast">
2059
- <xs:sequence>
2060
- <xs:element name="Forecast" type="tns:Forecast" maxOccurs="unbounded"/>
2061
- </xs:sequence>
2062
- </xs:complexType>
2063
- ```
2064
-
2065
- **OpenAPI Schema**:
2066
-
2067
- ```json
2068
- {
2069
- "ArrayOfForecast": {
2070
- "type": "array",
2071
- "items": { "$ref": "#/components/schemas/Forecast" }
2072
- }
2073
- }
2074
- ```
2075
-
2076
- ### Inheritance Flattening
2077
-
2078
- **Extension (`xs:extension`)**:
2079
- - Base properties merged into derived type
2080
- - TypeScript: `extends` when possible
2081
-
2082
- **Restriction (`xs:restriction`)**:
2083
- - Treated as base type with constraints
2084
-
2085
- **SimpleContent**:
2086
- - Base value collapsed into `$value` property
2087
- - Attributes remain as peer properties
2088
-
2089
- ### Validation
2090
-
2091
- OpenAPI validation uses `@apidevtools/swagger-parser`:
2092
- - Validates schema structure
2093
- - Resolves all `$ref` references
2094
- - Catches missing schemas
2095
- - Detects circular dependencies
2096
-
2097
- Disable with `--openapi-validate false` or `validate: false` in API.
2098
-
2099
- ---
2100
-
2101
- ## Troubleshooting
2102
-
2103
- ### Common Issues
2104
-
2105
- | Symptom | Resolution |
2106
- |-----------------------------------|---------------------------------------------------------------------------------------------------------------------------|
2107
- | **WSDL fetch fails** | Curl the URL, check TLS/proxy settings, retry with local copy |
2108
- | **Unresolved type references** | Re-run with `--client-fail-on-unresolved=false` to inspect partial graph |
2109
- | **Missing schema in OpenAPI** | Ensure the global element exists (catalog shows compiled symbols) |
2110
- | **Wrong array modeling** | Check `maxOccurs` in WSDL; tool only arrays when `maxOccurs>1` or `unbounded` |
2111
- | **Authentication errors** | Provide proper `soap.ISecurity` instance (`WSSecurity`, `BasicAuthSecurity`) |
2112
- | **Date/time confusion** | Use `--client-date-as Date` for runtime Date objects |
2113
- | **TypeScript compilation errors** | Check `--import-extensions` matches your tsconfig `moduleResolution` |
2114
- | **Gateway validation failures** | Ensure OpenAPI has valid `$ref` paths and all schemas in `components.schemas` |
2115
- | **Catalog file not found** | Catalog defaults to output directory (e.g., `{client-dir}/catalog.json`); use `--catalog-file` to specify custom location |
2116
-
2117
- ### Enable SOAP Wire Logging
2118
-
2119
- Debug SOAP requests/responses:
2120
-
2121
- ```bash
2122
- NODE_DEBUG=soap node app.js
2123
- ```
2124
-
2125
- ### Verify Installation
2126
-
2127
- ```bash
2128
- npx wsdl-tsc --help
2129
- npm run smoke:compile # Test catalog generation
2130
- npm run smoke:client # Test client generation
2131
- npm run smoke:openapi # Test OpenAPI generation
2132
- npm run smoke:gateway # Test gateway generation
2133
- npm run smoke:pipeline # Test complete pipeline
2134
- ```
2135
-
2136
- ### TypeScript Configuration
2137
-
2138
- Ensure your `tsconfig.json` is compatible:
2139
-
2140
- ```json
2141
- {
2142
- "compilerOptions": {
2143
- "target": "ES2022",
2144
- "module": "NodeNext",
2145
- "moduleResolution": "NodeNext",
2146
- "strict": true,
2147
- "esModuleInterop": true,
2148
- "skipLibCheck": true
2149
- }
2150
- }
2151
- ```
2152
-
2153
- ### Catalog Inspection
2154
-
2155
- Examine the compiled catalog to understand type resolution:
2156
-
2157
- ```bash
2158
- # Compile to specific location
2159
- npx wsdl-tsc compile \
2160
- --wsdl-source ./wsdl/Hotel.wsdl \
2161
- --catalog-file build/hotel-catalog.json
2162
-
2163
- # Inspect types, operations, and metadata
2164
- cat build/hotel-catalog.json | jq '.types'
2165
- cat build/hotel-catalog.json | jq '.operations'
2166
- ```
2167
-
2168
- Or inspect catalog from client generation:
2169
-
2170
- ```bash
2171
- npx wsdl-tsc client \
2172
- --wsdl-source ./wsdl/Hotel.wsdl \
2173
- --client-dir ./src/services/hotel
2174
-
2175
- cat ./src/services/hotel/catalog.json | jq '.types'
2176
- ```
2177
-
2178
- The catalog is automatically placed at `./src/services/hotel/catalog.json`.
2179
-
2180
- ---
2181
-
2182
- ## Contributing
2183
-
2184
- We welcome contributions! Here's how to get started:
2185
-
2186
- ### Development Setup
2187
-
2188
- ```bash
2189
- # Clone repository
2190
- git clone https://github.com/techspokes/typescript-wsdl-client.git
2191
- cd typescript-wsdl-client
2192
-
2193
- # Install dependencies
2194
- npm install
2195
-
2196
- # Build
2197
- npm run build
2198
-
2199
- # Type check
2200
- npm run typecheck
2201
-
2202
- # Run smoke tests
2203
- npm run smoke:compile
2204
- npm run smoke:client
2205
- npm run smoke:openapi
2206
- npm run smoke:gateway
2207
- npm run smoke:pipeline
2208
-
2209
- # Run full CI suite
2210
- npm run ci
2211
- ```
2212
-
2213
- ### Making Changes
2214
-
2215
- 1. **Fork & branch** — Create a feature branch from `main`
2216
- 2. **Make changes** — Implement your feature or fix
2217
- 3. **Test** — Run smoke tests and verify functionality
2218
- 4. **Update CHANGELOG** — Add entry under `## [Unreleased]` section
2219
- 5. **Commit** — Use conventional commit format: `feat:`, `fix:`, `docs:`, etc.
2220
- 6. **Submit PR** — Create pull request with clear description
2221
-
2222
- ### Commit Message Format
2223
-
2224
- ```
2225
- Version: <version> <type>(<optional-scope>): <imperative summary>
2226
-
2227
- [optional body with details, rationale, breaking changes]
2228
-
2229
- [optional footer with refs: Closes #123]
2230
- ```
2231
-
2232
- **Types**: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`
2233
-
2234
- **Example**:
2235
- ```
2236
- Version: 0.8.0 feat(gateway): add support for YAML OpenAPI input
2237
-
2238
- Gateway command now accepts both JSON and YAML OpenAPI files,
2239
- determined by file extension (.json, .yaml, .yml).
2240
-
2241
- Closes #456
2242
- ```
2243
-
2244
- ### Guidelines
2245
-
2246
- - Follow existing code style and conventions
2247
- - Keep PRs focused and scoped
2248
- - Update documentation for user-visible changes
2249
- - Add tests where applicable
2250
- - Ensure CI passes
2251
-
2252
- See also: [CONTRIBUTING.md](CONTRIBUTING.md), [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
2253
-
2254
- ---
95
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, project structure, and guidelines.
2255
96
 
2256
97
  ## License
2257
98
 
2258
- MIT © TechSpokes
2259
-
2260
- Generated artifacts are fully yours with no restrictions or attribution required.
2261
-
2262
- See [LICENSE](LICENSE) for full text.
2263
-
2264
- ---
2265
-
2266
- ## Sponsors
2267
-
2268
- Support ongoing development and maintenance:
2269
-
2270
- **GitHub Sponsors**: https://github.com/sponsors/TechSpokes
2271
-
2272
- ### Current Sponsors
2273
-
2274
- *Your organization could be featured here!*
2275
-
2276
- ### Why Sponsor?
2277
-
2278
- - Priority support for issues and feature requests
2279
- - Early access to new features
2280
- - Recognition in README and release notes
2281
- - Direct influence on roadmap priorities
2282
- - Support open source sustainability
2283
-
2284
- Thank you for considering sponsorship!
2285
-
2286
- ---
99
+ MIT. See [LICENSE](LICENSE) for full text. Generated artifacts are fully yours with no restrictions or attribution required.
2287
100
 
2288
101
  ## Links
2289
102
 
2290
- - **Documentation**: [README.md](README.md) (you are here)
2291
- - **Contributing Guide**: [CONTRIBUTING.md](CONTRIBUTING.md)
2292
- - **Roadmap**: [ROADMAP.md](ROADMAP.md)
2293
- - **Changelog**: [CHANGELOG.md](CHANGELOG.md)
2294
- - **Security Policy**: [SECURITY.md](SECURITY.md)
2295
- - **Support**: [SUPPORT.md](SUPPORT.md)
2296
- - **Issues**: https://github.com/techspokes/typescript-wsdl-client/issues
2297
- - **Discussions**: https://github.com/techspokes/typescript-wsdl-client/discussions
2298
- - **npm Package**: https://www.npmjs.com/package/@techspokes/typescript-wsdl-client
103
+ - [npm](https://www.npmjs.com/package/@techspokes/typescript-wsdl-client)
104
+ - [Issues](https://github.com/techspokes/typescript-wsdl-client/issues)
105
+ - [Discussions](https://github.com/techspokes/typescript-wsdl-client/discussions)
106
+ - [Changelog](CHANGELOG.md)
107
+ - [Roadmap](ROADMAP.md)
108
+ - [Security](SECURITY.md)
109
+ - [Support](SUPPORT.md)
110
+ - [Sponsor](https://github.com/sponsors/TechSpokes)
2299
111
 
112
+ Vendor: [TechSpokes](https://www.techspokes.com). Maintainer: Serge Liatko ([@sergeliatko](https://github.com/sergeliatko)).