@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,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Companion-catalog shape resolver (phase-2 of ADR-002).
|
|
3
|
+
*
|
|
4
|
+
* For stream operations whose record types live in a different WSDL (e.g.
|
|
5
|
+
* Escapia's main EVRN service provides the concrete UnitDescriptiveContentType
|
|
6
|
+
* while the content-service WSDL only exposes an xs:any-wrapped envelope),
|
|
7
|
+
* load the companion catalog and copy the reachable record-type graph into
|
|
8
|
+
* the current catalog.
|
|
9
|
+
*
|
|
10
|
+
* Invariants:
|
|
11
|
+
* - A name collision against a type already in the current catalog is only
|
|
12
|
+
* allowed when the two types are *structurally identical* — otherwise we
|
|
13
|
+
* fail the build rather than silently rename public API types.
|
|
14
|
+
* - Existing buffered generation stays byte-for-byte identical when no
|
|
15
|
+
* streamConfig.shapeCatalogs entries are declared.
|
|
16
|
+
*/
|
|
17
|
+
import fs from "node:fs";
|
|
18
|
+
import path from "node:path";
|
|
19
|
+
import { compileCatalog } from "./schemaCompiler.js";
|
|
20
|
+
import { loadWsdl } from "../loader/wsdlLoader.js";
|
|
21
|
+
import { resolveCompilerOptions } from "../config.js";
|
|
22
|
+
import { WsdlCompilationError } from "../util/errors.js";
|
|
23
|
+
/**
|
|
24
|
+
* Apply a parsed StreamConfig to a compiled catalog:
|
|
25
|
+
* 1. Verify every opted-in operation's record type is resolvable.
|
|
26
|
+
* 2. For each operation that names a shapeCatalog, load the companion
|
|
27
|
+
* catalog (once, cached) and copy the reachable record-type graph.
|
|
28
|
+
*
|
|
29
|
+
* Mutates `compiled` in place. Safe to call with a StreamConfig that has
|
|
30
|
+
* zero shapeCatalogs — it will still validate record-type presence against
|
|
31
|
+
* the current catalog.
|
|
32
|
+
*/
|
|
33
|
+
export async function applyShapeCatalogs(compiled, streamConfig, options = {}) {
|
|
34
|
+
const baseDir = options.baseDir ?? process.cwd();
|
|
35
|
+
// Load each declared shape catalog once, on-demand. Shape catalogs declared
|
|
36
|
+
// but never referenced are harmless — we only load the ones an operation
|
|
37
|
+
// actually uses.
|
|
38
|
+
const referencedCatalogs = new Set();
|
|
39
|
+
for (const meta of Object.values(streamConfig.operations)) {
|
|
40
|
+
if (meta.shapeCatalogName)
|
|
41
|
+
referencedCatalogs.add(meta.shapeCatalogName);
|
|
42
|
+
}
|
|
43
|
+
const companionByName = new Map();
|
|
44
|
+
for (const name of referencedCatalogs) {
|
|
45
|
+
const ref = streamConfig.shapeCatalogs[name];
|
|
46
|
+
if (!ref) {
|
|
47
|
+
throw new WsdlCompilationError(`Stream config references shape catalog "${name}" that is not declared under "shapeCatalogs".`, {
|
|
48
|
+
suggestion: `Add a "shapeCatalogs.${name}" entry pointing to a wsdlSource or catalogFile, or remove the reference.`,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
companionByName.set(name, await loadCompanionCatalog(name, ref, baseDir, compiled));
|
|
52
|
+
}
|
|
53
|
+
for (const [opName, meta] of Object.entries(streamConfig.operations)) {
|
|
54
|
+
if (meta.shapeCatalogName) {
|
|
55
|
+
const companion = companionByName.get(meta.shapeCatalogName);
|
|
56
|
+
if (!companion) {
|
|
57
|
+
// Guarded by the loop above; this path is defensive.
|
|
58
|
+
throw new WsdlCompilationError(`Stream config for "${opName}" references shape catalog "${meta.shapeCatalogName}" which failed to load.`);
|
|
59
|
+
}
|
|
60
|
+
copyReachableGraph(compiled, companion, meta.recordTypeName, {
|
|
61
|
+
opName,
|
|
62
|
+
shapeCatalog: meta.shapeCatalogName,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// No companion: the record type must already live in the main catalog.
|
|
67
|
+
if (!hasNamedType(compiled, meta.recordTypeName)) {
|
|
68
|
+
throw new WsdlCompilationError(`Stream config for operation "${opName}" references record type "${meta.recordTypeName}" which is not present in the compiled catalog.`, {
|
|
69
|
+
element: meta.recordTypeName,
|
|
70
|
+
suggestion: `Either declare a "shapeCatalogs.<name>" entry and set shapeCatalog on the operation, or correct the recordType to a type defined in the WSDL.`,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function loadCompanionCatalog(name, ref, baseDir, compiled) {
|
|
77
|
+
if (ref.catalogFile) {
|
|
78
|
+
const abs = path.resolve(baseDir, ref.catalogFile);
|
|
79
|
+
let text;
|
|
80
|
+
try {
|
|
81
|
+
text = fs.readFileSync(abs, "utf-8");
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
throw new WsdlCompilationError(`Failed to read companion catalog "${name}" at ${abs}: ${err.message}`, { suggestion: `Check that shapeCatalogs.${name}.catalogFile points to an existing catalog.json.` });
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
return JSON.parse(text);
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
throw new WsdlCompilationError(`Companion catalog "${name}" at ${abs} is not valid JSON: ${err.message}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (ref.wsdlSource) {
|
|
94
|
+
// Relative paths resolve against baseDir; URLs pass through untouched.
|
|
95
|
+
const src = isLikelyUrl(ref.wsdlSource) ? ref.wsdlSource : path.resolve(baseDir, ref.wsdlSource);
|
|
96
|
+
const wsdlCatalog = await loadWsdl(src);
|
|
97
|
+
// Reuse the current catalog's compiler options so primitives / attrs keys
|
|
98
|
+
// / choice handling stay consistent with the main generation.
|
|
99
|
+
const companionOptions = resolveCompilerOptions({ ...compiled.options, catalog: false }, { wsdl: src, out: baseDir });
|
|
100
|
+
return compileCatalog(wsdlCatalog, companionOptions);
|
|
101
|
+
}
|
|
102
|
+
throw new WsdlCompilationError(`Shape catalog "${name}" declares neither wsdlSource nor catalogFile.`);
|
|
103
|
+
}
|
|
104
|
+
function isLikelyUrl(s) {
|
|
105
|
+
return /^[a-z][a-z0-9+.-]*:\/\//i.test(s);
|
|
106
|
+
}
|
|
107
|
+
function hasNamedType(cat, name) {
|
|
108
|
+
return cat.types.some((t) => t.name === name) || cat.aliases.some((a) => a.name === name);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Walk the reachable type graph from `rootTypeName` within the companion
|
|
112
|
+
* catalog and copy each reachable entry into `dst`. Types with the same name
|
|
113
|
+
* already present in `dst` are checked for structural equality; any divergence
|
|
114
|
+
* is fatal.
|
|
115
|
+
*/
|
|
116
|
+
function copyReachableGraph(dst, src, rootTypeName, context) {
|
|
117
|
+
const srcTypes = new Map(src.types.map((t) => [t.name, t]));
|
|
118
|
+
const srcAliases = new Map(src.aliases.map((a) => [a.name, a]));
|
|
119
|
+
if (!srcTypes.has(rootTypeName) && !srcAliases.has(rootTypeName)) {
|
|
120
|
+
throw new WsdlCompilationError(`Stream config for operation "${context.opName}" references record type "${rootTypeName}" but it is not present in shape catalog "${context.shapeCatalog}".`, {
|
|
121
|
+
element: rootTypeName,
|
|
122
|
+
suggestion: `Check the companion catalog or correct the recordType.`,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
const known = new Set([...srcTypes.keys(), ...srcAliases.keys()]);
|
|
126
|
+
const queue = [rootTypeName];
|
|
127
|
+
const visited = new Set();
|
|
128
|
+
while (queue.length > 0) {
|
|
129
|
+
const typeName = queue.shift();
|
|
130
|
+
if (visited.has(typeName))
|
|
131
|
+
continue;
|
|
132
|
+
visited.add(typeName);
|
|
133
|
+
const srcType = srcTypes.get(typeName);
|
|
134
|
+
if (srcType) {
|
|
135
|
+
mergeType(dst, src, srcType, context);
|
|
136
|
+
// Enqueue referenced names from elems, attrs, base.
|
|
137
|
+
for (const e of srcType.elems ?? []) {
|
|
138
|
+
for (const ref of extractReferencedNames(e.tsType, known))
|
|
139
|
+
queue.push(ref);
|
|
140
|
+
}
|
|
141
|
+
for (const a of srcType.attrs ?? []) {
|
|
142
|
+
for (const ref of extractReferencedNames(a.tsType, known))
|
|
143
|
+
queue.push(ref);
|
|
144
|
+
}
|
|
145
|
+
if (srcType.base && known.has(srcType.base))
|
|
146
|
+
queue.push(srcType.base);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const srcAlias = srcAliases.get(typeName);
|
|
150
|
+
if (srcAlias) {
|
|
151
|
+
mergeAlias(dst, src, srcAlias, context);
|
|
152
|
+
for (const ref of extractReferencedNames(srcAlias.tsType, known))
|
|
153
|
+
queue.push(ref);
|
|
154
|
+
}
|
|
155
|
+
// Not in companion; silently skip — either a primitive or a type that
|
|
156
|
+
// the main catalog is expected to own.
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function mergeType(dst, src, srcType, context) {
|
|
160
|
+
const existingIdx = dst.types.findIndex((t) => t.name === srcType.name);
|
|
161
|
+
if (existingIdx < 0) {
|
|
162
|
+
dst.types.push({ ...srcType });
|
|
163
|
+
copyTypeMeta(dst, src, srcType.name);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const existing = dst.types[existingIdx];
|
|
167
|
+
if (!structurallyEqualType(existing, srcType)) {
|
|
168
|
+
throw new WsdlCompilationError(`Companion catalog "${context.shapeCatalog}" declares type "${srcType.name}" that conflicts structurally with the current catalog.`, {
|
|
169
|
+
element: srcType.name,
|
|
170
|
+
suggestion: `Rename one of the conflicting types in the source WSDL, or resolve the conflict before streaming. wsdl-tsc refuses to silently rename public API types.`,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
// Structurally identical — keep the existing entry (and its meta) as-is.
|
|
174
|
+
}
|
|
175
|
+
function mergeAlias(dst, src, srcAlias, context) {
|
|
176
|
+
const existingIdx = dst.aliases.findIndex((a) => a.name === srcAlias.name);
|
|
177
|
+
if (existingIdx < 0) {
|
|
178
|
+
dst.aliases.push({ ...srcAlias });
|
|
179
|
+
// Aliases that point at a complex type get meta synonyms in compileCatalog;
|
|
180
|
+
// the main catalog already owns that path for its own types, so we only
|
|
181
|
+
// need to add meta if the companion aliases a complex type whose type we
|
|
182
|
+
// also just copied.
|
|
183
|
+
copyAliasSynonymMeta(dst, src, srcAlias.name);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const existing = dst.aliases[existingIdx];
|
|
187
|
+
if (!structurallyEqualAlias(existing, srcAlias)) {
|
|
188
|
+
throw new WsdlCompilationError(`Companion catalog "${context.shapeCatalog}" declares alias "${srcAlias.name}" that conflicts structurally with the current catalog.`, {
|
|
189
|
+
element: srcAlias.name,
|
|
190
|
+
suggestion: `Resolve the conflicting type name before streaming. wsdl-tsc refuses to silently rename public API types.`,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function copyTypeMeta(dst, src, typeName) {
|
|
195
|
+
if (typeName in src.meta.attrSpec)
|
|
196
|
+
dst.meta.attrSpec[typeName] = [...src.meta.attrSpec[typeName]];
|
|
197
|
+
if (typeName in src.meta.attrType)
|
|
198
|
+
dst.meta.attrType[typeName] = { ...src.meta.attrType[typeName] };
|
|
199
|
+
if (typeName in src.meta.childType)
|
|
200
|
+
dst.meta.childType[typeName] = { ...src.meta.childType[typeName] };
|
|
201
|
+
if (typeName in src.meta.propMeta)
|
|
202
|
+
dst.meta.propMeta[typeName] = { ...src.meta.propMeta[typeName] };
|
|
203
|
+
}
|
|
204
|
+
function copyAliasSynonymMeta(dst, src, aliasName) {
|
|
205
|
+
// Phase-2 MVP: only copy meta for aliases whose name already keys into the
|
|
206
|
+
// source's meta maps. Aliases that are just simple-type renames don't need
|
|
207
|
+
// child/attr meta at all.
|
|
208
|
+
copyTypeMeta(dst, src, aliasName);
|
|
209
|
+
}
|
|
210
|
+
const TS_BUILTINS = new Set([
|
|
211
|
+
"string", "number", "boolean", "bigint", "null", "undefined", "void", "any", "unknown", "never",
|
|
212
|
+
"Date", "Array", "Record", "Map", "Set", "Promise", "Buffer", "Object", "Function",
|
|
213
|
+
]);
|
|
214
|
+
/**
|
|
215
|
+
* Extract PascalCase identifiers from a TypeScript type expression that are
|
|
216
|
+
* known to the companion catalog. Deliberately cheap — matches identifiers
|
|
217
|
+
* starting with an uppercase letter, skips TS built-ins and anything not
|
|
218
|
+
* present in the companion's known-names set.
|
|
219
|
+
*/
|
|
220
|
+
function extractReferencedNames(tsType, known) {
|
|
221
|
+
if (!tsType)
|
|
222
|
+
return [];
|
|
223
|
+
const out = [];
|
|
224
|
+
// Identifiers starting with an uppercase letter; bare word boundaries.
|
|
225
|
+
for (const m of tsType.matchAll(/\b[A-Z][A-Za-z0-9_]*\b/g)) {
|
|
226
|
+
const name = m[0];
|
|
227
|
+
if (TS_BUILTINS.has(name))
|
|
228
|
+
continue;
|
|
229
|
+
if (known.has(name))
|
|
230
|
+
out.push(name);
|
|
231
|
+
}
|
|
232
|
+
return out;
|
|
233
|
+
}
|
|
234
|
+
function structurallyEqualType(a, b) {
|
|
235
|
+
return canonicalizeType(a) === canonicalizeType(b);
|
|
236
|
+
}
|
|
237
|
+
function structurallyEqualAlias(a, b) {
|
|
238
|
+
return canonicalizeAlias(a) === canonicalizeAlias(b);
|
|
239
|
+
}
|
|
240
|
+
function canonicalizeType(t) {
|
|
241
|
+
// Drop fields that legitimately differ between catalogs (ns, docs) and
|
|
242
|
+
// stabilize ordering. Stream metadata is on operations, not on types.
|
|
243
|
+
return JSON.stringify({
|
|
244
|
+
name: t.name,
|
|
245
|
+
attrs: (t.attrs ?? []).map(canonicalizeAttr),
|
|
246
|
+
elems: (t.elems ?? []).map(canonicalizeElem),
|
|
247
|
+
base: t.base ?? null,
|
|
248
|
+
wildcards: (t.wildcards ?? []).map((w) => ({
|
|
249
|
+
min: w.min,
|
|
250
|
+
max: w.max,
|
|
251
|
+
namespace: w.namespace ?? null,
|
|
252
|
+
processContents: w.processContents ?? null,
|
|
253
|
+
})),
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
function canonicalizeAlias(a) {
|
|
257
|
+
return JSON.stringify({
|
|
258
|
+
name: a.name,
|
|
259
|
+
tsType: a.tsType,
|
|
260
|
+
declared: a.declared,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
function canonicalizeAttr(a) {
|
|
264
|
+
return {
|
|
265
|
+
name: a.name,
|
|
266
|
+
tsType: a.tsType,
|
|
267
|
+
use: a.use ?? "optional",
|
|
268
|
+
declaredType: a.declaredType,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
function canonicalizeElem(e) {
|
|
272
|
+
return {
|
|
273
|
+
name: e.name,
|
|
274
|
+
tsType: e.tsType,
|
|
275
|
+
min: e.min,
|
|
276
|
+
max: e.max,
|
|
277
|
+
nillable: !!e.nillable,
|
|
278
|
+
declaredType: e.declaredType,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateGateway.d.ts","sourceRoot":"","sources":["../../src/gateway/generateGateway.ts"],"names":[],"mappings":"AA6CA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAC;IACtC,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IAE/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"generateGateway.d.ts","sourceRoot":"","sources":["../../src/gateway/generateGateway.ts"],"names":[],"mappings":"AA6CA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAC;IACtC,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IAE/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8JjF"}
|
|
@@ -183,7 +183,8 @@ export async function generateGateway(opts) {
|
|
|
183
183
|
}
|
|
184
184
|
// Step 6: Emit runtime.ts (if enabled)
|
|
185
185
|
if (emitRuntime) {
|
|
186
|
-
|
|
186
|
+
const hasStreams = operations.some((o) => !!o.stream);
|
|
187
|
+
emitRuntimeModule(outDir, versionSlug, serviceSlug, shouldUnwrap ? catalog : undefined, { hasStreams });
|
|
187
188
|
}
|
|
188
189
|
// Step 7: Emit plugin.ts and type-check fixture (if enabled)
|
|
189
190
|
if (emitPlugin) {
|
|
@@ -40,6 +40,16 @@ export interface OperationMetadata {
|
|
|
40
40
|
description?: string;
|
|
41
41
|
/** When true, response schema is omitted from route registration to avoid fast-json-stringify stack overflow on deeply nested $ref graphs */
|
|
42
42
|
skipResponseSchema?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Stream metadata populated from the OpenAPI `x-wsdl-tsc-stream` extension.
|
|
45
|
+
* When present, the route handler pipes `result.records` through the NDJSON
|
|
46
|
+
* helper instead of envelope-wrapping a single response object.
|
|
47
|
+
*/
|
|
48
|
+
stream?: {
|
|
49
|
+
mediaType: string;
|
|
50
|
+
format: "ndjson" | "json-array";
|
|
51
|
+
recordTypeName?: string;
|
|
52
|
+
};
|
|
43
53
|
}
|
|
44
54
|
/**
|
|
45
55
|
* Emits Fastify-compatible operation schema files
|
|
@@ -107,7 +117,9 @@ export declare function emitSchemasModule(outDir: string, modelsDir: string, ver
|
|
|
107
117
|
* @param {"js"|"ts"|"bare"} importsMode - Import-extension mode for generated TypeScript modules
|
|
108
118
|
*/
|
|
109
119
|
export declare function emitRouteFiles(outDir: string, routesDir: string, versionSlug: string, serviceSlug: string, operations: OperationMetadata[], importsMode: "js" | "ts" | "bare"): void;
|
|
110
|
-
export declare function emitRuntimeModule(outDir: string, versionSlug: string, serviceSlug: string, catalog?: any
|
|
120
|
+
export declare function emitRuntimeModule(outDir: string, versionSlug: string, serviceSlug: string, catalog?: any, opts?: {
|
|
121
|
+
hasStreams?: boolean;
|
|
122
|
+
}): void;
|
|
111
123
|
/**
|
|
112
124
|
* Emits plugin.ts module as the primary Fastify plugin wrapper
|
|
113
125
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../src/gateway/generators.ts"],"names":[],"mappings":"AAcA,OAAO,EAAC,KAAK,UAAU,EAAE,KAAK,eAAe,EAAyE,MAAM,cAAc,CAAC;AAG3I;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC5B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA6BxB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6IAA6I;IAC7I,kBAAkB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../src/gateway/generators.ts"],"names":[],"mappings":"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"}
|
|
@@ -148,11 +148,19 @@ export function emitOperationSchemas(doc, opsDir, versionSlug, serviceSlug, sche
|
|
|
148
148
|
// Build response schemas
|
|
149
149
|
const responses = operation.responses || {};
|
|
150
150
|
const responseObj = {};
|
|
151
|
+
// Detect streaming operation: OpenAPI emits a non-JSON content entry with
|
|
152
|
+
// an `x-wsdl-tsc-stream` extension on the 200 response.
|
|
153
|
+
const streamEntry = detectStreamResponse(responses["200"]);
|
|
151
154
|
const explicitCodes = Object.keys(responses).filter(isNumeric);
|
|
152
155
|
for (const code of explicitCodes) {
|
|
153
156
|
const r = responses[code];
|
|
154
157
|
if (!r || typeof r !== "object")
|
|
155
158
|
continue;
|
|
159
|
+
// Stream ops intentionally skip JSON response-schema construction on the
|
|
160
|
+
// streamed status code; the body is an NDJSON stream, not a single
|
|
161
|
+
// JSON object, so fast-json-stringify cannot serialize it anyway.
|
|
162
|
+
if (streamEntry && code === "200")
|
|
163
|
+
continue;
|
|
156
164
|
const rSchema = r.content?.["application/json"]?.schema;
|
|
157
165
|
if (!rSchema) {
|
|
158
166
|
throw new Error(`Response ${code} for operation '${operationId}' is missing application/json schema`);
|
|
@@ -222,12 +230,38 @@ export function emitOperationSchemas(doc, opsDir, versionSlug, serviceSlug, sche
|
|
|
222
230
|
path: p,
|
|
223
231
|
summary: normalizeDocCommentText(typeof operation.summary === "string" ? operation.summary : undefined),
|
|
224
232
|
description: normalizeDocCommentText(typeof operation.description === "string" ? operation.description : undefined),
|
|
225
|
-
|
|
233
|
+
// Stream ops always skip response schema because NDJSON is not a single
|
|
234
|
+
// JSON document and fast-json-stringify can't serialize it.
|
|
235
|
+
skipResponseSchema: skipResponseSchema || !!streamEntry,
|
|
236
|
+
...(streamEntry ? { stream: streamEntry } : {}),
|
|
226
237
|
});
|
|
227
238
|
}
|
|
228
239
|
}
|
|
229
240
|
return operations;
|
|
230
241
|
}
|
|
242
|
+
/**
|
|
243
|
+
* Look for an `x-wsdl-tsc-stream` extension on the 200 response's content map.
|
|
244
|
+
* Returns the normalized stream metadata when found, or undefined otherwise.
|
|
245
|
+
*/
|
|
246
|
+
function detectStreamResponse(response200) {
|
|
247
|
+
const content = response200?.content;
|
|
248
|
+
if (!content || typeof content !== "object")
|
|
249
|
+
return undefined;
|
|
250
|
+
for (const [mediaType, entry] of Object.entries(content)) {
|
|
251
|
+
const ext = entry && typeof entry === "object" ? entry["x-wsdl-tsc-stream"] : undefined;
|
|
252
|
+
if (!ext || typeof ext !== "object")
|
|
253
|
+
continue;
|
|
254
|
+
const format = ext.format;
|
|
255
|
+
if (format !== "ndjson" && format !== "json-array")
|
|
256
|
+
continue;
|
|
257
|
+
const itemRef = ext.itemSchema?.$ref;
|
|
258
|
+
const recordTypeName = typeof itemRef === "string"
|
|
259
|
+
? itemRef.split("/").pop()
|
|
260
|
+
: undefined;
|
|
261
|
+
return { mediaType, format, recordTypeName };
|
|
262
|
+
}
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
231
265
|
/**
|
|
232
266
|
* Emits schemas.ts module that registers all model schemas with Fastify
|
|
233
267
|
*
|
|
@@ -361,7 +395,7 @@ import type { FastifyInstance } from "fastify";
|
|
|
361
395
|
function detectArrayWrappers(catalog) {
|
|
362
396
|
return detectArrayWrappersShared(catalog.types || []);
|
|
363
397
|
}
|
|
364
|
-
export function emitRuntimeModule(outDir, versionSlug, serviceSlug, catalog) {
|
|
398
|
+
export function emitRuntimeModule(outDir, versionSlug, serviceSlug, catalog, opts) {
|
|
365
399
|
const vSlug = slugName(versionSlug);
|
|
366
400
|
const sSlug = slugName(serviceSlug);
|
|
367
401
|
// Build unwrap maps from catalog if provided
|
|
@@ -602,7 +636,43 @@ export function createGatewayErrorHandler_${vSlug}_${sSlug}() {
|
|
|
602
636
|
};
|
|
603
637
|
}
|
|
604
638
|
`;
|
|
605
|
-
|
|
639
|
+
const streamSection = opts?.hasStreams ? buildStreamRuntimeSection() : "";
|
|
640
|
+
fs.writeFileSync(path.join(outDir, "runtime.ts"), runtimeTs + unwrapSection + streamSection, "utf8");
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Returns the streaming helpers block for runtime.ts.
|
|
644
|
+
*
|
|
645
|
+
* The emitted `toNdjson` mirrors the reference implementation in
|
|
646
|
+
* src/runtime/ndjson.ts but is inlined here to avoid a cross-package import
|
|
647
|
+
* from the generated gateway (which would require wsdl-tsc to be a runtime
|
|
648
|
+
* dependency of the consumer's project).
|
|
649
|
+
*/
|
|
650
|
+
function buildStreamRuntimeSection() {
|
|
651
|
+
return `
|
|
652
|
+
// -----------------------------------------------------------------------------
|
|
653
|
+
// Streaming helpers (emitted because at least one operation is stream-configured).
|
|
654
|
+
// -----------------------------------------------------------------------------
|
|
655
|
+
|
|
656
|
+
import { Readable } from "node:stream";
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Wrap an async iterable of records in a Node Readable stream that emits
|
|
660
|
+
* NDJSON (one JSON document per line, LF-terminated). Downstream backpressure
|
|
661
|
+
* is honored by Readable.from's default iterator-pausing behavior. Source
|
|
662
|
+
* errors are forwarded to the returned stream's 'error' event — before-first-
|
|
663
|
+
* byte errors fire before any push(), so Fastify translates them into the
|
|
664
|
+
* standard JSON error envelope.
|
|
665
|
+
*/
|
|
666
|
+
export function toNdjson<T>(records: AsyncIterable<T>): Readable {
|
|
667
|
+
return Readable.from(encodeNdjson(records), { objectMode: false, encoding: "utf-8" });
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
async function* encodeNdjson<T>(records: AsyncIterable<T>): AsyncIterable<string> {
|
|
671
|
+
for await (const record of records) {
|
|
672
|
+
yield JSON.stringify(record) + "\\n";
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
`;
|
|
606
676
|
}
|
|
607
677
|
/**
|
|
608
678
|
* Emits plugin.ts module as the primary Fastify plugin wrapper
|
|
@@ -799,25 +869,44 @@ export function emitRouteFilesWithHandlers(outDir, routesDir, versionSlug, servi
|
|
|
799
869
|
? `request.body as ${reqTypeName}`
|
|
800
870
|
: "request.body";
|
|
801
871
|
// Build the runtime import and return expression based on unwrap availability
|
|
802
|
-
const runtimeImport =
|
|
803
|
-
? `import {
|
|
804
|
-
:
|
|
872
|
+
const runtimeImport = op.stream
|
|
873
|
+
? `import { toNdjson } from "../runtime${suffix}";`
|
|
874
|
+
: hasUnwrap
|
|
875
|
+
? `import { buildSuccessEnvelope, unwrapArrayWrappers } from "../runtime${suffix}";`
|
|
876
|
+
: `import { buildSuccessEnvelope } from "../runtime${suffix}";`;
|
|
805
877
|
const returnExpr = hasUnwrap
|
|
806
878
|
? `return buildSuccessEnvelope(unwrapArrayWrappers(result.response, "${resTypeName}"));`
|
|
807
879
|
: `return buildSuccessEnvelope(result.response);`;
|
|
808
880
|
// Note: op.path comes from OpenAPI and already includes any base path
|
|
809
881
|
const schemaBinding = op.skipResponseSchema
|
|
810
|
-
? `\n// Response schema omitted: $
|
|
882
|
+
? `\n// Response schema omitted: ${op.stream
|
|
883
|
+
? "stream operations emit NDJSON, not a single JSON object"
|
|
884
|
+
: "$ref graph exceeds fast-json-stringify depth limit"}\nconst { response: _response, ...routeSchema } = schema as Record<string, unknown>;\n`
|
|
811
885
|
: "";
|
|
812
886
|
const schemaLine = op.skipResponseSchema
|
|
813
887
|
? " schema: routeSchema,"
|
|
814
888
|
: " schema,";
|
|
815
889
|
const operationDocLines = buildOperationDocLines(op);
|
|
890
|
+
const handlerBody = op.stream
|
|
891
|
+
? ` handler: async (request, reply) => {
|
|
892
|
+
const client = fastify.${clientMeta.decoratorName};
|
|
893
|
+
const result = await client.${clientMethod}(${bodyArg});
|
|
894
|
+
reply.type(${JSON.stringify(op.stream.mediaType)});
|
|
895
|
+
return reply.send(toNdjson(result.records));
|
|
896
|
+
},`
|
|
897
|
+
: ` handler: async (request) => {
|
|
898
|
+
const client = fastify.${clientMeta.decoratorName};
|
|
899
|
+
const result = await client.${clientMethod}(${bodyArg});
|
|
900
|
+
${returnExpr}
|
|
901
|
+
},`;
|
|
902
|
+
const responseTypeDoc = op.stream
|
|
903
|
+
? `${op.stream.recordTypeName ?? "records"} (streamed as ${op.stream.format})`
|
|
904
|
+
: `${resTypeName} (wrapped in envelope)`;
|
|
816
905
|
let routeTs = `/**
|
|
817
906
|
* Route: ${op.method.toUpperCase()} ${op.path}
|
|
818
907
|
* Operation: ${op.operationId || op.operationSlug}
|
|
819
908
|
${operationDocLines} * Request Type: ${reqTypeName}
|
|
820
|
-
* Response Type: ${
|
|
909
|
+
* Response Type: ${responseTypeDoc}
|
|
821
910
|
* Auto-generated - do not edit manually.
|
|
822
911
|
*/
|
|
823
912
|
import type { FastifyInstance } from "fastify";
|
|
@@ -829,11 +918,7 @@ export async function ${fnName}(fastify: FastifyInstance) {
|
|
|
829
918
|
method: "${op.method.toUpperCase()}",
|
|
830
919
|
url: "${op.path}",
|
|
831
920
|
${schemaLine}
|
|
832
|
-
|
|
833
|
-
const client = fastify.${clientMeta.decoratorName};
|
|
834
|
-
const result = await client.${clientMethod}(${bodyArg});
|
|
835
|
-
${returnExpr}
|
|
836
|
-
},
|
|
921
|
+
${handlerBody}
|
|
837
922
|
});
|
|
838
923
|
}
|
|
839
924
|
`;
|
|
@@ -176,6 +176,16 @@ export interface ResolvedOperationMeta {
|
|
|
176
176
|
responseTypeName?: string;
|
|
177
177
|
summary?: string;
|
|
178
178
|
description?: string;
|
|
179
|
+
/**
|
|
180
|
+
* Populated for operations that opt into streaming via stream-config. Drives
|
|
181
|
+
* mock-client emission (async-iterable records) and test-payload shape.
|
|
182
|
+
*/
|
|
183
|
+
stream?: {
|
|
184
|
+
format: "ndjson" | "json-array";
|
|
185
|
+
mediaType: string;
|
|
186
|
+
recordTypeName: string;
|
|
187
|
+
recordPath: string[];
|
|
188
|
+
};
|
|
179
189
|
}
|
|
180
190
|
/**
|
|
181
191
|
* Options for resolving client metadata
|
|
@@ -226,6 +236,12 @@ export declare function resolveOperationMeta(operationId: string, operationSlug:
|
|
|
226
236
|
summary?: string;
|
|
227
237
|
description?: string;
|
|
228
238
|
doc?: string;
|
|
239
|
+
stream?: {
|
|
240
|
+
format: "ndjson" | "json-array";
|
|
241
|
+
mediaType: string;
|
|
242
|
+
recordTypeName: string;
|
|
243
|
+
recordPath: string[];
|
|
244
|
+
};
|
|
229
245
|
}>): ResolvedOperationMeta;
|
|
230
246
|
/**
|
|
231
247
|
* Measures the $ref graph complexity of a schema component.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/gateway/helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,UAAU,CAAC,EAAE;QACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC9B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAClC,CAAC;CACH;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7C;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,GAAG,CAqBxF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,GAAG,EACX,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC/B,OAAO,GAAE,GAAG,CAAC,MAAM,CAAa,GAC/B,GAAG,CA4GL;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,CAcxD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE,GAAG,EAAE,eAAe,GAAG,GAAG,CAiB3E;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,aAAa,CAAC,EAAE,GAAG,CAAC;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,GAAG,EACb,SAAS,EAAE,GAAG,EACd,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACrC,sBAAsB,CAmFxB;AAED;;;;GAIG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/gateway/helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,UAAU,CAAC,EAAE;QACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC9B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAClC,CAAC;CACH;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7C;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,GAAG,CAqBxF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,GAAG,EACX,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC/B,OAAO,GAAE,GAAG,CAAC,MAAM,CAAa,GAC/B,GAAG,CA4GL;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,CAcxD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE,GAAG,EAAE,eAAe,GAAG,GAAG,CAiB3E;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,aAAa,CAAC,EAAE,GAAG,CAAC;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,GAAG,EACb,SAAS,EAAE,GAAG,EACd,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACrC,sBAAsB,CAmFxB;AAED;;;;GAIG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,MAAM,CAAC,EAAE;QACP,MAAM,EAAE,QAAQ,GAAG,YAAY,CAAC;QAChC,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC;CACH;AAGD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,wBAAwB,EAAE,OAAO,CAAC,EAAE,GAAG,GAAG,UAAU,CAkD3F;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,iBAAiB,CAAC,EAAE,KAAK,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE;QACP,MAAM,EAAE,QAAQ,GAAG,YAAY,CAAC;QAChC,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC;CACH,CAAC,GACD,qBAAqB,CAwBvB;AAoBD;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CACxC,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC/B,KAAK,GAAE,MAAY,GAClB,MAAM,CAsCR"}
|
package/dist/gateway/helpers.js
CHANGED
|
@@ -430,6 +430,7 @@ export function resolveOperationMeta(operationId, operationSlug, method, path, c
|
|
|
430
430
|
responseTypeName,
|
|
431
431
|
...(summary ? { summary } : {}),
|
|
432
432
|
...(description ? { description } : {}),
|
|
433
|
+
...(catalogOp?.stream ? { stream: catalogOp.stream } : {}),
|
|
433
434
|
};
|
|
434
435
|
}
|
|
435
436
|
function normalizeOperationText(value) {
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export { generateOpenAPI } from "./openapi/generateOpenAPI.js";
|
|
|
3
3
|
export { generateGateway } from "./gateway/generateGateway.js";
|
|
4
4
|
export { generateTests } from "./test/generateTests.js";
|
|
5
5
|
export { runGenerationPipeline } from "./pipeline.js";
|
|
6
|
+
export { loadStreamConfigFile, parseStreamConfig, StreamConfigError, type OperationStreamMetadata, type ShapeCatalogRef, type StreamConfig, } from "./util/streamConfig.js";
|
|
7
|
+
export { applyShapeCatalogs, type ApplyShapeCatalogsOptions } from "./compiler/shapeResolver.js";
|
|
6
8
|
/**
|
|
7
9
|
* Compiles a WSDL file to TypeScript client code
|
|
8
10
|
*
|
|
@@ -27,5 +29,9 @@ export declare function compileWsdlToProject(input: {
|
|
|
27
29
|
wsdl: string;
|
|
28
30
|
outDir: string;
|
|
29
31
|
options?: CompilerOptions;
|
|
32
|
+
/** Path to a stream configuration JSON file (ADR-002). Takes precedence over `streamConfig` when both are set. */
|
|
33
|
+
streamConfigFile?: string;
|
|
34
|
+
/** In-memory stream configuration. Ignored when `streamConfigFile` is set. */
|
|
35
|
+
streamConfig?: import("./util/streamConfig.js").StreamConfig;
|
|
30
36
|
}): Promise<void>;
|
|
31
37
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,aAAa,CAAC;AAWjD,OAAO,EAAC,eAAe,EAAC,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAC,eAAe,EAAC,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAC,aAAa,EAAC,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAC,qBAAqB,EAAC,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,aAAa,CAAC;AAWjD,OAAO,EAAC,eAAe,EAAC,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAC,eAAe,EAAC,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAC,aAAa,EAAC,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAC,qBAAqB,EAAC,MAAM,eAAe,CAAC;AACpD,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,YAAY,GAClB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAC,kBAAkB,EAAE,KAAK,yBAAyB,EAAC,MAAM,6BAA6B,CAAC;AAG/F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE;IACL,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,kHAAkH;IAClH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8EAA8E;IAC9E,YAAY,CAAC,EAAE,OAAO,wBAAwB,EAAE,YAAY,CAAC;CAC9D,GACA,OAAO,CAAC,IAAI,CAAC,CA2Ef"}
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,8 @@ export { generateOpenAPI } from "./openapi/generateOpenAPI.js";
|
|
|
26
26
|
export { generateGateway } from "./gateway/generateGateway.js";
|
|
27
27
|
export { generateTests } from "./test/generateTests.js";
|
|
28
28
|
export { runGenerationPipeline } from "./pipeline.js";
|
|
29
|
+
export { loadStreamConfigFile, parseStreamConfig, StreamConfigError, } from "./util/streamConfig.js";
|
|
30
|
+
export { applyShapeCatalogs } from "./compiler/shapeResolver.js";
|
|
29
31
|
// noinspection JSUnusedGlobalSymbols
|
|
30
32
|
/**
|
|
31
33
|
* Compiles a WSDL file to TypeScript client code
|
|
@@ -53,6 +55,11 @@ export async function compileWsdlToProject(input) {
|
|
|
53
55
|
wsdl: input.wsdl,
|
|
54
56
|
out: input.outDir,
|
|
55
57
|
});
|
|
58
|
+
// Resolve stream configuration.
|
|
59
|
+
const { loadStreamConfigFile } = await import("./util/streamConfig.js");
|
|
60
|
+
const streamConfig = input.streamConfigFile
|
|
61
|
+
? loadStreamConfigFile(input.streamConfigFile)
|
|
62
|
+
: input.streamConfig;
|
|
56
63
|
// Load & compile
|
|
57
64
|
const wsdlCatalog = await loadWsdl(input.wsdl);
|
|
58
65
|
info(`Loaded WSDL: ${wsdlCatalog.wsdlUri}`);
|
|
@@ -60,7 +67,15 @@ export async function compileWsdlToProject(input) {
|
|
|
60
67
|
throw new Error(`No schemas found in WSDL: ${input.wsdl}`);
|
|
61
68
|
}
|
|
62
69
|
info(`Schemas discovered: ${wsdlCatalog.schemas.length}`);
|
|
63
|
-
const compiled = compileCatalog(wsdlCatalog, finalOptions);
|
|
70
|
+
const compiled = compileCatalog(wsdlCatalog, finalOptions, streamConfig);
|
|
71
|
+
// Apply companion-catalog shape resolution when a stream config is present.
|
|
72
|
+
if (streamConfig) {
|
|
73
|
+
const { applyShapeCatalogs } = await import("./compiler/shapeResolver.js");
|
|
74
|
+
const shapeBaseDir = input.streamConfigFile
|
|
75
|
+
? path.dirname(path.resolve(input.streamConfigFile))
|
|
76
|
+
: path.dirname(path.resolve(input.wsdl));
|
|
77
|
+
await applyShapeCatalogs(compiled, streamConfig, { baseDir: shapeBaseDir });
|
|
78
|
+
}
|
|
64
79
|
info(`Compiled WSDL: ${wsdlCatalog.wsdlUri}`);
|
|
65
80
|
// check if we have any data models and operations
|
|
66
81
|
if (compiled.types.length === 0 && compiled.aliases.length === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateOpenAPI.d.ts","sourceRoot":"","sources":["../../src/openapi/generateOpenAPI.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH,OAAO,EAAiB,KAAK,eAAe,EAAC,MAAM,+BAA+B,CAAC;AAKnF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAC3C,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAClC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC;IAC3E,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC,
|
|
1
|
+
{"version":3,"file":"generateOpenAPI.d.ts","sourceRoot":"","sources":["../../src/openapi/generateOpenAPI.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH,OAAO,EAAiB,KAAK,eAAe,EAAC,MAAM,+BAA+B,CAAC;AAKnF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAC3C,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAClC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC;IAC3E,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC,CAsTD"}
|