@techspokes/typescript-wsdl-client 1.3.0 → 1.4.1
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 +9 -0
- package/dist/checkedPipeline.d.ts +73 -2
- package/dist/checkedPipeline.js +118 -8
- package/dist/checkedPlanning.d.ts +5 -2
- package/dist/checkedPlanning.js +30 -5
- package/dist/checkedResponseInspection.d.ts +100 -0
- package/dist/checkedResponseInspection.js +499 -0
- package/dist/cli.js +55 -1
- package/dist/client/checkedDirectRuntime.d.ts +8 -0
- package/dist/client/checkedDirectRuntime.js +22 -14
- package/dist/client/directClientRuntime.d.ts +10 -3
- package/dist/client/directClientRuntime.js +14 -8
- package/dist/client/directClientVersion.d.ts +2 -0
- package/dist/client/directClientVersion.js +2 -0
- package/dist/client/generateDirectClient.js +7 -7
- package/dist/compiler/componentRecordProjection.d.ts +1 -0
- package/dist/compiler/componentRecordProjection.js +15 -4
- package/dist/compiler/directCodec.js +3 -11
- package/dist/compiler/directSoap.d.ts +50 -5
- package/dist/compiler/directSoap.js +204 -98
- package/dist/compiler/sourceCorrections.d.ts +118 -0
- package/dist/compiler/sourceCorrections.js +794 -0
- package/dist/gateway/checkedDocumentation.d.ts +14 -0
- package/dist/gateway/checkedDocumentation.js +106 -0
- package/dist/gateway/generateCheckedGateway.js +30 -53
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/util/readBoundedFile.d.ts +9 -0
- package/dist/util/readBoundedFile.js +36 -0
- package/dist/util/xmlBytes.d.ts +9 -0
- package/dist/util/xmlBytes.js +24 -0
- package/docs/api-reference.md +30 -1
- package/docs/checked-gateway.md +48 -0
- package/docs/cli-reference.md +16 -1
- package/docs/migration.md +16 -0
- package/package.json +1 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DirectOperationSelector } from '../compiler/directOperation.js';
|
|
2
|
+
type Schema = Readonly<Record<string, unknown>>;
|
|
3
|
+
/** Lower one issued shape while its original reference scope is still available.
|
|
4
|
+
* @param root Generator-owned shape, with at most one root resource and definition dictionary.
|
|
5
|
+
* @param selector Outer operation selector, independent of companion projection contracts.
|
|
6
|
+
* @param role Direction or declared-fault role owning the shape.
|
|
7
|
+
* @param grouped Whether published configured definition names must be preserved.
|
|
8
|
+
* @param components Destination dictionary shared by the operation document.
|
|
9
|
+
* @param check Generation cancellation and semantic resource-accounting checkpoint.
|
|
10
|
+
* @returns A new documentation schema; runtime schemas and literal annotations remain unchanged.
|
|
11
|
+
* @throws TypeError For unexpected resources, references, missing descendants or component collisions.
|
|
12
|
+
*/
|
|
13
|
+
export declare function lowerCheckedDocumentation(root: Schema, selector: DirectOperationSelector, role: string, grouped: boolean, components: Record<string, Schema>, check: () => void): Schema;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relocates generator-owned shape resources into OpenAPI documentation components.
|
|
3
|
+
* @since 1.4.1
|
|
4
|
+
* @constraints This is not a general JSON Schema resource bundler.
|
|
5
|
+
*/
|
|
6
|
+
import { createHash } from 'node:crypto';
|
|
7
|
+
const maps = new Set(['properties', 'patternProperties', 'dependentSchemas']);
|
|
8
|
+
const singles = new Set(['additionalProperties', 'additionalItems', 'contains', 'not', 'if', 'then', 'else', 'propertyNames', 'unevaluatedProperties', 'unevaluatedItems']);
|
|
9
|
+
const arrays = new Set(['allOf', 'anyOf', 'oneOf', 'prefixItems']);
|
|
10
|
+
const escape = (value) => encodeURIComponent(value.replace(/~/g, '~0').replace(/\//g, '~1'));
|
|
11
|
+
/** Lower one issued shape while its original reference scope is still available.
|
|
12
|
+
* @param root Generator-owned shape, with at most one root resource and definition dictionary.
|
|
13
|
+
* @param selector Outer operation selector, independent of companion projection contracts.
|
|
14
|
+
* @param role Direction or declared-fault role owning the shape.
|
|
15
|
+
* @param grouped Whether published configured definition names must be preserved.
|
|
16
|
+
* @param components Destination dictionary shared by the operation document.
|
|
17
|
+
* @param check Generation cancellation and semantic resource-accounting checkpoint.
|
|
18
|
+
* @returns A new documentation schema; runtime schemas and literal annotations remain unchanged.
|
|
19
|
+
* @throws TypeError For unexpected resources, references, missing descendants or component collisions.
|
|
20
|
+
*/
|
|
21
|
+
export function lowerCheckedDocumentation(root, selector, role, grouped, components, check) {
|
|
22
|
+
check();
|
|
23
|
+
if (root.$id !== undefined && (typeof root.$id !== 'string' || !/^urn:checked-component:shape:[a-f0-9]{64}$/.test(root.$id))) {
|
|
24
|
+
throw new TypeError('Unexpected checked documentation resource');
|
|
25
|
+
}
|
|
26
|
+
const definitions = (root.definitions ?? {});
|
|
27
|
+
// @why #467 Original resource IDs encode selection, not contract equivalence or component ownership.
|
|
28
|
+
const owner = createHash('sha256').update(JSON.stringify([selector.portType.namespace, selector.portType.local,
|
|
29
|
+
selector.binding.namespace, selector.binding.local, selector.operation, role])).digest('hex');
|
|
30
|
+
const names = new Map(Object.keys(definitions).sort().map(name => [name, grouped ? name : `Checked_${owner}_${name}`]));
|
|
31
|
+
const reference = (value) => {
|
|
32
|
+
if (typeof value !== 'string' || !value.startsWith('#/definitions/'))
|
|
33
|
+
throw new TypeError('Unexpected checked documentation reference');
|
|
34
|
+
let pointer;
|
|
35
|
+
try {
|
|
36
|
+
pointer = decodeURIComponent(value.slice(1));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
throw new TypeError('Invalid checked documentation pointer');
|
|
40
|
+
}
|
|
41
|
+
const parts = pointer.slice(1).split('/').map(part => {
|
|
42
|
+
if (/~(?![01])/.test(part))
|
|
43
|
+
throw new TypeError('Invalid checked documentation pointer');
|
|
44
|
+
return part.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
45
|
+
});
|
|
46
|
+
const name = names.get(parts[1]);
|
|
47
|
+
if (!name)
|
|
48
|
+
throw new TypeError('Unresolved checked documentation definition');
|
|
49
|
+
let target = root;
|
|
50
|
+
for (const part of parts) {
|
|
51
|
+
check();
|
|
52
|
+
if (!target || typeof target !== 'object' || !Object.hasOwn(target, part))
|
|
53
|
+
throw new TypeError('Unresolved checked documentation descendant');
|
|
54
|
+
target = target[part];
|
|
55
|
+
}
|
|
56
|
+
if (typeof target !== 'boolean' && (!target || typeof target !== 'object' || Array.isArray(target))) {
|
|
57
|
+
throw new TypeError('Checked documentation reference must target a schema');
|
|
58
|
+
}
|
|
59
|
+
return '#/components/schemas/' + escape(name) + parts.slice(2).map(part => '/' + escape(part)).join('');
|
|
60
|
+
};
|
|
61
|
+
const visit = (value, isRoot = false) => {
|
|
62
|
+
check();
|
|
63
|
+
if (typeof value === 'boolean')
|
|
64
|
+
return value;
|
|
65
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
66
|
+
throw new TypeError('Unexpected checked documentation schema');
|
|
67
|
+
const record = value, result = Object.create(null);
|
|
68
|
+
for (const [key, item] of Object.entries(record)) {
|
|
69
|
+
check();
|
|
70
|
+
if (key === '$id' && isRoot)
|
|
71
|
+
continue;
|
|
72
|
+
if (key === 'definitions' && isRoot)
|
|
73
|
+
continue;
|
|
74
|
+
if (['$id', '$anchor', '$dynamicAnchor', '$dynamicRef', '$recursiveRef', '$recursiveAnchor', '$defs', 'definitions'].includes(key)) {
|
|
75
|
+
throw new TypeError('Unexpected checked documentation resource');
|
|
76
|
+
}
|
|
77
|
+
if (key === '$ref')
|
|
78
|
+
result[key] = reference(item);
|
|
79
|
+
else if (maps.has(key) || key === 'dependencies') {
|
|
80
|
+
const dictionary = Object.create(null);
|
|
81
|
+
for (const [name, child] of Object.entries(item)) {
|
|
82
|
+
check();
|
|
83
|
+
dictionary[name] = key === 'dependencies' && Array.isArray(child) ? child : visit(child);
|
|
84
|
+
}
|
|
85
|
+
result[key] = dictionary;
|
|
86
|
+
}
|
|
87
|
+
else if (arrays.has(key) || key === 'items' && Array.isArray(item))
|
|
88
|
+
result[key] = item.map(child => visit(child));
|
|
89
|
+
else if (singles.has(key) || key === 'items')
|
|
90
|
+
result[key] = visit(item);
|
|
91
|
+
// @constraints Unknown annotations are literal data, including keyword-shaped application examples.
|
|
92
|
+
else
|
|
93
|
+
result[key] = item;
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
};
|
|
97
|
+
const lowered = visit(root, true);
|
|
98
|
+
for (const [original, name] of names) {
|
|
99
|
+
const resolved = visit(definitions[original]);
|
|
100
|
+
if (Object.hasOwn(components, name) && JSON.stringify(components[name]) !== JSON.stringify(resolved)) {
|
|
101
|
+
throw new TypeError(`applicationGroups OpenAPI component collision ${name}`);
|
|
102
|
+
}
|
|
103
|
+
components[name] = resolved;
|
|
104
|
+
}
|
|
105
|
+
return lowered;
|
|
106
|
+
}
|
|
@@ -7,6 +7,7 @@ import { mkdir, writeFile } from 'node:fs/promises';
|
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import { componentSourceCapsuleBytes, inspectReconstructedComponentSource, inspectComponentSourceService } from '../compiler/directSourceCapsule.js';
|
|
9
9
|
import { lowerComponentShape } from '../generation/componentShape.js';
|
|
10
|
+
import { lowerCheckedDocumentation } from './checkedDocumentation.js';
|
|
10
11
|
import { checkSemanticBudget } from '../compiler/semanticBudget.js';
|
|
11
12
|
import { inspectDirectOperation } from '../compiler/directOperation.js';
|
|
12
13
|
import { inspectComponentValueMapping } from '../compiler/directValues.js';
|
|
@@ -22,7 +23,7 @@ async function generateGatewayFromReconstruction(expected, options) {
|
|
|
22
23
|
throw new Error('Checked gateway generation cancelled');
|
|
23
24
|
inspectReconstructedComponentSource(expected);
|
|
24
25
|
const capsule = { bytes: componentSourceCapsuleBytes(expected, options.signal) };
|
|
25
|
-
const runtime = expected.contract.binding.version === '1.2' ? 'checkedComponentRuntimeV2' : '
|
|
26
|
+
const runtime = expected.contract.binding.version === '1.2' ? 'checkedComponentRuntimeV2' : 'checkedComponentRuntimeV3';
|
|
26
27
|
if (!options.routePath.startsWith('/') || options.routePath.split('/').slice(1)
|
|
27
28
|
.some(segment => !segment || !/^(?:[A-Za-z0-9._~-]|%[0-9A-Fa-f]{2})+$/.test(segment))) {
|
|
28
29
|
throw new TypeError('Checked routePath requires literal nonempty path segments');
|
|
@@ -31,15 +32,21 @@ async function generateGatewayFromReconstruction(expected, options) {
|
|
|
31
32
|
const output = expected.mappings.find(mapping => mapping.direction.kind === 'output');
|
|
32
33
|
if (!input || !output)
|
|
33
34
|
throw new TypeError('Issued input and output mappings required');
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
throw new Error('Checked gateway generation cancelled');
|
|
40
|
-
}).schema;
|
|
35
|
+
const { budget } = inspectDirectOperation(expected.contract).context;
|
|
36
|
+
const check = () => {
|
|
37
|
+
checkSemanticBudget(budget);
|
|
38
|
+
if (options.signal?.aborted)
|
|
39
|
+
throw new Error('Checked gateway generation cancelled');
|
|
41
40
|
};
|
|
41
|
+
const schema = (mapping, role) => lowerComponentShape(expected.contract, mapping, role, check).schema;
|
|
42
|
+
const components = Object.create(null);
|
|
43
|
+
const documented = (value, mapping, role) => lowerCheckedDocumentation(value, expected.contract.selector, role, mapping.kind === 'component-mapping'
|
|
44
|
+
&& !!inspectComponentValueMapping(mapping, expected.contract).applicationGroups, components, () => {
|
|
45
|
+
budget.chargeWork();
|
|
46
|
+
check();
|
|
47
|
+
});
|
|
42
48
|
const request = schema(input, 'Request'), response = schema(output, 'Response');
|
|
49
|
+
const documentation = { request: documented(request, input, 'Request'), response: documented(response, output, 'Response') };
|
|
43
50
|
const soap12 = expected.contract.binding.version === '1.2';
|
|
44
51
|
const nameSchema = { type: 'object', additionalProperties: false, required: ['namespace', 'local'],
|
|
45
52
|
properties: { namespace: { type: 'string' }, local: { type: 'string' } } };
|
|
@@ -53,12 +60,14 @@ async function generateGatewayFromReconstruction(expected, options) {
|
|
|
53
60
|
const faults = expected.mappings.filter(mapping => mapping.direction.kind === 'fault').map(mapping => {
|
|
54
61
|
if (mapping.direction.kind !== 'fault')
|
|
55
62
|
throw new TypeError('Declared fault mapping required');
|
|
56
|
-
|
|
63
|
+
const role = `Fault_${expected.mappings.filter(item => item.direction.kind === 'fault').indexOf(mapping)}`;
|
|
64
|
+
const value = schema(mapping, role);
|
|
65
|
+
return { name: mapping.direction.name, value, documented: documented(value, mapping, role) };
|
|
57
66
|
});
|
|
58
|
-
const faultVariants = faults.map(fault => ({
|
|
67
|
+
const faultVariants = (documentationOnly) => faults.map(fault => ({
|
|
59
68
|
type: 'object', additionalProperties: false, required: ['fault', 'value'],
|
|
60
69
|
properties: {
|
|
61
|
-
value: fault.value,
|
|
70
|
+
value: documentationOnly ? fault.documented : fault.value,
|
|
62
71
|
fault: {
|
|
63
72
|
type: 'object', additionalProperties: false, required: ['name', 'code', 'string', ...(soap12 ? ['version', 'subcodes', 'reasons'] : [])],
|
|
64
73
|
properties: soap12 ? { ...protocolFaultProperties, name: { const: fault.name } } : {
|
|
@@ -69,49 +78,17 @@ async function generateGatewayFromReconstruction(expected, options) {
|
|
|
69
78
|
},
|
|
70
79
|
},
|
|
71
80
|
}));
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const
|
|
81
|
+
const protocolFault = { type: 'object', additionalProperties: false, required: ['fault'], properties: {
|
|
82
|
+
fault: { type: 'object', additionalProperties: false, required: ['version', 'code', 'string', ...(soap12 ? ['subcodes', 'reasons'] : [])],
|
|
83
|
+
properties: soap12 ? protocolFaultProperties : { version: { const: '1.1' }, code: nameSchema, string: { type: 'string' }, actor: { type: 'string' } } },
|
|
84
|
+
} };
|
|
85
|
+
const fault = { oneOf: [...faultVariants(false), protocolFault] };
|
|
86
|
+
const documentedFault = { oneOf: [...faultVariants(true), protocolFault] };
|
|
78
87
|
const schemas = { request: { $schema: draft07, ...request }, response: { $schema: draft07, ...response }, fault: { $schema: draft07, ...fault } };
|
|
79
|
-
const grouped = expected.mappings.some(mapping => mapping.kind === 'component-mapping'
|
|
80
|
-
&& inspectComponentValueMapping(mapping, expected.contract).applicationGroups);
|
|
81
|
-
const components = Object.create(null);
|
|
82
|
-
const documented = (value, dictionary = false) => {
|
|
83
|
-
if (Array.isArray(value))
|
|
84
|
-
return value.map(item => documented(item));
|
|
85
|
-
if (!value || typeof value !== 'object')
|
|
86
|
-
return value;
|
|
87
|
-
const record = value, result = Object.create(null);
|
|
88
|
-
// @why Property names belong to the application; definitions and $id are keywords only at schema nodes.
|
|
89
|
-
if (dictionary) {
|
|
90
|
-
for (const [key, item] of Object.entries(record))
|
|
91
|
-
result[key] = documented(item);
|
|
92
|
-
return result;
|
|
93
|
-
}
|
|
94
|
-
if (Object.hasOwn(record, 'definitions'))
|
|
95
|
-
for (const [key, definition] of Object.entries(record.definitions)) {
|
|
96
|
-
const resolved = documented(definition);
|
|
97
|
-
if (components[key] && JSON.stringify(components[key]) !== JSON.stringify(resolved))
|
|
98
|
-
throw new TypeError(`applicationGroups OpenAPI component collision ${key}`);
|
|
99
|
-
components[key] = resolved;
|
|
100
|
-
}
|
|
101
|
-
for (const [key, item] of Object.entries(record)) {
|
|
102
|
-
if (key === 'definitions' || key === '$id')
|
|
103
|
-
continue;
|
|
104
|
-
result[key] = ['const', 'enum', 'default', 'examples'].includes(key) ? item
|
|
105
|
-
: key === '$ref' && typeof item === 'string' && item.startsWith('#/definitions/') ? item.replace('#/definitions/', '#/components/schemas/')
|
|
106
|
-
: documented(item, ['properties', 'patternProperties', 'dependencies', 'dependentSchemas'].includes(key));
|
|
107
|
-
}
|
|
108
|
-
return result;
|
|
109
|
-
};
|
|
110
|
-
const documentation = grouped ? { request: documented(request), response: documented(response), fault: documented(fault) } : { request, response, fault };
|
|
111
88
|
const doc = {
|
|
112
89
|
openapi: '3.1.1', jsonSchemaDialect: 'https://json-schema.org/draft/2020-12/schema',
|
|
113
90
|
info: { title: expected.selection.service.local, version: '1.0.0' },
|
|
114
|
-
...(
|
|
91
|
+
...(Object.keys(components).length ? { components: { schemas: components } } : {}),
|
|
115
92
|
'x-checked-model': { model: 'checked-components-v1', scope: soap12 ? 'native-component-structured-soap12' : 'native-component-structured-soap11',
|
|
116
93
|
...(expected.responseProjection
|
|
117
94
|
? { responseProjection: { spec: expected.responseProjection.spec, delivery: 'buffered', retainedValue: 'complete-companion-payload' } } : {}),
|
|
@@ -124,7 +101,7 @@ async function generateGatewayFromReconstruction(expected, options) {
|
|
|
124
101
|
requestBody: { required: true, content: { 'application/json': { schema: documentation.request } } },
|
|
125
102
|
responses: { '200': { description: 'Independently validated SOAP response', content: { 'application/json': { schema: documentation.response } } },
|
|
126
103
|
'400': { description: 'Invalid HTTP request; no SOAP request is dispatched' },
|
|
127
|
-
'502': { description: '
|
|
104
|
+
'502': { description: 'SOAP fault or refused upstream response', content: { 'application/json': { schema: { oneOf: [documentedFault,
|
|
128
105
|
{ type: 'object', additionalProperties: false, required: ['kind', 'rule'], properties: { kind: { type: 'string' }, rule: { type: 'string' } } }] } } } },
|
|
129
106
|
'500': { description: 'Incompatible artifacts or gateway configuration' } } } } },
|
|
130
107
|
};
|
|
@@ -191,9 +168,9 @@ const plugin: FastifyPluginAsync<CheckedGatewayOptions> = async (fastify, option
|
|
|
191
168
|
...(result.fault.name === undefined ? {} : {name: result.fault.name}),
|
|
192
169
|
...(result.fault.node === undefined ? {} : {node: result.fault.node}),
|
|
193
170
|
...(result.fault.role === undefined ? {} : {role: result.fault.role})};
|
|
194
|
-
const value = result.fault.name === undefined ? {fault} : {fault, value: result.value};` : `const fault = {name: result.fault.name, code: {namespace: result.fault.code.namespace, local: result.fault.code.local},
|
|
171
|
+
const value = result.fault.name === undefined ? {fault} : {fault, value: result.value};` : `const fault = {...(result.fault.name === undefined ? {version: result.fault.version} : {name: result.fault.name}), code: {namespace: result.fault.code.namespace, local: result.fault.code.local},
|
|
195
172
|
string: result.fault.string, ...(result.fault.actor === undefined ? {} : {actor: result.fault.actor})};
|
|
196
|
-
const value = {fault, value: result.value};`}
|
|
173
|
+
const value = 'value' in result ? {fault, value: result.value} : {fault};`}
|
|
197
174
|
if (!validateFault(value)) return reply.code(502).send({kind: 'value-invalid', rule: 'http-fault-shape'});
|
|
198
175
|
return reply.code(502).type('application/json').serializer(value => JSON.stringify(value)).send(value);
|
|
199
176
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,10 +12,12 @@ export type { ComposedOpenApiDocument, OpenApiCompositionEntry, OpenApiCompositi
|
|
|
12
12
|
export type { CheckedComponentOptions, CheckedInventory } from './checkedPipeline.js';
|
|
13
13
|
export { planCheckedComponents, formatCheckedComponentPlan, writeCheckedPlanningFile, CheckedPlanningError } from './checkedPlanning.js';
|
|
14
14
|
export type { CheckedComponentPlan, ComponentPlanBlocker } from './checkedPlanning.js';
|
|
15
|
+
export { inspectCheckedResponse } from './checkedResponseInspection.js';
|
|
16
|
+
export type { CheckedResponseInspectionOptions, CheckedResponseInspectionReport } from './checkedResponseInspection.js';
|
|
15
17
|
export type { ComponentRecordProjectionSpec, ComponentRecordProjectionAssociation } from './compiler/componentRecordProjection.js';
|
|
16
18
|
export { loadStreamConfigFile, parseStreamConfig, StreamConfigError, type OperationStreamMetadata, type ShapeCatalogRef, type StreamConfig, } from "./util/streamConfig.js";
|
|
17
19
|
export { applyShapeCatalogs, type ApplyShapeCatalogsOptions } from "./compiler/shapeResolver.js";
|
|
18
|
-
export { checkedDirectRuntimeV1, checkedComponentRuntimeV1, checkedComponentRuntimeV2 } from './client/checkedDirectRuntime.js';
|
|
20
|
+
export { checkedDirectRuntimeV1, checkedComponentRuntimeV1, checkedComponentRuntimeV2, checkedComponentRuntimeV3 } from './client/checkedDirectRuntime.js';
|
|
19
21
|
/**
|
|
20
22
|
* Compiles a WSDL file to TypeScript client code
|
|
21
23
|
*
|
package/dist/index.js
CHANGED
|
@@ -30,9 +30,10 @@ export { runGenerationPipeline } from "./pipeline.js";
|
|
|
30
30
|
export { runMultiServicePipeline, loadMultiServiceConfig } from './multiServicePipeline.js';
|
|
31
31
|
export { composeOpenApiDocuments } from './openapi/composeOpenAPI.js';
|
|
32
32
|
export { planCheckedComponents, formatCheckedComponentPlan, writeCheckedPlanningFile, CheckedPlanningError } from './checkedPlanning.js';
|
|
33
|
+
export { inspectCheckedResponse } from './checkedResponseInspection.js';
|
|
33
34
|
export { loadStreamConfigFile, parseStreamConfig, StreamConfigError, } from "./util/streamConfig.js";
|
|
34
35
|
export { applyShapeCatalogs } from "./compiler/shapeResolver.js";
|
|
35
|
-
export { checkedDirectRuntimeV1, checkedComponentRuntimeV1, checkedComponentRuntimeV2 } from './client/checkedDirectRuntime.js';
|
|
36
|
+
export { checkedDirectRuntimeV1, checkedComponentRuntimeV1, checkedComponentRuntimeV2, checkedComponentRuntimeV3 } from './client/checkedDirectRuntime.js';
|
|
36
37
|
// noinspection JSUnusedGlobalSymbols
|
|
37
38
|
/**
|
|
38
39
|
* Compiles a WSDL file to TypeScript client code
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Acquire a regular file through one descriptor under a caller-specified byte limit.
|
|
2
|
+
* @since 1.4.0
|
|
3
|
+
* @param file Local input path.
|
|
4
|
+
* @param maxBytes Maximum accepted file size, leaving room for a one-byte growth probe.
|
|
5
|
+
* @returns The bytes read from the opened file.
|
|
6
|
+
* @throws RangeError For an invalid limit or an input exceeding it.
|
|
7
|
+
* @throws Error For filesystem errors, a nonregular input, or a size change observed during the read.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readBoundedFile(file: string, maxBytes: number): Buffer;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { constants } from 'node:buffer';
|
|
3
|
+
/** Acquire a regular file through one descriptor under a caller-specified byte limit.
|
|
4
|
+
* @since 1.4.0
|
|
5
|
+
* @param file Local input path.
|
|
6
|
+
* @param maxBytes Maximum accepted file size, leaving room for a one-byte growth probe.
|
|
7
|
+
* @returns The bytes read from the opened file.
|
|
8
|
+
* @throws RangeError For an invalid limit or an input exceeding it.
|
|
9
|
+
* @throws Error For filesystem errors, a nonregular input, or a size change observed during the read.
|
|
10
|
+
*/
|
|
11
|
+
export function readBoundedFile(file, maxBytes) {
|
|
12
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 0 || maxBytes >= constants.MAX_LENGTH)
|
|
13
|
+
throw new RangeError('Invalid file byte limit');
|
|
14
|
+
const fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NONBLOCK);
|
|
15
|
+
try {
|
|
16
|
+
const stat = fs.fstatSync(fd);
|
|
17
|
+
if (!stat.isFile())
|
|
18
|
+
throw new TypeError('Expected a regular file');
|
|
19
|
+
if (stat.size > maxBytes)
|
|
20
|
+
throw new RangeError('File byte limit exceeded');
|
|
21
|
+
const buffer = Buffer.alloc(stat.size + 1);
|
|
22
|
+
let offset = 0;
|
|
23
|
+
while (offset < buffer.length) {
|
|
24
|
+
const count = fs.readSync(fd, buffer, offset, buffer.length - offset, null);
|
|
25
|
+
if (count === 0)
|
|
26
|
+
break;
|
|
27
|
+
offset += count;
|
|
28
|
+
}
|
|
29
|
+
if (offset !== stat.size)
|
|
30
|
+
throw new Error('File size changed during the read');
|
|
31
|
+
return buffer.subarray(0, offset);
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
fs.closeSync(fd);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Inspect genuine XML bytes without evaluating caller-owned length, backing-store or iterator properties.
|
|
2
|
+
* @throws TypeError For non-byte views, proxies or shared backing stores.
|
|
3
|
+
* @constraints Callers must enforce their capacity before requesting a snapshot.
|
|
4
|
+
*/
|
|
5
|
+
export declare function xmlByteLength(value: unknown): number;
|
|
6
|
+
/** Copy XML bytes through native slots so hashing and decoding share one private observation.
|
|
7
|
+
* @constraints Callers must first bound xmlByteLength; no user iterator or property getter is consulted.
|
|
8
|
+
*/
|
|
9
|
+
export declare function snapshotXmlBytes(value: Uint8Array): Uint8Array;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { types } from 'node:util';
|
|
2
|
+
const typed = Object.getPrototypeOf(Uint8Array.prototype);
|
|
3
|
+
const lengthGetter = Object.getOwnPropertyDescriptor(typed, 'byteLength').get;
|
|
4
|
+
const bufferGetter = Object.getOwnPropertyDescriptor(typed, 'buffer').get;
|
|
5
|
+
const setBytes = Uint8Array.prototype.set;
|
|
6
|
+
/** Inspect genuine XML bytes without evaluating caller-owned length, backing-store or iterator properties.
|
|
7
|
+
* @throws TypeError For non-byte views, proxies or shared backing stores.
|
|
8
|
+
* @constraints Callers must enforce their capacity before requesting a snapshot.
|
|
9
|
+
*/
|
|
10
|
+
export function xmlByteLength(value) {
|
|
11
|
+
if (!types.isUint8Array(value) || types.isProxy(value))
|
|
12
|
+
throw new TypeError('XML requires Uint8Array bytes');
|
|
13
|
+
if (types.isSharedArrayBuffer(bufferGetter.call(value)))
|
|
14
|
+
throw new TypeError('Shared XML bytes are unsupported');
|
|
15
|
+
return lengthGetter.call(value);
|
|
16
|
+
}
|
|
17
|
+
/** Copy XML bytes through native slots so hashing and decoding share one private observation.
|
|
18
|
+
* @constraints Callers must first bound xmlByteLength; no user iterator or property getter is consulted.
|
|
19
|
+
*/
|
|
20
|
+
export function snapshotXmlBytes(value) {
|
|
21
|
+
const copy = new Uint8Array(xmlByteLength(value));
|
|
22
|
+
setBytes.call(copy, value);
|
|
23
|
+
return copy;
|
|
24
|
+
}
|
package/docs/api-reference.md
CHANGED
|
@@ -4,9 +4,36 @@ This reference covers public generation, composition, stream and security APIs.
|
|
|
4
4
|
|
|
5
5
|
See the main [README](../README.md) for installation, CLI usage, and project overview.
|
|
6
6
|
|
|
7
|
+
## Captured checked SOAP responses
|
|
8
|
+
|
|
9
|
+
`inspectCheckedResponse(source, options)` returns versioned diagnostic data without generating files or dispatching SOAP. Supply an authorized local WSDL, closed snapshots in `checkedComponents`, a full operation selector, and `responseBytes`. Optional `responseMetadata` supplies the actual HTTP `status`, `contentType` and `contentEncoding`. Omission leaves HTTP duties unassessed. `signal` and `limits` retain cancellation and XML capacity controls.
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import {inspectCheckedResponse} from '@techspokes/typescript-wsdl-client';
|
|
13
|
+
|
|
14
|
+
const report = await inspectCheckedResponse('./sources/service.wsdl', {
|
|
15
|
+
checkedComponents: configuration,
|
|
16
|
+
selector: configuration.selectors[0],
|
|
17
|
+
responseBytes: capturedBytes,
|
|
18
|
+
});
|
|
19
|
+
console.log(report.kind);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The report separates wrapper and companion outcomes and excludes raw XML and decoded values. Configuration can select a consumer-owned `sourceCorrectionsFile`; the same effective contract is used for planning, inspection and generation. A correction draft does not authorize execution until its semantic choices are completed. See [source corrections and offline inspection](checked-gateway.md#consumer-owned-source-corrections).
|
|
23
|
+
|
|
24
|
+
Set `includeCorrectionDraft: true` to request an available correction draft. Its exact resource pins can contain local source URIs; default reports retain only diagnostic resource labels.
|
|
25
|
+
|
|
26
|
+
Pass the complete multi-operation checked configuration unchanged. Inspection authenticates the complete correction-source closure before selecting the requested operation and its projection; inactive companions retain their freshness checks.
|
|
27
|
+
|
|
28
|
+
## Checked runtime bindings
|
|
29
|
+
|
|
30
|
+
New SOAP 1.1 component clients inject package-root `checkedComponentRuntimeV3` with handshake `checked-component-soap11-runtime-v1`. SOAP 1.2 keeps `checkedComponentRuntimeV2`, and existing SOAP 1.1 artifacts keep their V1 binding. These injection contracts are separate from package and capsule versions.
|
|
31
|
+
|
|
32
|
+
A V3 protocol `soap-fault` exposes version `1.1`, expanded `code`, `string`, optional `actor`, response bytes and transport status without a declared application `value` or fault `name`. A uniquely declared fault detail retains native decoding; malformed declared content is refused. See [runtime compatibility](https://github.com/TechSpokes/typescript-wsdl-client/blob/main/docs/decisions/005-checked-protocol-fault-compatibility.md) and [migration](migration.md#from-13x-to-140).
|
|
33
|
+
|
|
7
34
|
All file-producing APIs automatically apply [TypeScript preambles](generated-code.md#generated-preambles-and-eslint). Adding a preamble does not change an API signature or option; existing scaffold skip/force behavior still applies. Resource and TypeScript file-write failures propagate to callers.
|
|
8
35
|
|
|
9
|
-
Generated-output compatibility is versioned separately from those preambles. Read the [migration guide for the intended version](migration.md), including [1.
|
|
36
|
+
Generated-output compatibility is versioned separately from those preambles. Read the [migration guide for the intended version](migration.md), including [1.3.x-to-1.4.0 runtime adoption](migration.md#from-13x-to-140), before regenerating existing clients or changing their selected profile.
|
|
10
37
|
|
|
11
38
|
## compileWsdlToProject
|
|
12
39
|
|
|
@@ -335,6 +362,8 @@ The generated aggregate plugin exports `createClients`, `MultiServiceClientOptio
|
|
|
335
362
|
|
|
336
363
|
Compose existing OpenAPI 3.1 documents without generating clients or routers:
|
|
337
364
|
|
|
365
|
+
Checked documents regenerated with 1.4.1 or later support this API. Regeneration relocates generator-owned local schema resources while preserving configured names and native supplemental-validation metadata. Archived resource-bearing documents remain unsupported; composition does not replace native XML validation.
|
|
366
|
+
|
|
338
367
|
```typescript
|
|
339
368
|
interface OpenApiCompositionEntry {key: string; document: unknown}
|
|
340
369
|
interface OpenApiCompositionOptions {
|
package/docs/checked-gateway.md
CHANGED
|
@@ -8,6 +8,8 @@ SOAP 1.2 document/literal operations use the selected binding's envelope namespa
|
|
|
8
8
|
|
|
9
9
|
Generated SOAP 1.2 clients use the additive `checkedComponentRuntimeV2` package-root binding with protocol `checked-component-soap12-runtime-v1`. Existing SOAP 1.1 clients keep `checkedComponentRuntimeV1` and `checked-component-runtime-v2`, including their TypeScript injection contract. The older binding refuses SOAP 1.2 artifacts before SOAP dispatch.
|
|
10
10
|
|
|
11
|
+
Regenerated SOAP 1.1 clients use `checkedComponentRuntimeV3` and `checked-component-soap11-runtime-v1`. Valid SOAP 1.1 faults without declared application detail retain protocol metadata and original response bytes without inventing a typed value. Declared application detail still requires native validation; mixed or ambiguous declared detail refuses. Gateways expose protocol faults as HTTP 502 without a `value` member. Existing V1/V2 injection contracts remain available; see [ADR-005](https://github.com/TechSpokes/typescript-wsdl-client/blob/main/docs/decisions/005-checked-protocol-fault-compatibility.md).
|
|
12
|
+
|
|
11
13
|
SOAP 1.2 faults retain code, nested subcodes, language-tagged reasons and optional Node/Role metadata. Declared application detail uses the existing native mapping and gateway fault validation. A valid protocol fault without declared application detail carries fault metadata without a typed application value; the client retains original response bytes. Gateways return HTTP 502 for upstream faults, including SOAP Sender faults received on HTTP 400. SOAP 1.2 protocol rules follow [the messaging framework](https://www.w3.org/TR/soap12-part1/#soapfault) and [HTTP binding](https://www.w3.org/TR/soap12-part2/#soapinhttp).
|
|
12
14
|
|
|
13
15
|
SOAP 1.2 header processing uses the default ultimate receiver and next roles. Unknown mandatory blocks targeted at this receiver refuse; other-role and optional blocks may be ignored. The `mustUnderstand` and `relay` attributes accept SOAP 1.2 Boolean lexical forms. This does not enable outgoing application headers, WS-Security, streaming or RPC/encoded SOAP 1.2.
|
|
@@ -96,6 +98,48 @@ Previously, ordinary setup authored `sourceResources`, selectors, `endpoint` and
|
|
|
96
98
|
|
|
97
99
|
This component injection change uses `checked-component-runtime-v2`; regenerate clients, capsules, gateways and server scaffolds together when upgrading. The exported binding name remains `checkedComponentRuntimeV1` for existing imports, and existing explicit endpoint callbacks remain valid after regeneration. Consumer server/config/test files retain skip/force ownership rules; use existing force options deliberately to refresh those scaffolds. The v1.1.5 direct runtime protocol and legacy defaults are unchanged.
|
|
98
100
|
|
|
101
|
+
### Consumer-owned source corrections
|
|
102
|
+
|
|
103
|
+
Set `sourceCorrectionsFile` in checked generation configuration to apply a versioned JSON correction file to the project's outer and companion sources. Paths follow the existing generation convention: resolve them from the invocation working directory. Corrections are generation inputs; do not put them in HTTP request bodies or runtime endpoint configuration.
|
|
104
|
+
|
|
105
|
+
Maintain upstream snapshots unchanged and keep the correction file under version control. The correction file pins the complete original resource set by logical URI and digest. Refreshing upstream metadata requires regenerating and reviewing the correction draft. Scoped targets identify original declarations and particles, not generated TypeScript names. All edits resolve against the original inventory before application.
|
|
106
|
+
|
|
107
|
+
The bounded operations change particle occurrence bounds, narrow element wildcard namespaces, or insert a typed element into an existing sequence. Insertions require an existing named type or global element reference. Corrections do not define new complex types, rewrite imports, or change incoming SOAP XML. Use replacement snapshots for unsupported restructuring or sources that cannot construct a canonical inventory.
|
|
108
|
+
|
|
109
|
+
The correction document has `version: 1`, `resources: [{uri, digest}]`, and `corrections`. Retain every original resource pin supplied by the tool. A target is `{id, uri, digest}` copied from the inventory or draft; do not replace it with a generated DTO name. Complete unresolved draft values before passing the file to generation.
|
|
110
|
+
|
|
111
|
+
| Correction kind | Required settings |
|
|
112
|
+
| --- | --- |
|
|
113
|
+
| `set-occurs` | `target`, `min`, and `max`; bounds are canonical decimal strings, with `"unbounded"` also permitted for `max` |
|
|
114
|
+
| `set-wildcard-namespaces` | `target` and `namespaces`; use explicit namespace strings and `""` for the no-namespace case; the original `processContents` is preserved |
|
|
115
|
+
| `insert-element` | Sequence `target`, `position`, and `element`; position is `"append"` or `{kind: "before" or "after", target: originalChildTarget}` |
|
|
116
|
+
|
|
117
|
+
For a local inserted declaration, `element` contains `{kind: "declaration", name, type: {namespace, local}, min, max}`. The type must be a built-in XSD type or an existing named type. A global element reference instead uses `{kind: "reference", target: globalElementTarget, min, max}`. For example, a reviewed new scalar can use `type: {namespace: "http://www.w3.org/2001/XMLSchema", local: "string"}`; selecting that type is a contract decision, not an inference from one text value. Local declarations follow the containing schema's element-form rules.
|
|
118
|
+
|
|
119
|
+
Inserting a no-namespace type or reference beneath a nonempty default namespace currently refuses rather than changing QName meaning. Use a replacement snapshot for that case. Two insertions at the same original source position also refuse; choose distinct original anchors or supply a replacement snapshot for a larger restructuring.
|
|
120
|
+
|
|
121
|
+
Making metadata optional can make a following unrestricted wildcard ambiguous. Review both declarations: an explicit payload namespace constraint may be necessary to preserve native XSD 1.0 qualification. Narrowing changes the accepted contract, so confirm every intended payload namespace rather than copying the wrapper namespace by assumption.
|
|
122
|
+
|
|
123
|
+
Effective metadata is freshly parsed and checked before generation. Native decoding, SOAP bootstrap, generated types, OpenAPI, and runtime source reconstruction use those same effective bytes. Generated provenance distinguishes upstream and effective digests; successful validation establishes conformance to the consumer's effective contract, not upstream approval. Runtime needs the generated effective snapshots, not the correction file or upstream network access. Regenerate clients, contracts and gateways together after changes, and refresh source-derived presentation targets when necessary.
|
|
124
|
+
|
|
125
|
+
One generated project retains one effective byte sequence per logical URI. Shared declarations change for all their uses in that project. Conflicting URI contents and interpretation-specific edits to shared chameleon declarations refuse; separate replacement snapshots are required for those cases. This feature does not extend checked multi-service composition or legacy generation.
|
|
126
|
+
|
|
127
|
+
### Offline response inspection
|
|
128
|
+
|
|
129
|
+
Use `inspect-response` with a local WSDL, closed snapshot configuration, one configured operation and a saved SOAP response. It does not acquire missing remote metadata, dispatch SOAP, or read credentials. Create the output directory first; existing report or draft files are not overwritten.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npx wsdl-tsc inspect-response --wsdl-source ./sources/service.wsdl --checked-config ./checked.json --operation Fetch --response-file ./captures/fetch.xml --report .generated/inspection.json --corrections-draft .generated/corrections-draft.json
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
XML-only inspection leaves HTTP status and media checks unassessed. To assess an actual full response, add `--response-metadata ./captures/fetch-metadata.json` containing `status`, `contentType`, and optional `contentEncoding`. Do not invent metadata for a capture that did not retain it.
|
|
136
|
+
|
|
137
|
+
Reports separate wrapper and companion assessment. A valid inner payload cannot rescue an invalid wrapper. Reports omit decoded values and raw XML. Correction drafts provide pinned targets and existing values, but leave type, occurrence and namespace decisions unresolved until a developer reviews and completes them. Drafts may be unavailable when source loading or target inventory construction fails.
|
|
138
|
+
|
|
139
|
+
Drafts retain exact logical source URIs, which can include local filesystem paths, because those identities are needed to apply corrections. The CLI writes them only to the explicitly requested draft file. Programmatic callers must select `includeCorrectionDraft: true` to receive those additional local identities; ordinary diagnostic reports use resource labels.
|
|
140
|
+
|
|
141
|
+
Exit codes are 0 for conformance within the reported scope, 1 for mismatch/refusal, and 2 for invocation/file errors. A conforming SOAP fault remains identified as a fault. The package-root `inspectCheckedResponse` API accepts the same checked choices, a full operation selector, response bytes, optional actual response metadata, cancellation and XML limits; it returns diagnostic data without writing files.
|
|
142
|
+
|
|
99
143
|
### Planning and missing-schema recovery
|
|
100
144
|
|
|
101
145
|
`--checked-report` writes versioned `checked-component-plan-v1` JSON on native success or refusal. Human refusals identify the native reason, stage, dimension, affected full operation identities and configuration pointer. Source legality, correspondence, mapping/artifact readiness and runtime remain separate dimensions. Unsupported or inconclusive qualification does not establish invalid vendor schemas. Loading interruptions retain discovered counts plus explicit incomplete inventory; independent operation refusals are collected before generation writes project artifacts.
|
|
@@ -211,6 +255,10 @@ Generated `buildServer` accepts runtime cancellation, timeout and XML limits. Or
|
|
|
211
255
|
|
|
212
256
|
## Validation and coverage evidence
|
|
213
257
|
|
|
258
|
+
Regenerate with 1.4.1 or later to compose checked OpenAPI documents through `composeOpenApiDocuments`. Documentation definitions are relocated into operation- and role-scoped components for ungrouped shapes; configured grouped names remain unchanged. Runtime draft-07 schemas, capsules and native supplemental validation retain their existing contracts.
|
|
259
|
+
|
|
260
|
+
Composition preserves structural JSON documentation, not complete native XML equivalence. Archived 1.4.0 documents with embedded schema resources still refuse composition; updating the runtime package alone does not repair those documents.
|
|
261
|
+
|
|
214
262
|
OpenAPI documentation uses 3.1.1 with separate draft-07 HTTP runtime plans. Route-local Ajv disables coercion, default insertion and property removal, and preserves unrelated host policy. The native runtime explicitly converts validated HTTP values through the issued mapping, performs actual SOAP execution and independently validates response/fault XML. HTTP response validation also runs independently of serializer selection; JSON serialization preserves the validated values.
|
|
215
263
|
|
|
216
264
|
`client/inventory.json` and the API result's `checked` field list every discovered portType operation, selected service/port/binding, requested/generated operation and unselected operations. Generation records `executed:false`; it does not claim a SOAP call occurred. Refused selection diagnostics name the requested operation and zero generated/executed operations. Unselected operations remain unassessed.
|
package/docs/cli-reference.md
CHANGED
|
@@ -10,7 +10,7 @@ Generation paths are explicit. Examples use the git-ignored `.generated/` direct
|
|
|
10
10
|
|
|
11
11
|
## Commands Overview
|
|
12
12
|
|
|
13
|
-
The tool provides six generation commands and the
|
|
13
|
+
The tool provides six generation commands and the diagnostic commands `assess` and `inspect-response`.
|
|
14
14
|
|
|
15
15
|
TypeScript outputs automatically receive [generated preambles](generated-code.md#generated-preambles-and-eslint), including app/test scaffolds when actually written. Command syntax is unchanged and there is no preamble flag. `compile` and `openapi` data outputs remain unchanged.
|
|
16
16
|
|
|
@@ -23,6 +23,21 @@ TypeScript outputs automatically receive [generated preambles](generated-code.md
|
|
|
23
23
|
| app | Runnable Fastify app from client + gateway + OpenAPI | Local testing, demos |
|
|
24
24
|
| compile | Parse WSDL to catalog.json only | Debugging, multi-stage builds |
|
|
25
25
|
| assess | Source schema diagnostic report | Checked evidence and unresolved duties |
|
|
26
|
+
| inspect-response | Offline captured SOAP response inspection | Scoped mismatches and source correction drafts |
|
|
27
|
+
|
|
28
|
+
## inspect-response
|
|
29
|
+
|
|
30
|
+
Inspect saved SOAP XML using an authorized local checked source and closed snapshots. This command never dispatches SOAP or reads credentials.
|
|
31
|
+
|
|
32
|
+
Required inputs are `--wsdl-source`, `--checked-config`, `--operation`, `--response-file` and `--report`.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx wsdl-tsc inspect-response --wsdl-source ./sources/service.wsdl --checked-config ./checked.json --operation Fetch --response-file ./captures/fetch.xml --report .generated/inspection.json
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The checked configuration must list exactly one matching selector for `--operation`. Narrow `selectors` when different bindings expose the same operation name. Optional `--response-metadata` points to JSON containing actual `status`, `contentType` and optional `contentEncoding`; omission selects XML-only scope with HTTP checks unassessed. Optional `--corrections-draft` writes a draft when the inspector can derive one. Reports and drafts use exclusive creation; create the destination directory and choose unused filenames. Input files have a 1 MiB CLI capacity.
|
|
39
|
+
|
|
40
|
+
Exit 0 establishes conformance only within the report's assessment scope; 1 reports mismatch/refusal and 2 identifies invocation/file errors. SOAP faults remain faults even when their declared shape conforms. See [checked source corrections](checked-gateway.md#consumer-owned-source-corrections) for draft completion and regeneration.
|
|
26
41
|
|
|
27
42
|
## pipeline
|
|
28
43
|
|
package/docs/migration.md
CHANGED
|
@@ -6,6 +6,12 @@ Versions are listed newest first. Find your current version and follow the steps
|
|
|
6
6
|
|
|
7
7
|
See the root [README](../README.md). Historical version sections below describe their original releases; 1.2.0 compatibility guidance supersedes earlier unchanged-output statements for this upgrade.
|
|
8
8
|
|
|
9
|
+
## From 1.4.0 to 1.4.1
|
|
10
|
+
|
|
11
|
+
Regenerate checked specifications to compose them with `composeOpenApiDocuments`. Ungrouped documentation uses operation- and role-scoped components; configured grouped names remain stable. Archived 1.4.0 specifications containing embedded resources remain explicitly refused by composition.
|
|
12
|
+
|
|
13
|
+
Existing runtime artifacts remain usable. Runtime draft-07 validation, capsules and native supplemental validation are unchanged; structural documentation parity does not establish complete native XML equivalence.
|
|
14
|
+
|
|
9
15
|
## General Upgrade Steps
|
|
10
16
|
|
|
11
17
|
These steps apply to every version upgrade:
|
|
@@ -16,6 +22,16 @@ These steps apply to every version upgrade:
|
|
|
16
22
|
4. Regenerate matched generator-owned artifacts using the existing generation script and options.
|
|
17
23
|
5. Review the generated diff and run the consumer project's TypeScript build and tests.
|
|
18
24
|
|
|
25
|
+
## From 1.3.x to 1.4.0
|
|
26
|
+
|
|
27
|
+
Package updates preserve existing SOAP 1.1 V1 and SOAP 1.2 V2 runtime contracts. Newly generated checked SOAP 1.1 clients use `checkedComponentRuntimeV3` and `checked-component-soap11-runtime-v1`; regenerate matched clients, capsules, OpenAPI and gateways together to adopt that binding. Legacy generation and direct preview remain unchanged.
|
|
28
|
+
|
|
29
|
+
A V3 `soap-fault` can carry protocol metadata without a declared application `value` or fault `name`. Check whether a typed value exists before accessing it. Declared details still undergo native validation, and protocol faults remain gateway HTTP 502 responses.
|
|
30
|
+
|
|
31
|
+
Checked projects can opt into `sourceCorrectionsFile` for digest-pinned consumer corrections. Preserve upstream originals, review source changes, and regenerate effective snapshots and dependent artifacts together. Runtime deployments need effective snapshots and capsules, not the correction recipe; see [contract correction maintenance](checked-gateway.md).
|
|
32
|
+
|
|
33
|
+
Offline inspection accepts the complete multi-operation checked configuration and a full operation selector. Correction pins cover every project companion even when only one operation is inspected. XML-only reports do not establish HTTP status or media conformance without supplied response metadata.
|
|
34
|
+
|
|
19
35
|
## From 1.2.x to 1.3.0
|
|
20
36
|
|
|
21
37
|
Version 1.3.0 adds checked SOAP 1.2 document/literal execution. Legacy generation remains the default. Existing SOAP 1.1 component clients keep `checkedComponentRuntimeV1` and `checked-component-runtime-v2`; the shipped direct runtime is unchanged. Updating the package alone does not adopt SOAP 1.2 or require regeneration of existing SOAP 1.1 clients.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@techspokes/typescript-wsdl-client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Turn legacy WSDL/SOAP services into typed TypeScript clients, OpenAPI 3.1 specs, and production-ready Fastify REST gateways. Built for enterprise SOAP modernization.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wsdl",
|