@techspokes/typescript-wsdl-client 0.17.0 → 0.19.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +1 -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 +74 -7
  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 +2 -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/troubleshooting.md +1 -1
  41. package/package.json +5 -4
  42. package/src/runtime/appSecurity.tpl.txt +108 -0
@@ -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";
@@ -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.17.0",
3
+ "version": "0.19.2",
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",
@@ -77,23 +77,24 @@
77
77
  "smoke:gateway": "npm run smoke:reset && tsx src/cli.ts client --wsdl-source examples/minimal/weather.wsdl --client-dir tmp/client && tsx src/cli.ts openapi --catalog-file tmp/client/catalog.json --openapi-file tmp/openapi.json --openapi-format json && tsx src/cli.ts gateway --openapi-file tmp/openapi.json --client-dir tmp/client --gateway-dir tmp/gateway --gateway-service-name weather --gateway-version-prefix v1 && tsc -p tsconfig.smoke.json",
78
78
  "smoke:pipeline": "npm run smoke:reset && tsx src/cli.ts pipeline --wsdl-source examples/minimal/weather.wsdl --client-dir tmp/client --openapi-file tmp/openapi.json --gateway-dir tmp/gateway --gateway-service-name weather --gateway-version-prefix v1 --openapi-format json --init-app && tsc -p tsconfig.smoke.json",
79
79
  "smoke:app": "npm run smoke:reset && tsx src/cli.ts pipeline --wsdl-source examples/minimal/weather.wsdl --client-dir tmp/client --openapi-file tmp/openapi.json --gateway-dir tmp/gateway --gateway-service-name weather --gateway-version-prefix v1 --openapi-format json --openapi-servers https://example.com/api && tsx src/cli.ts app --client-dir tmp/client --gateway-dir tmp/gateway --openapi-file tmp/openapi.json --app-dir tmp/app --port 8080 && tsc -p tsconfig.smoke.json",
80
+ "maint:deps": "node scripts/maint-deps.mjs",
80
81
  "ci": "npm run clean && npm run build && npm run typecheck && vitest run && npm run smoke:pipeline",
81
82
  "examples:regenerate": "tsx src/cli.ts pipeline --wsdl-source examples/minimal/weather.wsdl --client-dir examples/generated-output/client --openapi-file examples/generated-output/openapi.json --gateway-dir examples/generated-output/gateway --gateway-service-name weather --gateway-version-prefix v1 --openapi-format json"
82
83
  },
83
84
  "devDependencies": {
84
85
  "@types/js-yaml": "^4.0.9",
85
- "@types/node": "^25.6.0",
86
+ "@types/node": "^25.7.0",
86
87
  "@types/yargs": "^17.0.35",
87
88
  "fastify": "^5.8.5",
88
89
  "fastify-plugin": "^5.1.0",
89
90
  "rimraf": "^6.1.3",
90
91
  "tsx": "^4.21.0",
91
92
  "typescript": "^6.0.3",
92
- "vitest": "^4.1.0"
93
+ "vitest": "^4.1.6"
93
94
  },
94
95
  "dependencies": {
95
96
  "@apidevtools/swagger-parser": "^12.1.0",
96
- "fast-xml-parser": "^5.7.1",
97
+ "fast-xml-parser": "^5.8.0",
97
98
  "js-yaml": "^4.1.1",
98
99
  "saxes": "^6.0.0",
99
100
  "soap": "^1.9.1",
@@ -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
+ }