@techspokes/typescript-wsdl-client 0.16.1 → 0.17.0
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 +5 -0
- package/dist/app/generateApp.d.ts.map +1 -1
- package/dist/app/generateApp.js +1 -0
- package/dist/cli.js +46 -2
- package/dist/client/generateClient.d.ts.map +1 -1
- package/dist/client/generateClient.js +62 -6
- package/dist/client/generateOperations.d.ts.map +1 -1
- package/dist/client/generateOperations.js +27 -4
- package/dist/compiler/schemaCompiler.d.ts +40 -11
- package/dist/compiler/schemaCompiler.d.ts.map +1 -1
- package/dist/compiler/schemaCompiler.js +81 -6
- package/dist/compiler/shapeResolver.d.ts +18 -0
- package/dist/compiler/shapeResolver.d.ts.map +1 -0
- package/dist/compiler/shapeResolver.js +280 -0
- package/dist/gateway/generateGateway.d.ts.map +1 -1
- package/dist/gateway/generateGateway.js +2 -1
- package/dist/gateway/generators.d.ts +13 -1
- package/dist/gateway/generators.d.ts.map +1 -1
- package/dist/gateway/generators.js +98 -13
- package/dist/gateway/helpers.d.ts +16 -0
- package/dist/gateway/helpers.d.ts.map +1 -1
- package/dist/gateway/helpers.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -1
- package/dist/openapi/generateOpenAPI.d.ts.map +1 -1
- package/dist/openapi/generateOpenAPI.js +28 -0
- package/dist/pipeline.d.ts +13 -0
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +17 -1
- package/dist/runtime/ndjson.d.ts +24 -0
- package/dist/runtime/ndjson.d.ts.map +1 -0
- package/dist/runtime/ndjson.js +30 -0
- package/dist/runtime/streamXml.d.ts +45 -0
- package/dist/runtime/streamXml.d.ts.map +1 -0
- package/dist/runtime/streamXml.js +212 -0
- package/dist/test/generators.d.ts.map +1 -1
- package/dist/test/generators.js +50 -0
- package/dist/test/mockData.d.ts +6 -0
- package/dist/test/mockData.d.ts.map +1 -1
- package/dist/test/mockData.js +6 -2
- package/dist/util/cli.d.ts.map +1 -1
- package/dist/util/cli.js +3 -1
- package/dist/util/runtimeSource.d.ts +2 -0
- package/dist/util/runtimeSource.d.ts.map +1 -0
- package/dist/util/runtimeSource.js +38 -0
- package/dist/util/streamConfig.d.ts +59 -0
- package/dist/util/streamConfig.d.ts.map +1 -0
- package/dist/util/streamConfig.js +230 -0
- package/docs/README.md +1 -0
- package/docs/api-reference.md +146 -0
- package/docs/architecture.md +27 -5
- package/docs/cli-reference.md +30 -0
- package/docs/concepts.md +51 -0
- package/docs/configuration.md +40 -0
- package/docs/decisions/002-streamable-responses.md +308 -0
- package/docs/gateway-guide.md +37 -0
- package/docs/generated-code.md +21 -0
- package/docs/migration-playbook.md +33 -0
- package/docs/migration.md +31 -6
- package/docs/output-anatomy.md +49 -0
- package/docs/production.md +32 -0
- package/docs/start-here.md +33 -0
- package/docs/supported-patterns.md +2 -0
- package/docs/testing.md +14 -0
- package/docs/troubleshooting.md +18 -0
- package/package.json +5 -2
- package/src/runtime/clientStreamMethods.tpl.txt +183 -0
- package/src/runtime/ndjson.ts +32 -0
- package/src/runtime/operationsStreamHelper.tpl.txt +13 -0
- package/src/runtime/streamXml.ts +293 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# ADR 002: Streamable SOAP Responses and JSON Gateway Output
|
|
2
|
+
|
|
3
|
+
Proposal for opt-in streamable SOAP response support, with Escapia EVRN Content Service as the concrete driver.
|
|
4
|
+
|
|
5
|
+
See the root [README](../../README.md) for the authoritative documentation index and [Architecture](../architecture.md) for the current generator pipeline.
|
|
6
|
+
|
|
7
|
+
## Status
|
|
8
|
+
|
|
9
|
+
Accepted (2026-04-20). Implementation shipped in 0.17.0 across five phases
|
|
10
|
+
(Phase 0 research → Phase 5 integration). See
|
|
11
|
+
`scratches/plans/v017/streamable-responses.plan.yaml` for phase-by-phase
|
|
12
|
+
notes and verification gates.
|
|
13
|
+
|
|
14
|
+
## Context
|
|
15
|
+
|
|
16
|
+
The current generator handles WSDL operations as buffered request and response calls. A generated client method awaits the SOAP runtime callback, receives a fully materialized result object, and returns `{ response, headers, responseRaw, requestRaw }`. The generated OpenAPI document describes each operation as `application/json`. The generated Fastify route calls the client method, optionally unwraps array wrapper types, and returns the standard response envelope.
|
|
17
|
+
|
|
18
|
+
Escapia exposes two related SOAP services:
|
|
19
|
+
|
|
20
|
+
- `EVRNService` contains the normal operation and type model.
|
|
21
|
+
- `EVRNContentService` contains content-oriented operations that are intended for large responses.
|
|
22
|
+
|
|
23
|
+
The Escapia content WSDL includes stream-like operations such as `UnitDescriptiveInfoStream` and `UnitCalendarAvailBatch`. Their output wrapper types contain schema and wildcard payload sections instead of clean concrete response members. The practical record shapes come from the main EVRN service WSDL, for example `UnitDescriptiveContentType` and `UnitCalendarAvailType`.
|
|
24
|
+
|
|
25
|
+
This means the current package has two gaps:
|
|
26
|
+
|
|
27
|
+
- It does not stream SOAP responses through generated clients or gateways.
|
|
28
|
+
- It does not let users map opaque WSDL response wrappers to concrete JSON record shapes from the same or a companion WSDL.
|
|
29
|
+
|
|
30
|
+
## Current Architecture Review
|
|
31
|
+
|
|
32
|
+
The compile stage produces `catalog.json`, which is the only artifact that understands WSDL types, operation input and output elements, attribute metadata, child type metadata, and primitive mapping options.
|
|
33
|
+
|
|
34
|
+
The client stage generates a `node-soap` wrapper. Every operation is generated as a promise-returning method. The public operations interface mirrors that buffered shape, which is useful for mocks but cannot currently express an `AsyncIterable` or stream response.
|
|
35
|
+
|
|
36
|
+
The OpenAPI stage generates paths from catalog operations. It assumes every operation has a JSON request body and a JSON response body. Since version 0.7.1, successful responses are always wrapped in the standard envelope schema.
|
|
37
|
+
|
|
38
|
+
The gateway stage reads the OpenAPI document first and enriches operation metadata from `catalog.json` when the catalog is available. This lets route generation stay OpenAPI-driven, but stream support needs metadata that OpenAPI alone cannot represent.
|
|
39
|
+
|
|
40
|
+
The app and test generators assume ordinary JSON route responses. Generated tests use mock clients that implement the buffered operations interface.
|
|
41
|
+
|
|
42
|
+
## Requirements
|
|
43
|
+
|
|
44
|
+
- Existing buffered generation must remain unchanged unless a user opts in.
|
|
45
|
+
- Stream support must be configurable per operation.
|
|
46
|
+
- Users must be able to map an opaque output wrapper to a concrete record type.
|
|
47
|
+
- Record types must be resolvable from the current catalog or from a companion catalog.
|
|
48
|
+
- Gateway output must be able to emit records before the full SOAP response has arrived.
|
|
49
|
+
- Generated routes must respect Node and Fastify backpressure.
|
|
50
|
+
- OpenAPI output must describe the wire media type without pretending that NDJSON is a single JSON object.
|
|
51
|
+
- Error handling must distinguish errors before the first byte from errors after streaming has started.
|
|
52
|
+
- The feature must be testable with a local chunked SOAP server, not only static XML fixtures.
|
|
53
|
+
|
|
54
|
+
## Proposed Configuration Model
|
|
55
|
+
|
|
56
|
+
Add a stream configuration file passed with `--stream-config`. The same option should be available on `compile`, `client`, `openapi`, `gateway`, and `pipeline` so each stage can be run independently.
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"shapeCatalogs": {
|
|
61
|
+
"evrn": {
|
|
62
|
+
"wsdlSource": "https://api.escapia.com/EVRNService.svc?singleWsdl"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"operations": {
|
|
66
|
+
"UnitDescriptiveInfoStream": {
|
|
67
|
+
"mode": "stream",
|
|
68
|
+
"format": "ndjson",
|
|
69
|
+
"mediaType": "application/x-ndjson",
|
|
70
|
+
"recordType": "UnitDescriptiveContentType",
|
|
71
|
+
"recordPath": [
|
|
72
|
+
"UnitDescriptiveInfoStream",
|
|
73
|
+
"EVRN_UnitDescriptiveInfoRS",
|
|
74
|
+
"UnitDescriptiveContents",
|
|
75
|
+
"UnitDescriptiveContent"
|
|
76
|
+
],
|
|
77
|
+
"shapeCatalog": "evrn"
|
|
78
|
+
},
|
|
79
|
+
"UnitCalendarAvailBatch": {
|
|
80
|
+
"mode": "stream",
|
|
81
|
+
"format": "ndjson",
|
|
82
|
+
"mediaType": "application/x-ndjson",
|
|
83
|
+
"recordType": "UnitCalendarAvailType",
|
|
84
|
+
"recordPath": [
|
|
85
|
+
"EVRN_UnitCalendarAvailBatchRS",
|
|
86
|
+
"EVRN_UnitCalendarAvailBatchRS",
|
|
87
|
+
"UnitCalendarAvails",
|
|
88
|
+
"UnitCalendarAvail"
|
|
89
|
+
],
|
|
90
|
+
"shapeCatalog": "evrn"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`shapeCatalogs` names additional WSDL or catalog inputs used only to resolve stream record shapes.
|
|
97
|
+
|
|
98
|
+
`operations` marks specific WSDL operations as streamed. Operations not listed keep the existing buffered behavior.
|
|
99
|
+
|
|
100
|
+
`recordPath` is an ordered XML element path from the SOAP body payload to the repeated record element. Duplicate local names must be allowed because Escapia uses nested elements with the same name in at least one response.
|
|
101
|
+
|
|
102
|
+
`recordType` is the TypeScript and schema model to emit for each streamed record.
|
|
103
|
+
|
|
104
|
+
`format` should support `ndjson` first. `json-array` can be added later for clients that require a single JSON array response.
|
|
105
|
+
|
|
106
|
+
## CLI and Programmatic API
|
|
107
|
+
|
|
108
|
+
The CLI should add `--stream-config <file>` to all generation commands. The pipeline command should pass the parsed and normalized configuration to every stage.
|
|
109
|
+
|
|
110
|
+
The programmatic API should add optional stream configuration fields to:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
export interface PipelineOptions {
|
|
114
|
+
streamConfigFile?: string;
|
|
115
|
+
streamConfig?: StreamConfig;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface GenerateOpenAPIOptions {
|
|
119
|
+
streamConfigFile?: string;
|
|
120
|
+
streamConfig?: StreamConfig;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface GenerateGatewayOptions {
|
|
124
|
+
streamConfigFile?: string;
|
|
125
|
+
streamConfig?: StreamConfig;
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The compiler options should accept normalized stream metadata only when compilation needs to persist it into the catalog.
|
|
130
|
+
|
|
131
|
+
## Catalog Model
|
|
132
|
+
|
|
133
|
+
The compiled catalog should carry normalized stream metadata beside operation metadata:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
export interface Operation {
|
|
137
|
+
name: string;
|
|
138
|
+
inputTypeName?: string;
|
|
139
|
+
outputTypeName?: string;
|
|
140
|
+
stream?: OperationStreamMetadata;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface OperationStreamMetadata {
|
|
144
|
+
mode: "stream";
|
|
145
|
+
format: "ndjson" | "json-array";
|
|
146
|
+
mediaType: string;
|
|
147
|
+
recordPath: string[];
|
|
148
|
+
recordTypeName: string;
|
|
149
|
+
shapeCatalogName?: string;
|
|
150
|
+
sourceOutputTypeName?: string;
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The compiler should also represent wildcard schema particles explicitly. Today Escapia stream wrappers compile into misleading `xs:schema` properties and drop the wildcard payload. A better model is to retain both the schema marker and a wildcard marker so diagnostics and stream candidate detection are honest.
|
|
155
|
+
|
|
156
|
+
## Shape Resolution
|
|
157
|
+
|
|
158
|
+
The first implementation should support companion catalogs in one of two forms:
|
|
159
|
+
|
|
160
|
+
- A `catalogFile` path for a catalog already produced by `wsdl-tsc compile`.
|
|
161
|
+
- A `wsdlSource` path or URL that the pipeline compiles before normalizing stream metadata.
|
|
162
|
+
|
|
163
|
+
For generated types, the MVP should copy the reachable record type graph from the companion catalog into the current generated output when there is no name collision. If a collision occurs, generation should fail with a clear diagnostic instead of silently renaming public API types.
|
|
164
|
+
|
|
165
|
+
A future version can support external type imports from another generated client directory.
|
|
166
|
+
|
|
167
|
+
## Client Runtime
|
|
168
|
+
|
|
169
|
+
Generated clients should keep the existing buffered method signatures for ordinary operations.
|
|
170
|
+
|
|
171
|
+
Stream operations should return a separate response type:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
export type StreamOperationResponse<RecordType, HeadersType = Record<string, unknown>> = {
|
|
175
|
+
records: AsyncIterable<RecordType>;
|
|
176
|
+
headers: HeadersType;
|
|
177
|
+
requestRaw?: string;
|
|
178
|
+
};
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The operations interface should use the same stream response type so generated gateway tests and user mocks can implement streaming behavior without importing the concrete SOAP client.
|
|
182
|
+
|
|
183
|
+
The transport layer should be proven by a chunked integration test. If `node-soap` with stream or SAX options can deliver records incrementally, it can be used for the MVP. If it buffers before yielding, the feature must use a dedicated SOAP HTTP transport for stream operations before release.
|
|
184
|
+
|
|
185
|
+
> **Phase 0 research outcome (2026-04-20):** `node-soap` **buffers** the full response before invoking the operation callback. Measured with `test/research/node-soap-streaming.test.ts` against a chunked HTTP fixture: first chunk flushed at ~48 ms, server closed at ~701 ms, node-soap callback fired at ~659 ms (~40 ms before close — that is parse time, not streaming). Generated stream operations therefore use a dedicated streaming HTTP transport emitted into the client runtime; `node-soap` remains the transport for buffered operations only. SAX streaming was validated with `saxes` 6.0.0; `test/research/sax-record-path.test.ts` chunk-fuzzes the Escapia-shaped XML (duplicate `EVRN_UnitDescriptiveInfoRS` wrappers) across every single-byte split and every byte-pair split and produces identical records each time. See `scratches/plans/v017/streamable-responses.plan.yaml` for the full findings.
|
|
186
|
+
|
|
187
|
+
## XML to JSON Streaming Conversion
|
|
188
|
+
|
|
189
|
+
The runtime needs a streaming XML parser. `fast-xml-parser` is suitable for buffered documents but not for this use case. A SAX-style parser should track the configured `recordPath`, build a record object as the target element closes, and yield each record immediately.
|
|
190
|
+
|
|
191
|
+
The converter must reuse catalog metadata for:
|
|
192
|
+
|
|
193
|
+
- XML attributes and the configured attributes key
|
|
194
|
+
- Child element type lookup
|
|
195
|
+
- Repeated elements
|
|
196
|
+
- Nillable elements
|
|
197
|
+
- Text content and `$value`
|
|
198
|
+
- Primitive mapping
|
|
199
|
+
|
|
200
|
+
The converter should collect SOAP faults, response errors, and warnings when they appear before the first record. After streaming starts, terminal errors cannot be represented as a normal JSON error envelope for NDJSON. The runtime should either emit a final error record with a documented extension shape or abort the stream and log the classified error.
|
|
201
|
+
|
|
202
|
+
## OpenAPI Output
|
|
203
|
+
|
|
204
|
+
Stream operations should not use the standard success envelope for `200` responses. The response content should use the configured stream media type.
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"description": "Successful streamed SOAP operation response",
|
|
209
|
+
"content": {
|
|
210
|
+
"application/x-ndjson": {
|
|
211
|
+
"schema": { "type": "string" },
|
|
212
|
+
"x-wsdl-tsc-stream": {
|
|
213
|
+
"format": "ndjson",
|
|
214
|
+
"itemSchema": {
|
|
215
|
+
"$ref": "#/components/schemas/UnitDescriptiveContentType"
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
OpenAPI 3.1 cannot fully describe an NDJSON sequence as a standard JSON Schema document. The `x-wsdl-tsc-stream` extension makes the item schema explicit for generated gateways, documentation tools, and future SDK generators.
|
|
224
|
+
|
|
225
|
+
## Gateway Output
|
|
226
|
+
|
|
227
|
+
Generated stream routes should call the stream operation and send a Node stream through Fastify.
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
import { Readable } from "node:stream";
|
|
231
|
+
|
|
232
|
+
handler: async (request, reply) => {
|
|
233
|
+
const client = fastify.escapiaContentClient;
|
|
234
|
+
const result = await client.UnitDescriptiveInfoStream(request.body);
|
|
235
|
+
|
|
236
|
+
reply.type("application/x-ndjson");
|
|
237
|
+
return reply.send(Readable.from(toNdjson(result.records)));
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
The generated operation schema should keep request validation but omit the Fastify response serialization schema for streamed `200` responses. Fastify cannot serialize an unbounded stream with a normal JSON response schema.
|
|
242
|
+
|
|
243
|
+
The gateway runtime should add `toNdjson()` and, later, `toJsonArrayStream()` helpers. These helpers should be deterministic, backpressure-aware, and safe for large payloads.
|
|
244
|
+
|
|
245
|
+
## Test Strategy
|
|
246
|
+
|
|
247
|
+
Add unit tests for stream config parsing, operation matching, catalog normalization, wildcard compiler metadata, and record path matching.
|
|
248
|
+
|
|
249
|
+
Add converter tests that split XML chunks across element boundaries to prove the parser does not rely on convenient chunking.
|
|
250
|
+
|
|
251
|
+
Add a local Escapia-like WSDL fixture with `xs:any` output wrappers and a companion WSDL fixture with the concrete record types.
|
|
252
|
+
|
|
253
|
+
Add an integration test with a fake SOAP HTTP server that writes one record, waits, writes another record, and then closes the envelope. The test should assert that the gateway emits the first NDJSON line before the upstream response completes.
|
|
254
|
+
|
|
255
|
+
Add snapshot tests for generated `client.ts`, `operations.ts`, OpenAPI output, gateway route files, and gateway runtime helpers.
|
|
256
|
+
|
|
257
|
+
Run `npm run smoke:pipeline` after implementation to verify ordinary buffered generation is unchanged.
|
|
258
|
+
|
|
259
|
+
## Implementation Plan
|
|
260
|
+
|
|
261
|
+
1. Define `StreamConfig`, parser, validation errors, and normalized operation metadata.
|
|
262
|
+
2. Add `--stream-config` to the CLI and thread it through the programmatic API.
|
|
263
|
+
3. Update the compiler to preserve wildcard particles and emit stream candidate diagnostics.
|
|
264
|
+
4. Implement companion catalog loading and record type graph copying.
|
|
265
|
+
5. Generate stream method signatures in `client.ts` and `operations.ts`.
|
|
266
|
+
6. Add a streaming XML converter with catalog-aware JSON shape conversion.
|
|
267
|
+
7. Generate OpenAPI stream responses with `x-wsdl-tsc-stream` metadata.
|
|
268
|
+
8. Generate Fastify streaming handlers and runtime helpers.
|
|
269
|
+
9. Add unit, snapshot, and chunked integration tests.
|
|
270
|
+
10. Update README, CLI reference, configuration docs, gateway guide, testing guide, and supported patterns.
|
|
271
|
+
|
|
272
|
+
## Acceptance Criteria
|
|
273
|
+
|
|
274
|
+
- Existing generated output is unchanged when no stream config is provided.
|
|
275
|
+
- A stream-configured Escapia content WSDL generates typed stream client methods.
|
|
276
|
+
- The generated gateway emits `application/x-ndjson` records incrementally.
|
|
277
|
+
- The generated OpenAPI document identifies stream operations and record schemas.
|
|
278
|
+
- The converter maps XML attributes, arrays, text values, and nillable values consistently with buffered responses.
|
|
279
|
+
- The chunked integration test proves the first record is sent before the full SOAP response is available.
|
|
280
|
+
- Stream route errors before the first byte use the normal gateway error envelope.
|
|
281
|
+
- Stream route errors after the first byte follow a documented terminal error policy.
|
|
282
|
+
|
|
283
|
+
## Consequences
|
|
284
|
+
|
|
285
|
+
The generator gains a second response execution model. This increases complexity in the client, OpenAPI, gateway, and test generators, but keeps the complexity opt-in and operation-scoped.
|
|
286
|
+
|
|
287
|
+
The catalog becomes more important as the shared source of truth because OpenAPI alone cannot carry enough stream conversion metadata.
|
|
288
|
+
|
|
289
|
+
NDJSON becomes the recommended stream format because it is simple, broadly consumable, and does not require buffering a complete JSON array before sending data.
|
|
290
|
+
|
|
291
|
+
Companion catalogs are required for vendors that split stream wrappers and concrete record shapes across separate WSDLs.
|
|
292
|
+
|
|
293
|
+
## Implementation Notes
|
|
294
|
+
|
|
295
|
+
Captured after the 0.17.0 ship for future maintainers:
|
|
296
|
+
|
|
297
|
+
- `--stream-config` is wired onto the `compile`, `client`, and `pipeline` CLI commands. It is intentionally not accepted on `openapi`, `gateway`, or `app` because those commands consume a pre-compiled `catalog.json` that already carries the normalized `OperationStreamMetadata`. The original proposal text that listed the flag on every command reflected the design intent; the shipped surface is narrower for that reason.
|
|
298
|
+
- `GenerateOpenAPIOptions` and `GenerateGatewayOptions` in the programmatic API do not carry stream-config fields for the same reason. `compileWsdlToProject` and `runGenerationPipeline` (PipelineOptions) do.
|
|
299
|
+
- The client stream transport is emitted from two templates (`clientStreamMethods.tpl.txt`, `operationsStreamHelper.tpl.txt`). They embed the `StreamOperationResponse<T>` type and a `callStream()` method that POSTs a hand-built SOAP envelope via global `fetch`, bypassing `node-soap` as required by the phase-0 finding.
|
|
300
|
+
- `saxes ^6.0.0` was promoted from devDependency to runtime dependency on the package, and added as a pinned dependency in the generated app scaffold so stream-enabled consumers install it automatically.
|
|
301
|
+
- The `json-array` format is reserved in the config parser but not yet implemented by the emitters. Entries using `format: "json-array"` parse successfully and can be used to forward-declare intent; they do not currently generate routes or client methods.
|
|
302
|
+
|
|
303
|
+
## References
|
|
304
|
+
|
|
305
|
+
- Escapia EVRN API documentation: <https://eweb.escapia.com/distribution/api/evrn-api-documentation>
|
|
306
|
+
- Escapia EVRN service WSDL: <https://api.escapia.com/EVRNService.svc?WSDL>
|
|
307
|
+
- Escapia EVRN content service WSDL: <https://api.escapia.com/EVRNContentService.svc?WSDL>
|
|
308
|
+
- Escapia batch API support article: <https://support.escapia.com/articles/en_US/Article/HASW-Batch-API-Methods-EVRN?category=Website_Services>
|
package/docs/gateway-guide.md
CHANGED
|
@@ -81,6 +81,43 @@ export async function registerRoute_v1_weather_getcityforecastbyzip(fastify: Fas
|
|
|
81
81
|
}
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
+
### Streaming Handlers
|
|
85
|
+
|
|
86
|
+
Operations opted in via `--stream-config` emit an NDJSON response pipe
|
|
87
|
+
instead of the standard envelope. The generated handler streams records as
|
|
88
|
+
they arrive, and the Fastify response is flushed line-by-line with
|
|
89
|
+
backpressure (ADR-002).
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import type { FastifyInstance } from "fastify";
|
|
93
|
+
import type { GetWeatherInformation } from "../../client/types.js";
|
|
94
|
+
import schema from "../schemas/operations/getweatherinformation.json" with { type: "json" };
|
|
95
|
+
import { toNdjson } from "../runtime.js";
|
|
96
|
+
|
|
97
|
+
// Response schema omitted: stream operations emit NDJSON, not a single JSON object
|
|
98
|
+
const { response: _response, ...routeSchema } = schema as Record<string, unknown>;
|
|
99
|
+
|
|
100
|
+
export async function registerRoute_v1_weather_getweatherinformation(fastify: FastifyInstance) {
|
|
101
|
+
fastify.route<{ Body: GetWeatherInformation }>({
|
|
102
|
+
method: "POST",
|
|
103
|
+
url: "/get-weather-information",
|
|
104
|
+
schema: routeSchema,
|
|
105
|
+
handler: async (request, reply) => {
|
|
106
|
+
const client = fastify.weatherClient;
|
|
107
|
+
const result = await client.GetWeatherInformation(request.body as GetWeatherInformation);
|
|
108
|
+
reply.type("application/x-ndjson");
|
|
109
|
+
return reply.send(toNdjson(result.records));
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The client method returns `StreamOperationResponse<RecordType>` with a
|
|
116
|
+
`records: AsyncIterable<RecordType>`. Errors raised before the first record
|
|
117
|
+
use the normal error envelope; errors raised mid-stream trip the chunked
|
|
118
|
+
response's truncation — consumers detect these via the absence of a clean
|
|
119
|
+
terminating zero-chunk.
|
|
120
|
+
|
|
84
121
|
## Error Handling
|
|
85
122
|
|
|
86
123
|
The centralized error handler (runtime.ts) automatically classifies errors:
|
package/docs/generated-code.md
CHANGED
|
@@ -36,6 +36,23 @@ const info = await client.GetWeatherInformation({});
|
|
|
36
36
|
console.log(info.GetWeatherInformationResult.WeatherDescriptions);
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
## Calling Stream Operations
|
|
40
|
+
|
|
41
|
+
Operations opted into streaming with `--stream-config` return `StreamOperationResponse<RecordType>` instead of the buffered shape. `records` is a single-pass `AsyncIterable<RecordType>` that pulls bytes from the upstream SOAP response on demand, so memory stays bounded regardless of payload size.
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
const result = await client.UnitDescriptiveInfoStream({});
|
|
45
|
+
for await (const record of result.records) {
|
|
46
|
+
console.log(record);
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Because `records` is single-pass, each response can be iterated once. Headers captured before the first record are available on `result.headers`, and the serialized SOAP envelope that was sent upstream is on `result.requestRaw` when populated.
|
|
51
|
+
|
|
52
|
+
Streaming requires the `saxes` runtime dependency. The generated app scaffold pins `saxes ^6.0.0` automatically; consumers that integrate the generated client into their own project must install it explicitly.
|
|
53
|
+
|
|
54
|
+
See [Stream Configuration](configuration.md#stream-configuration) for how to opt specific operations in, and [ADR-002](decisions/002-streamable-responses.md) for the rationale and terminal-error policy.
|
|
55
|
+
|
|
39
56
|
## Attributes and Text Content
|
|
40
57
|
|
|
41
58
|
When an element has both attributes and text content, use the $value convention:
|
|
@@ -134,6 +151,8 @@ Key features of the generated handlers:
|
|
|
134
151
|
- Envelope wrapping: `buildSuccessEnvelope()` wraps the raw SOAP response in the standard `{ status, message, data, error }` envelope
|
|
135
152
|
- Route file header comments include propagated operation summary and description when present
|
|
136
153
|
|
|
154
|
+
Stream-configured operations generate a different handler shape: the response serialization schema is omitted, `reply.type("application/x-ndjson")` is set, and `reply.send(toNdjson(result.records))` streams records with backpressure. See the [Gateway Guide Streaming Handlers section](gateway-guide.md#streaming-handlers) for the full example and terminal-error policy.
|
|
155
|
+
|
|
137
156
|
See [Gateway Guide](gateway-guide.md) for the full architecture and [CLI Reference](cli-reference.md) for generation flags.
|
|
138
157
|
|
|
139
158
|
## Operations Interface
|
|
@@ -158,4 +177,6 @@ The gateway plugin accepts any `WeatherOperations` implementation, so you can pa
|
|
|
158
177
|
app.register(weatherGateway, { client: mock });
|
|
159
178
|
```
|
|
160
179
|
|
|
180
|
+
For stream operations, mock implementations return an async-iterable `records` field. See the [Testing Guide](testing.md) for the full pattern with async generators.
|
|
181
|
+
|
|
161
182
|
See [Testing Guide](testing.md) for full integration test patterns.
|
|
@@ -58,6 +58,39 @@ Open `openapi.json` and review the paths, request/response schemas, and descript
|
|
|
58
58
|
|
|
59
59
|
Validate the spec with any OpenAPI tool. Built-in validation runs by default; disable with `--openapi-validate false` if you need to inspect an intermediate state.
|
|
60
60
|
|
|
61
|
+
## Step 2b (Optional): Opt Into Streaming for Large Responses
|
|
62
|
+
|
|
63
|
+
Skip this step unless a specific SOAP operation returns payloads too large or too slow to buffer in memory. Good candidates are batch-style operations with repeated record elements, responses that use `xs:any` wildcards to point at concrete records in a companion WSDL, and any operation where first-byte latency matters more than total duration.
|
|
64
|
+
|
|
65
|
+
Author a stream config naming those operations:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"operations": {
|
|
70
|
+
"MyBatchOp": {
|
|
71
|
+
"recordType": "MyRecordType",
|
|
72
|
+
"recordPath": ["MyBatchOpResponse", "Records", "Record"]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Regenerate with `--stream-config`:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npx wsdl-tsc pipeline \
|
|
82
|
+
--wsdl-source your-service.wsdl \
|
|
83
|
+
--client-dir ./generated/client \
|
|
84
|
+
--openapi-file ./generated/openapi.json \
|
|
85
|
+
--gateway-dir ./generated/gateway \
|
|
86
|
+
--gateway-service-name your-service \
|
|
87
|
+
--gateway-version-prefix v1 \
|
|
88
|
+
--stream-config ./stream.config.json \
|
|
89
|
+
--init-app
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The opted-in operations now return `StreamOperationResponse<RecordType>` on the client, serve `application/x-ndjson` on the gateway, and advertise the record schema in OpenAPI via `x-wsdl-tsc-stream`. Operations not listed in the config are unchanged. See [Stream Configuration](configuration.md#stream-configuration) for the full file reference and [ADR-002](decisions/002-streamable-responses.md) for the terminal-error policy.
|
|
93
|
+
|
|
61
94
|
## Step 3: Generate the REST Gateway
|
|
62
95
|
|
|
63
96
|
Generate Fastify route handlers that translate JSON HTTP requests into SOAP calls.
|
package/docs/migration.md
CHANGED
|
@@ -16,12 +16,37 @@ These steps apply to every version upgrade:
|
|
|
16
16
|
|
|
17
17
|
## Version Compatibility
|
|
18
18
|
|
|
19
|
-
| wsdl-tsc | Node.js | TypeScript | soap | Fastify |
|
|
20
|
-
|
|
21
|
-
| 0.
|
|
22
|
-
| 0.
|
|
23
|
-
| 0.
|
|
24
|
-
| 0.
|
|
19
|
+
| wsdl-tsc | Node.js | TypeScript | soap | Fastify | saxes |
|
|
20
|
+
|----------|---------|------------|------|---------|-------|
|
|
21
|
+
| 0.17.x | >= 20.0 | >= 6.0 | >= 1.9 | >= 5.8 | >= 6.0 |
|
|
22
|
+
| 0.16.x | >= 20.0 | >= 6.0 | >= 1.9 | >= 5.8 | N/A |
|
|
23
|
+
| 0.15.x | >= 20.0 | >= 6.0 | >= 1.8 | >= 5.4 | N/A |
|
|
24
|
+
| 0.11.x to 0.14.x | >= 20.0 | >= 5.6 | >= 1.3 | >= 5.2 | N/A |
|
|
25
|
+
| 0.10.x | >= 20.0 | >= 5.6 | >= 1.3 | >= 5.2 | N/A |
|
|
26
|
+
| 0.9.x | >= 20.0 | >= 5.6 | >= 1.3 | >= 5.2 | N/A |
|
|
27
|
+
| 0.8.x | >= 20.0 | >= 5.6 | >= 1.3 | >= 5.2 | N/A |
|
|
28
|
+
| 0.7.x | >= 20.0 | >= 5.6 | >= 1.3 | N/A | N/A |
|
|
29
|
+
|
|
30
|
+
Versions 0.11 through 0.16 are additive and non-breaking. See `CHANGELOG.md` for per-version detail rather than dedicated upgrade sections here.
|
|
31
|
+
|
|
32
|
+
## Upgrading to 0.17.x from 0.16.x
|
|
33
|
+
|
|
34
|
+
This upgrade adds opt-in streamable SOAP responses. No breaking changes; generated output is byte-for-byte unchanged when `--stream-config` is not provided.
|
|
35
|
+
|
|
36
|
+
### What Changed in 0.17.x
|
|
37
|
+
|
|
38
|
+
The CLI gains a `--stream-config <file>` flag on `compile`, `client`, and `pipeline`. Operations listed in that file emit a new client method signature returning `StreamOperationResponse<RecordType>` with `records: AsyncIterable<RecordType>`, an OpenAPI 200 response typed as `application/x-ndjson` with an `x-wsdl-tsc-stream` extension, and a Fastify route that streams NDJSON with backpressure. The compiler now retains `xs:any` wildcard particles on compiled types (previously dropped silently), enabling honest stream-candidate detection and companion-catalog shape resolution. `saxes ^6.0.0` is now a runtime dependency of the package and is pinned automatically into the generated app scaffold.
|
|
39
|
+
|
|
40
|
+
### Steps to Upgrade to 0.17.x
|
|
41
|
+
|
|
42
|
+
1. Update the package and regenerate; no flag or code changes are required for buffered operations
|
|
43
|
+
2. If consumers integrate the generated client directly (not via the app scaffold), install `saxes ^6.0.0` as a runtime dependency before using any stream operation
|
|
44
|
+
3. To opt into streaming for specific operations, author a stream-config file (see [Stream Configuration](configuration.md#stream-configuration)) and pass it via `--stream-config`
|
|
45
|
+
4. Review the new generated client method signatures for any opted-in operation; consumers must use `for await (const record of result.records)` instead of awaiting the full response
|
|
46
|
+
|
|
47
|
+
### Is 0.17.x Breaking?
|
|
48
|
+
|
|
49
|
+
No. Without `--stream-config`, generated output is byte-for-byte unchanged. Consumers only see new surfaces when they opt in.
|
|
25
50
|
|
|
26
51
|
## Upgrading to 0.10.x from 0.9.x
|
|
27
52
|
|
package/docs/output-anatomy.md
CHANGED
|
@@ -43,6 +43,24 @@ Exports a TypeScript interface with the same method signatures as the client cla
|
|
|
43
43
|
|
|
44
44
|
Contains runtime metadata and helper functions. Includes `unwrapArrayWrappers()` for bridging between SOAP array wrapper objects and flattened OpenAPI array schemas.
|
|
45
45
|
|
|
46
|
+
### Stream Operations
|
|
47
|
+
|
|
48
|
+
When `--stream-config` opts an operation into streaming (see [ADR-002](decisions/002-streamable-responses.md)), the client emits additional surfaces alongside the buffered ones. Buffered operations in the same client are unaffected.
|
|
49
|
+
|
|
50
|
+
`operations.ts` gains a `StreamOperationResponse<RecordType>` type that stream methods return instead of the buffered `{ response, headers, responseRaw, requestRaw }` shape:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
export type StreamOperationResponse<RecordType, HeadersType = Record<string, unknown>> = {
|
|
54
|
+
records: AsyncIterable<RecordType>;
|
|
55
|
+
headers: HeadersType;
|
|
56
|
+
requestRaw?: string;
|
|
57
|
+
};
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`client.ts` gains a protected `callStream()` transport. Stream methods bypass `node-soap` (which buffers the full response before invoking its callback, as confirmed in phase-0 research) and instead POST a hand-built SOAP envelope via global `fetch`, piping the response body through a SAX-driven record parser. `node-soap` remains the transport for buffered operations.
|
|
61
|
+
|
|
62
|
+
Generated imports required at runtime: `saxes` for SAX parsing. The generated app scaffold pins `saxes ^6.0.0` automatically; manual consumers must install it explicitly.
|
|
63
|
+
|
|
46
64
|
## OpenAPI Output
|
|
47
65
|
|
|
48
66
|
Generated at the path specified by `--openapi-file`.
|
|
@@ -55,6 +73,29 @@ The spec includes one POST path per WSDL operation, request and response schemas
|
|
|
55
73
|
|
|
56
74
|
OpenAPI validation runs by default using `@apidevtools/swagger-parser`. Disable with `--openapi-validate false`.
|
|
57
75
|
|
|
76
|
+
### Stream Schema Extension
|
|
77
|
+
|
|
78
|
+
Stream operations do not use the standard success envelope for `200` responses. The response content declares the configured stream media type (default `application/x-ndjson`) with `schema: { "type": "string" }` and an `x-wsdl-tsc-stream` extension that carries the record schema reference:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"200": {
|
|
83
|
+
"description": "Successful streamed SOAP operation response",
|
|
84
|
+
"content": {
|
|
85
|
+
"application/x-ndjson": {
|
|
86
|
+
"schema": { "type": "string" },
|
|
87
|
+
"x-wsdl-tsc-stream": {
|
|
88
|
+
"format": "ndjson",
|
|
89
|
+
"itemSchema": { "$ref": "#/components/schemas/UnitDescriptiveContentType" }
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
OpenAPI 3.1 cannot fully describe an NDJSON sequence as a standard JSON Schema document, so the extension makes the item schema explicit for generated gateways, documentation tools, and future SDK generators. Error responses (400, 502, and the rest) still use the normal envelope.
|
|
98
|
+
|
|
58
99
|
## Gateway Output
|
|
59
100
|
|
|
60
101
|
Generated into the directory specified by `--gateway-dir`.
|
|
@@ -74,6 +115,14 @@ Generated into the directory specified by `--gateway-dir`.
|
|
|
74
115
|
|
|
75
116
|
Each route file in `routes/` follows the same pattern: validate the JSON request body against the operation schema, call the corresponding SOAP operation via the typed client, transform the SOAP response to JSON, and return it with the appropriate response schema.
|
|
76
117
|
|
|
118
|
+
### Stream Routes
|
|
119
|
+
|
|
120
|
+
Stream-configured operations generate a different route shape. The Fastify response serialization schema is omitted because Fastify cannot serialize an unbounded stream with a normal JSON response schema. The handler sets `reply.type("application/x-ndjson")` and returns `reply.send(toNdjson(result.records))`. `runtime.ts` gains a `toNdjson<T>(records: AsyncIterable<T>): Readable` helper that wraps the async iterable in a backpressure-aware Node `Readable`. See the [Gateway Guide](gateway-guide.md#streaming-handlers) for the full handler example and terminal-error policy.
|
|
121
|
+
|
|
122
|
+
### Generated Test Surface
|
|
123
|
+
|
|
124
|
+
When `--test-dir` is combined with `--stream-config`, the generated happy-path tests for stream operations assert on the `application/x-ndjson` content-type and parse each line as a separate JSON record. Mock clients use async-generator overrides that yield records to drive those tests; see the [Testing Guide](testing.md) for the pattern.
|
|
125
|
+
|
|
77
126
|
### Plugin registration
|
|
78
127
|
|
|
79
128
|
The generated plugin exports a Fastify plugin function. Register it with your Fastify app and provide a client instance (real or mock) and a route prefix.
|
package/docs/production.md
CHANGED
|
@@ -61,6 +61,30 @@ npx wsdl-tsc openapi --catalog-file ./build/catalog.json --openapi-file ./docs/a
|
|
|
61
61
|
}
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
## Streaming Operations
|
|
65
|
+
|
|
66
|
+
Operations opted into streaming with `--stream-config` change the production profile of the gateway. Plan for these characteristics before rolling out.
|
|
67
|
+
|
|
68
|
+
### Backpressure
|
|
69
|
+
|
|
70
|
+
Records flow through `Readable.from` in the generated `runtime.ts`. The iterator's `next()` is not called until the internal buffer has room, so a slow HTTP client propagates backpressure all the way to the upstream SOAP server. A client that opens a connection and stops reading will eventually stall the upstream SOAP socket; set idle timeouts on both the gateway and the SOAP endpoint accordingly.
|
|
71
|
+
|
|
72
|
+
### Connection Timeouts
|
|
73
|
+
|
|
74
|
+
Stream responses can stay open for the full duration of the upstream SOAP call. The Fastify `keepAliveTimeout`, `requestTimeout`, and any reverse proxy (nginx, ALB, CloudFront) must allow the maximum expected upstream duration. Default Fastify timeouts are shorter than typical long-running SOAP batch responses.
|
|
75
|
+
|
|
76
|
+
### Memory Profile
|
|
77
|
+
|
|
78
|
+
Memory stays bounded regardless of payload size because records are parsed and emitted one at a time. The SAX parser buffers only within the current record element. This is the primary reason to opt into streaming: buffered operations load the full response into memory before yielding.
|
|
79
|
+
|
|
80
|
+
### Observability
|
|
81
|
+
|
|
82
|
+
Log the time to first record, not just the time to response completion. First-record time is the most useful SLO signal because it measures the combined latency of upstream connect, first-byte, and parser spin-up. Track it separately from total stream duration.
|
|
83
|
+
|
|
84
|
+
### Terminal-Error Policy
|
|
85
|
+
|
|
86
|
+
Errors raised before the first record use the normal gateway error envelope (client sees a standard JSON error). Errors raised mid-stream truncate the chunked response without a terminating zero-chunk. Consumers detect this as an incomplete HTTP response. Document this behavior for downstream API consumers so they distinguish truncation from a legitimate empty stream.
|
|
87
|
+
|
|
64
88
|
## Known Limitations
|
|
65
89
|
|
|
66
90
|
### Choice Elements
|
|
@@ -78,3 +102,11 @@ Security hints extracted from policies. Custom policies may require manual secur
|
|
|
78
102
|
### Array Wrapper Flattening
|
|
79
103
|
|
|
80
104
|
Single-child sequences with maxOccurs>1 become array schemas. Sequences with multiple children preserve wrapper.
|
|
105
|
+
|
|
106
|
+
### Stream Format Coverage
|
|
107
|
+
|
|
108
|
+
Only `ndjson` is emitted today. `json-array` is reserved in the config schema but not yet implemented; opting in with `format: "json-array"` parses successfully but generates no routes for that operation.
|
|
109
|
+
|
|
110
|
+
### Stream Transport Bypasses node-soap
|
|
111
|
+
|
|
112
|
+
Stream operations bypass `node-soap` entirely and POST a hand-built SOAP envelope via `fetch`. Any `node-soap` middleware, interceptors, or custom security handlers that your buffered operations rely on will not apply to stream operations. Authentication headers, proxies, and TLS options must be configured on the stream transport path separately.
|
package/docs/start-here.md
CHANGED
|
@@ -64,6 +64,38 @@ The gateway transforms JSON HTTP requests into SOAP calls and returns JSON respo
|
|
|
64
64
|
|
|
65
65
|
Next: [Gateway Guide](gateway-guide.md) for integration details, then [Migration Playbook](migration-playbook.md) for the full modernization workflow
|
|
66
66
|
|
|
67
|
+
### I need to stream large SOAP responses
|
|
68
|
+
|
|
69
|
+
Some SOAP services return payloads that are too large or too slow to buffer in memory. Opt selected operations into streaming with a small JSON config and the `--stream-config` flag. Operations not listed keep their buffered behavior, so existing output stays byte-for-byte unchanged.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx wsdl-tsc pipeline \
|
|
73
|
+
--wsdl-source your-service.wsdl \
|
|
74
|
+
--client-dir ./generated/client \
|
|
75
|
+
--openapi-file ./generated/openapi.json \
|
|
76
|
+
--gateway-dir ./generated/gateway \
|
|
77
|
+
--gateway-service-name my-service \
|
|
78
|
+
--gateway-version-prefix v1 \
|
|
79
|
+
--stream-config ./stream.config.json
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Minimal `stream.config.json`:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"operations": {
|
|
87
|
+
"MyStreamOp": {
|
|
88
|
+
"recordType": "MyRecordType",
|
|
89
|
+
"recordPath": ["MyStreamOpResponse", "Records", "Record"]
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Stream operations return `StreamOperationResponse<RecordType>` on the client (`records: AsyncIterable<RecordType>`), emit `application/x-ndjson` on the gateway, and advertise the record schema in OpenAPI via the `x-wsdl-tsc-stream` extension.
|
|
96
|
+
|
|
97
|
+
Next: [ADR-002: Streamable Responses](decisions/002-streamable-responses.md) for rationale and terminal-error policy, then [Stream Configuration](configuration.md#stream-configuration) for the full file reference.
|
|
98
|
+
|
|
67
99
|
## What NOT to Expect
|
|
68
100
|
|
|
69
101
|
This package does not replace a full API management platform. It does not provide rate limiting, policy enforcement, or multi-language SDK generation. It generates code; it does not run a proxy or manage deployments.
|
|
@@ -80,3 +112,4 @@ For more on scope boundaries, see the "When NOT to Use This" section of the [REA
|
|
|
80
112
|
| Plan a full SOAP-to-REST migration | [Migration Playbook](migration-playbook.md) |
|
|
81
113
|
| Set up testing for generated code | [Testing Guide](testing.md) |
|
|
82
114
|
| Review all CLI flags | [CLI Reference](cli-reference.md) |
|
|
115
|
+
| Opt specific operations into NDJSON streaming | [ADR-002](decisions/002-streamable-responses.md) and [Stream Configuration](configuration.md#stream-configuration) |
|
|
@@ -19,6 +19,8 @@ These patterns are handled end-to-end: WSDL parsing, TypeScript type generation,
|
|
|
19
19
|
- Circular type references detected and broken with minimal stub types
|
|
20
20
|
- Multiple WSDL ports and bindings; the first SOAP binding is selected, all ports are documented in service metadata
|
|
21
21
|
- SOAP 1.1 and SOAP 1.2 binding detection
|
|
22
|
+
- Streamable SOAP responses, opt-in per operation via `--stream-config` (ADR-002): client exposes `AsyncIterable<RecordType>`, gateway emits NDJSON with backpressure, OpenAPI advertises the record schema via `x-wsdl-tsc-stream`
|
|
23
|
+
- `xs:any` wildcard particles retained on compiled types (they used to be dropped silently) — enables honest stream-candidate detection and companion-catalog shape resolution
|
|
22
24
|
|
|
23
25
|
### Named simple types and same-name elements
|
|
24
26
|
|