@techspokes/typescript-wsdl-client 0.18.0 → 0.20.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.
Files changed (44) hide show
  1. package/README.md +2 -1
  2. package/dist/app/generateApp.d.ts +1 -0
  3. package/dist/app/generateApp.d.ts.map +1 -1
  4. package/dist/app/generateApp.js +76 -9
  5. package/dist/cli.js +12 -2
  6. package/dist/gateway/helpers.js +2 -2
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +1 -0
  10. package/dist/openapi/casing.d.ts +0 -14
  11. package/dist/openapi/casing.d.ts.map +1 -1
  12. package/dist/openapi/casing.js +3 -3
  13. package/dist/openapi/generateOpenAPI.d.ts.map +1 -1
  14. package/dist/openapi/generateOpenAPI.js +3 -0
  15. package/dist/openapi/security.d.ts +1 -81
  16. package/dist/openapi/security.d.ts.map +1 -1
  17. package/dist/openapi/security.js +1 -146
  18. package/dist/pipeline.d.ts +1 -0
  19. package/dist/pipeline.d.ts.map +1 -1
  20. package/dist/pipeline.js +1 -0
  21. package/dist/test/generateTests.js +2 -2
  22. package/dist/util/builder.js +1 -1
  23. package/dist/util/runtimeSource.d.ts +1 -0
  24. package/dist/util/runtimeSource.d.ts.map +1 -1
  25. package/dist/util/runtimeSource.js +4 -0
  26. package/dist/util/securityConfig.d.ts +115 -0
  27. package/dist/util/securityConfig.d.ts.map +1 -0
  28. package/dist/util/securityConfig.js +274 -0
  29. package/dist/util/tools.d.ts +8 -0
  30. package/dist/util/tools.d.ts.map +1 -1
  31. package/dist/util/tools.js +16 -0
  32. package/docs/README.md +3 -2
  33. package/docs/api-reference.md +28 -4
  34. package/docs/architecture.md +1 -1
  35. package/docs/cli-reference.md +4 -1
  36. package/docs/configuration.md +33 -18
  37. package/docs/gateway-guide.md +8 -8
  38. package/docs/generated-code.md +7 -0
  39. package/docs/migration-playbook.md +14 -5
  40. package/docs/releases/README.md +42 -0
  41. package/docs/releases/v0.20.0.md +22 -0
  42. package/docs/troubleshooting.md +1 -1
  43. package/package.json +4 -4
  44. package/src/runtime/appSecurity.tpl.txt +108 -0
@@ -8,28 +8,43 @@ See [CLI Reference](cli-reference.md) for flag details and [README](../README.md
8
8
 
9
9
  Pass via `--openapi-security-config-file`.
10
10
 
11
- Defines security schemes, headers, and per-operation overrides.
11
+ Defines REST gateway security, request headers, and upstream SOAP security. The `gateway` section describes the generated REST API in OpenAPI and adds Fastify header validation. The `upstream` section is used by the generated app scaffold to build `node-soap` runtime options from environment variables.
12
12
 
13
13
  ```json
14
14
  {
15
- "global": {
16
- "scheme": "bearer",
17
- "bearer": { "bearerFormat": "JWT" },
18
- "headers": [
19
- {
20
- "name": "X-Correlation-Id",
21
- "required": false,
22
- "schema": { "type": "string" }
23
- }
24
- ]
15
+ "gateway": {
16
+ "global": {
17
+ "scheme": "bearer",
18
+ "bearer": { "bearerFormat": "JWT" },
19
+ "headers": [
20
+ {
21
+ "name": "X-Correlation-Id",
22
+ "required": false,
23
+ "schema": { "type": "string" }
24
+ }
25
+ ]
26
+ },
27
+ "operations": {
28
+ "CancelBooking": { "scheme": "apiKey" },
29
+ "HealthCheck": { "scheme": "none" }
30
+ }
25
31
  },
26
- "overrides": {
27
- "CancelBooking": { "scheme": "apiKey" }
32
+ "upstream": {
33
+ "profile": "ws-security-username-token",
34
+ "usernameEnv": "SOAP_USERNAME",
35
+ "passwordEnv": "SOAP_PASSWORD",
36
+ "endpointEnv": "SOAP_ENDPOINT"
28
37
  }
29
38
  }
30
39
  ```
31
40
 
32
- Supported schemes: none, basic, bearer, apiKey, oauth2.
41
+ Gateway schemes: none, basic, bearer, apiKey, oauth2, mutualTLS, openIdConnect.
42
+
43
+ Upstream SOAP profiles: none, basic, bearer, ws-security-username-token, client-ssl, client-ssl-pfx, x509, ntlm, custom.
44
+
45
+ The older OpenAPI-only shape with top-level `global` and `overrides` is still accepted. New projects should use `gateway.global` and `gateway.operations`.
46
+
47
+ The generated app scaffold reads upstream secrets from environment variables. It does not embed secret values in generated source and does not implement production JWT, OAuth, or API-key verification for inbound gateway requests. Add that verification in app hooks or your platform gateway.
33
48
 
34
49
  ## Tags Configuration
35
50
 
@@ -107,8 +122,8 @@ terminal-error policy.
107
122
 
108
123
  ## Example Files
109
124
 
110
- Example configuration files are available in the `examples/openapi/` directory:
125
+ Example configuration files are available in the `examples/config/` directory:
111
126
 
112
- - `examples/openapi/security.json` for security scheme configuration
113
- - `examples/openapi/tags.json` for tag mapping
114
- - `examples/openapi/ops.json` for operation overrides
127
+ - `examples/config/security.json` for gateway and upstream security configuration
128
+ - `examples/config/tags.json` for tag mapping
129
+ - `examples/config/ops.json` for operation overrides
@@ -122,13 +122,13 @@ terminating zero-chunk.
122
122
 
123
123
  The centralized error handler (runtime.ts) automatically classifies errors:
124
124
 
125
- | Error Type | HTTP Status | Error Code |
126
- |------------|-------------|------------|
127
- | Validation errors | 400 | VALIDATION_ERROR |
128
- | SOAP faults | 502 | SOAP_FAULT |
129
- | Connection refused | 503 | SERVICE_UNAVAILABLE |
130
- | Timeout | 504 | GATEWAY_TIMEOUT |
131
- | Other errors | 500 | INTERNAL_ERROR |
125
+ | Error Type | HTTP Status | Error Code |
126
+ |--------------------|-------------|---------------------|
127
+ | Validation errors | 400 | VALIDATION_ERROR |
128
+ | SOAP faults | 502 | SOAP_FAULT |
129
+ | Connection refused | 503 | SERVICE_UNAVAILABLE |
130
+ | Timeout | 504 | GATEWAY_TIMEOUT |
131
+ | Other errors | 500 | INTERNAL_ERROR |
132
132
 
133
133
  All errors are wrapped in the standard envelope format. See [Concepts](concepts.md) for the envelope structure.
134
134
 
@@ -186,7 +186,7 @@ await app.register(async (scope) => {
186
186
  await app.listen({ port: 3000 });
187
187
  ```
188
188
 
189
- See [`examples/fastify-gateway/`](../examples/fastify-gateway/) for a complete example.
189
+ See [`examples/fastify-gateway`](../examples/fastify-gateway/README.md) for a complete example.
190
190
 
191
191
  ## Contract Assumptions
192
192
 
@@ -18,6 +18,13 @@ const client = new Weather({
18
18
 
19
19
  The `source` parameter accepts a URL or local file path to the WSDL.
20
20
 
21
+ When generating a runnable app with a security config, the scaffold can create
22
+ `security.ts` to build `soap.IOptions` and `soap.ISecurity` from environment
23
+ variables. The generated helper supports common `node-soap` profiles such as
24
+ Basic auth, bearer auth, WS-Security UsernameToken, TLS client certificates,
25
+ X509 signing, and NTLM. Secrets are read at runtime and are not embedded in
26
+ generated source.
27
+
21
28
  ## Calling Operations
22
29
 
23
30
  ```typescript
@@ -126,9 +126,16 @@ Create a security configuration file to add authentication to the OpenAPI spec a
126
126
 
127
127
  ```json
128
128
  {
129
- "global": {
130
- "scheme": "bearer",
131
- "bearer": { "bearerFormat": "JWT" }
129
+ "gateway": {
130
+ "global": {
131
+ "scheme": "bearer",
132
+ "bearer": { "bearerFormat": "JWT" }
133
+ }
134
+ },
135
+ "upstream": {
136
+ "profile": "ws-security-username-token",
137
+ "usernameEnv": "SOAP_USERNAME",
138
+ "passwordEnv": "SOAP_PASSWORD"
132
139
  }
133
140
  }
134
141
  ```
@@ -142,11 +149,13 @@ npx wsdl-tsc pipeline \
142
149
  ...
143
150
  ```
144
151
 
145
- See [Configuration](configuration.md) for all options including per-operation overrides and custom headers.
152
+ See [Configuration](configuration.md) for all options including per-operation overrides, custom headers, and upstream SOAP security profiles.
146
153
 
147
154
  ### Custom middleware
148
155
 
149
- Add middleware in your application code, not in the generated gateway files. The generated app scaffold (`index.ts`) is the right place for auth verification, logging, CORS, and other cross-cutting concerns.
156
+ Add middleware in your application code, not in the generated gateway files. The generated app scaffold (`server.ts`) is the right place for auth verification, logging, CORS, and other cross-cutting concerns.
157
+
158
+ The security config describes gateway authentication in OpenAPI and can scaffold upstream SOAP credentials for `node-soap`. It does not validate JWTs, OAuth tokens, or API keys for inbound REST requests. Use Fastify hooks, platform middleware, or your API gateway for that enforcement.
150
159
 
151
160
  ```typescript
152
161
  import Fastify from "fastify";
@@ -0,0 +1,42 @@
1
+ # Release Notes
2
+
3
+ Add one Markdown file per release tag. The draft release workflow requires this file before it creates or updates a GitHub draft release.
4
+
5
+ ## File Naming
6
+
7
+ Use the Git tag as the filename:
8
+
9
+ ```text
10
+ vX.Y.Z.md
11
+ ```
12
+
13
+ For example, release `0.20.1` uses tag `v0.20.1` and release notes file `docs/releases/v0.20.1.md`.
14
+
15
+ ## File Structure
16
+
17
+ Each release notes file must use this structure:
18
+
19
+ ```markdown
20
+ # TypeScript WSDL Client vX.Y.Z
21
+
22
+ Short summary paragraph.
23
+
24
+ ## Highlights
25
+
26
+ - User-facing release highlight.
27
+
28
+ ## Upgrade Notes
29
+
30
+ No special upgrade steps.
31
+
32
+ ## Validation
33
+
34
+ - `npm run maint:deps`
35
+ - `npm run ci`
36
+
37
+ ## Notes
38
+
39
+ Release tag: `vX.Y.Z`.
40
+ ```
41
+
42
+ Write release notes for users and maintainers, not as a file-by-file change log. Use `CHANGELOG.md` for the canonical version history.
@@ -0,0 +1,22 @@
1
+ # TypeScript WSDL Client v0.20.0
2
+
3
+ This release refreshes dependency minimums and adds a tag-driven draft release workflow so each GitHub release starts from a reviewed release notes document.
4
+
5
+ ## Highlights
6
+
7
+ - Bump root and generated app dependency minimums for `@types/node`, `soap`, and `tsx`.
8
+ - Add a `vX.Y.Z` tag workflow that validates the release state and creates or updates a GitHub draft release from `docs/releases/vX.Y.Z.md`.
9
+ - Require release notes in agent and contributor guidance so the changelog, package version, tag, and release description stay synchronized.
10
+
11
+ ## Upgrade Notes
12
+
13
+ No special upgrade steps.
14
+
15
+ ## Validation
16
+
17
+ - `npm run maint:deps`
18
+ - `npm run ci`
19
+
20
+ ## Notes
21
+
22
+ Release tag: `v0.20.0`.
@@ -12,7 +12,7 @@ See [README](../README.md) for quick start and [CLI Reference](cli-reference.md)
12
12
  | Unresolved type references | Re-run with --client-fail-on-unresolved=false to inspect partial graph |
13
13
  | Missing schema in OpenAPI | Ensure the global element exists (catalog shows compiled symbols) |
14
14
  | Wrong array modeling | Check maxOccurs in WSDL; tool only arrays when maxOccurs>1 or unbounded |
15
- | Authentication errors | Provide proper soap.ISecurity instance (WSSecurity, BasicAuthSecurity) |
15
+ | Authentication errors | Provide proper upstream security config or `soap.ISecurity` instance |
16
16
  | Date/time confusion | Use --client-date-as Date for runtime Date objects |
17
17
  | TypeScript compilation errors | Check --import-extensions matches your tsconfig moduleResolution |
18
18
  | Gateway validation failures | Ensure OpenAPI has valid $ref paths and all schemas in components.schemas |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@techspokes/typescript-wsdl-client",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
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",
@@ -83,12 +83,12 @@
83
83
  },
84
84
  "devDependencies": {
85
85
  "@types/js-yaml": "^4.0.9",
86
- "@types/node": "^25.7.0",
86
+ "@types/node": "^25.9.0",
87
87
  "@types/yargs": "^17.0.35",
88
88
  "fastify": "^5.8.5",
89
89
  "fastify-plugin": "^5.1.0",
90
90
  "rimraf": "^6.1.3",
91
- "tsx": "^4.21.0",
91
+ "tsx": "^4.22.2",
92
92
  "typescript": "^6.0.3",
93
93
  "vitest": "^4.1.6"
94
94
  },
@@ -97,7 +97,7 @@
97
97
  "fast-xml-parser": "^5.8.0",
98
98
  "js-yaml": "^4.1.1",
99
99
  "saxes": "^6.0.0",
100
- "soap": "^1.9.1",
100
+ "soap": "^1.9.2",
101
101
  "yargs": "^18.0.0"
102
102
  },
103
103
  "funding": {
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Upstream SOAP Security
3
+ *
4
+ * Builds node-soap runtime options from environment variables referenced by
5
+ * the generation-time security config. Secrets are intentionally read at
6
+ * runtime and are never embedded in generated source.
7
+ *
8
+ * Scaffolded by wsdl-tsc. Customize freely.
9
+ */
10
+ import fs from "node:fs";
11
+ import soap from "soap";
12
+
13
+ const upstream: any = __UPSTREAM_JSON__;
14
+
15
+ export interface SoapRuntimeConfig {
16
+ options?: soap.IOptions;
17
+ security?: soap.ISecurity;
18
+ }
19
+
20
+ export function buildSoapRuntimeConfig(): SoapRuntimeConfig {
21
+ const options: soap.IOptions = {};
22
+ const wsdlHeaders = buildHeaders(upstream.wsdlHeaders, upstream.wsdlHeaderEnv);
23
+ if (Object.keys(wsdlHeaders).length) {
24
+ options.wsdl_headers = wsdlHeaders;
25
+ }
26
+ const requestHeaders = buildHeaders(upstream.requestHeaders, upstream.requestHeaderEnv);
27
+ if (Object.keys(requestHeaders).length) {
28
+ options.extraHeaders = requestHeaders;
29
+ }
30
+ if (upstream.endpointEnv) {
31
+ const endpoint = process.env[upstream.endpointEnv];
32
+ if (endpoint) options.endpoint = endpoint;
33
+ }
34
+
35
+ const security = buildSoapSecurity();
36
+ return {
37
+ ...(Object.keys(options).length ? { options } : {}),
38
+ ...(security ? { security } : {}),
39
+ };
40
+ }
41
+
42
+ function buildSoapSecurity(): soap.ISecurity | undefined {
43
+ const soapRuntime = soap as any;
44
+ switch (upstream.profile ?? "none") {
45
+ case "none":
46
+ return undefined;
47
+ case "basic":
48
+ return new soapRuntime.BasicAuthSecurity(requiredEnv(upstream.usernameEnv, "upstream.usernameEnv"), requiredEnv(upstream.passwordEnv, "upstream.passwordEnv"));
49
+ case "bearer":
50
+ return new soapRuntime.BearerSecurity(requiredEnv(upstream.tokenEnv, "upstream.tokenEnv"));
51
+ case "ws-security-username-token":
52
+ return new soapRuntime.WSSecurity(
53
+ requiredEnv(upstream.usernameEnv, "upstream.usernameEnv"),
54
+ requiredEnv(upstream.passwordEnv, "upstream.passwordEnv"),
55
+ upstream.wsSecurity ?? {},
56
+ );
57
+ case "ntlm":
58
+ return new soapRuntime.NTLMSecurity({
59
+ username: requiredEnv(upstream.usernameEnv, "upstream.usernameEnv"),
60
+ password: requiredEnv(upstream.passwordEnv, "upstream.passwordEnv"),
61
+ domain: envValue(upstream.domainEnv),
62
+ workstation: envValue(upstream.workstationEnv),
63
+ });
64
+ case "client-ssl":
65
+ return new soapRuntime.ClientSSLSecurity(
66
+ readFileFromEnv(upstream.keyFileEnv, "upstream.keyFileEnv"),
67
+ readFileFromEnv(upstream.certFileEnv, "upstream.certFileEnv"),
68
+ upstream.caFileEnv ? readFileFromEnv(upstream.caFileEnv, "upstream.caFileEnv") : undefined,
69
+ );
70
+ case "client-ssl-pfx":
71
+ return new soapRuntime.ClientSSLSecurityPFX(
72
+ readFileFromEnv(upstream.pfxFileEnv, "upstream.pfxFileEnv"),
73
+ envValue(upstream.passphraseEnv),
74
+ );
75
+ case "x509":
76
+ return new soapRuntime.WSSecurityCert(
77
+ readFileFromEnv(upstream.keyFileEnv, "upstream.keyFileEnv"),
78
+ readFileFromEnv(upstream.certFileEnv, "upstream.certFileEnv"),
79
+ envValue(upstream.passphraseEnv) ?? "",
80
+ );
81
+ case "custom":
82
+ throw new Error("upstream.profile=custom requires editing security.ts to return a soap.ISecurity implementation.");
83
+ }
84
+ }
85
+
86
+ function buildHeaders(staticHeaders?: Record<string, string>, envHeaders?: Record<string, string>): Record<string, string> {
87
+ const headers: Record<string, string> = {...(staticHeaders ?? {})};
88
+ for (const [headerName, envName] of Object.entries(envHeaders ?? {})) {
89
+ const value = process.env[envName];
90
+ if (value) headers[headerName] = value;
91
+ }
92
+ return headers;
93
+ }
94
+
95
+ function requiredEnv(envName: string | undefined, label: string): string {
96
+ if (!envName) throw new Error(`${label} must name an environment variable.`);
97
+ const value = process.env[envName];
98
+ if (!value) throw new Error(`${envName} environment variable is required for upstream SOAP security.`);
99
+ return value;
100
+ }
101
+
102
+ function envValue(envName: string | undefined): string | undefined {
103
+ return envName ? process.env[envName] : undefined;
104
+ }
105
+
106
+ function readFileFromEnv(envName: string | undefined, label: string): Buffer {
107
+ return fs.readFileSync(requiredEnv(envName, label));
108
+ }