@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.
- package/README.md +1 -1
- package/dist/app/generateApp.d.ts +1 -0
- package/dist/app/generateApp.d.ts.map +1 -1
- package/dist/app/generateApp.js +74 -7
- package/dist/cli.js +12 -2
- package/dist/gateway/helpers.js +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/openapi/casing.d.ts +0 -14
- package/dist/openapi/casing.d.ts.map +1 -1
- package/dist/openapi/casing.js +3 -3
- package/dist/openapi/generateOpenAPI.d.ts.map +1 -1
- package/dist/openapi/generateOpenAPI.js +3 -0
- package/dist/openapi/security.d.ts +1 -81
- package/dist/openapi/security.d.ts.map +1 -1
- package/dist/openapi/security.js +1 -146
- package/dist/pipeline.d.ts +1 -0
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +1 -0
- package/dist/test/generateTests.js +2 -2
- package/dist/util/builder.js +1 -1
- package/dist/util/runtimeSource.d.ts +1 -0
- package/dist/util/runtimeSource.d.ts.map +1 -1
- package/dist/util/runtimeSource.js +4 -0
- package/dist/util/securityConfig.d.ts +115 -0
- package/dist/util/securityConfig.d.ts.map +1 -0
- package/dist/util/securityConfig.js +274 -0
- package/dist/util/tools.d.ts +8 -0
- package/dist/util/tools.d.ts.map +1 -1
- package/dist/util/tools.js +16 -0
- package/docs/README.md +2 -2
- package/docs/api-reference.md +28 -4
- package/docs/architecture.md +1 -1
- package/docs/cli-reference.md +4 -1
- package/docs/configuration.md +33 -18
- package/docs/gateway-guide.md +8 -8
- package/docs/generated-code.md +7 -0
- package/docs/migration-playbook.md +14 -5
- package/docs/troubleshooting.md +1 -1
- package/package.json +5 -4
- package/src/runtime/appSecurity.tpl.txt +108 -0
package/dist/util/builder.js
CHANGED
|
@@ -40,7 +40,7 @@ export function buildOpenApiOptionsFromArgv(argv, format, servers) {
|
|
|
40
40
|
opsFile: argv["openapi-ops-file"],
|
|
41
41
|
pathStyle: argv["openapi-path-style"],
|
|
42
42
|
pruneUnusedSchemas: argv["openapi-prune-unused-schemas"],
|
|
43
|
-
securityConfigFile: argv["openapi-security-file"],
|
|
43
|
+
securityConfigFile: (argv["openapi-security-config-file"] || argv["openapi-security-file"]),
|
|
44
44
|
servers,
|
|
45
45
|
skipValidate: false, // Always validate
|
|
46
46
|
tagStyle: argv["openapi-tag-style"],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeSource.d.ts","sourceRoot":"","sources":["../../src/util/runtimeSource.ts"],"names":[],"mappings":"AAsCA,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI1D"}
|
|
1
|
+
{"version":3,"file":"runtimeSource.d.ts","sourceRoot":"","sources":["../../src/util/runtimeSource.ts"],"names":[],"mappings":"AAsCA,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI1D;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG5D"}
|
|
@@ -36,3 +36,7 @@ export function loadRuntimeSource(filename) {
|
|
|
36
36
|
const raw = fs.readFileSync(abs, "utf-8");
|
|
37
37
|
return HEADER(filename) + "\n" + raw;
|
|
38
38
|
}
|
|
39
|
+
export function loadRuntimeTemplate(filename) {
|
|
40
|
+
const abs = resolveRuntimeSourcePath(filename);
|
|
41
|
+
return fs.readFileSync(abs, "utf-8");
|
|
42
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
export type GatewayAuthScheme = "none" | "basic" | "bearer" | "apiKey" | "oauth2" | "mutualTLS" | "openIdConnect";
|
|
2
|
+
export type SecurityHeaderConfig = {
|
|
3
|
+
name: string;
|
|
4
|
+
required?: boolean;
|
|
5
|
+
schema?: any;
|
|
6
|
+
};
|
|
7
|
+
export type GatewaySecurityGlobal = {
|
|
8
|
+
scheme?: GatewayAuthScheme;
|
|
9
|
+
apiKey?: {
|
|
10
|
+
in: "header" | "query" | "cookie";
|
|
11
|
+
name: string;
|
|
12
|
+
};
|
|
13
|
+
bearer?: {
|
|
14
|
+
bearerFormat?: string;
|
|
15
|
+
};
|
|
16
|
+
basic?: Record<string, never>;
|
|
17
|
+
oauth2?: {
|
|
18
|
+
flows: Record<string, any>;
|
|
19
|
+
};
|
|
20
|
+
openIdConnect?: {
|
|
21
|
+
openIdConnectUrl: string;
|
|
22
|
+
};
|
|
23
|
+
mutualTLS?: {
|
|
24
|
+
description?: string;
|
|
25
|
+
};
|
|
26
|
+
headers?: SecurityHeaderConfig[];
|
|
27
|
+
};
|
|
28
|
+
export type GatewaySecurityOperation = {
|
|
29
|
+
scheme?: GatewayAuthScheme;
|
|
30
|
+
headers?: SecurityHeaderConfig[];
|
|
31
|
+
};
|
|
32
|
+
export type UpstreamSecurityConfig = {
|
|
33
|
+
profile?: "none" | "basic" | "bearer" | "ws-security-username-token" | "client-ssl" | "client-ssl-pfx" | "x509" | "ntlm" | "custom";
|
|
34
|
+
usernameEnv?: string;
|
|
35
|
+
passwordEnv?: string;
|
|
36
|
+
tokenEnv?: string;
|
|
37
|
+
domainEnv?: string;
|
|
38
|
+
workstationEnv?: string;
|
|
39
|
+
keyFileEnv?: string;
|
|
40
|
+
certFileEnv?: string;
|
|
41
|
+
caFileEnv?: string;
|
|
42
|
+
pfxFileEnv?: string;
|
|
43
|
+
passphraseEnv?: string;
|
|
44
|
+
endpointEnv?: string;
|
|
45
|
+
wsdlHeaders?: Record<string, string>;
|
|
46
|
+
wsdlHeaderEnv?: Record<string, string>;
|
|
47
|
+
requestHeaders?: Record<string, string>;
|
|
48
|
+
requestHeaderEnv?: Record<string, string>;
|
|
49
|
+
wsSecurity?: {
|
|
50
|
+
passwordType?: "PasswordText" | "PasswordDigest";
|
|
51
|
+
hasTimeStamp?: boolean;
|
|
52
|
+
hasTokenCreated?: boolean;
|
|
53
|
+
hasNonce?: boolean;
|
|
54
|
+
mustUnderstand?: boolean;
|
|
55
|
+
actor?: string;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
export type SecurityConfig = {
|
|
59
|
+
gateway?: {
|
|
60
|
+
global?: GatewaySecurityGlobal;
|
|
61
|
+
operations?: Record<string, GatewaySecurityOperation>;
|
|
62
|
+
overrides?: Record<string, GatewaySecurityOperation>;
|
|
63
|
+
};
|
|
64
|
+
upstream?: UpstreamSecurityConfig;
|
|
65
|
+
headers?: {
|
|
66
|
+
passThrough?: string[];
|
|
67
|
+
mappings?: Array<{
|
|
68
|
+
from: string;
|
|
69
|
+
to: string;
|
|
70
|
+
required?: boolean;
|
|
71
|
+
}>;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
export type BuiltSecurity = {
|
|
75
|
+
securitySchemes?: Record<string, any>;
|
|
76
|
+
headerParameters: Record<string, any>;
|
|
77
|
+
opSecurity: Record<string, any[] | undefined>;
|
|
78
|
+
opHeaderParameters: Record<string, string[]>;
|
|
79
|
+
globalSecurity?: any[];
|
|
80
|
+
};
|
|
81
|
+
export declare class SecurityConfigError extends Error {
|
|
82
|
+
constructor(message: string);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Loads and normalizes a JSON security configuration file.
|
|
86
|
+
*
|
|
87
|
+
* @param filePath - Optional path to the JSON config. Undefined returns undefined.
|
|
88
|
+
* @returns Parsed security configuration, or undefined when no file is provided.
|
|
89
|
+
* @throws SecurityConfigError when the parsed JSON shape is invalid.
|
|
90
|
+
* @throws SyntaxError when the file is not valid JSON.
|
|
91
|
+
*/
|
|
92
|
+
export declare function loadSecurityConfigFile(filePath?: string): SecurityConfig | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* Normalizes the shared gateway and upstream SOAP security config.
|
|
95
|
+
*
|
|
96
|
+
* @param input - Raw JSON value from a security config file or programmatic caller.
|
|
97
|
+
* @returns Normalized security config with legacy OpenAPI-only shape mapped to `gateway`.
|
|
98
|
+
* @throws SecurityConfigError when a section or scheme is malformed.
|
|
99
|
+
*/
|
|
100
|
+
export declare function parseSecurityConfig(input: unknown): SecurityConfig;
|
|
101
|
+
/**
|
|
102
|
+
* Builds the OpenAPI-facing security schemes, requirements, and header parameters.
|
|
103
|
+
*
|
|
104
|
+
* @param cfg - Normalized shared security config.
|
|
105
|
+
* @returns Deterministic OpenAPI security fragments consumed by the OpenAPI generator.
|
|
106
|
+
*/
|
|
107
|
+
export declare function buildSecurity(cfg?: SecurityConfig): BuiltSecurity;
|
|
108
|
+
/**
|
|
109
|
+
* Checks whether a generated app needs an upstream SOAP security helper.
|
|
110
|
+
*
|
|
111
|
+
* @param cfg - Normalized shared security config.
|
|
112
|
+
* @returns True when `upstream.profile` is configured to anything other than `none`.
|
|
113
|
+
*/
|
|
114
|
+
export declare function hasUpstreamRuntimeSecurity(cfg?: SecurityConfig): boolean;
|
|
115
|
+
//# sourceMappingURL=securityConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"securityConfig.d.ts","sourceRoot":"","sources":["../../src/util/securityConfig.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,eAAe,CAAC;AAElH,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,GAAG,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE;QAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,CAAC;IAC3D,MAAM,CAAC,EAAE;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAAC,CAAC;IACtC,aAAa,CAAC,EAAE;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAC,CAAC;IAC3C,SAAS,CAAC,EAAE;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC;IACnC,OAAO,CAAC,EAAE,oBAAoB,EAAE,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,OAAO,CAAC,EAAE,oBAAoB,EAAE,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,CAAC,EACJ,MAAM,GACN,OAAO,GACP,QAAQ,GACR,4BAA4B,GAC5B,YAAY,GACZ,gBAAgB,GAChB,MAAM,GACN,MAAM,GACN,QAAQ,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,UAAU,CAAC,EAAE;QACX,YAAY,CAAC,EAAE,cAAc,GAAG,gBAAgB,CAAC;QACjD,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,qBAAqB,CAAC;QAC/B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;QACtD,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;KACtD,CAAC;IACF,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,OAAO,CAAC,EAAE;QACR,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;QACvB,QAAQ,CAAC,EAAE,KAAK,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;SAAC,CAAC,CAAC;KAClE,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC;IAC9C,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7C,cAAc,CAAC,EAAE,GAAG,EAAE,CAAC;CACxB,CAAC;AAEF,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAIpF;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAuBlE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,cAAc,GAAG,aAAa,CA0DjE;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,CAAC,EAAE,cAAc,GAAG,OAAO,CAExE"}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { trimRepeatedEdgeChar } from "./tools.js";
|
|
3
|
+
export class SecurityConfigError extends Error {
|
|
4
|
+
constructor(message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "SecurityConfigError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Loads and normalizes a JSON security configuration file.
|
|
11
|
+
*
|
|
12
|
+
* @param filePath - Optional path to the JSON config. Undefined returns undefined.
|
|
13
|
+
* @returns Parsed security configuration, or undefined when no file is provided.
|
|
14
|
+
* @throws SecurityConfigError when the parsed JSON shape is invalid.
|
|
15
|
+
* @throws SyntaxError when the file is not valid JSON.
|
|
16
|
+
*/
|
|
17
|
+
export function loadSecurityConfigFile(filePath) {
|
|
18
|
+
if (!filePath)
|
|
19
|
+
return undefined;
|
|
20
|
+
const raw = fs.readFileSync(filePath, "utf8");
|
|
21
|
+
return parseSecurityConfig(JSON.parse(raw));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Normalizes the shared gateway and upstream SOAP security config.
|
|
25
|
+
*
|
|
26
|
+
* @param input - Raw JSON value from a security config file or programmatic caller.
|
|
27
|
+
* @returns Normalized security config with legacy OpenAPI-only shape mapped to `gateway`.
|
|
28
|
+
* @throws SecurityConfigError when a section or scheme is malformed.
|
|
29
|
+
*/
|
|
30
|
+
export function parseSecurityConfig(input) {
|
|
31
|
+
if (!isRecord(input)) {
|
|
32
|
+
throw new SecurityConfigError("Security config must be a JSON object.");
|
|
33
|
+
}
|
|
34
|
+
const root = input;
|
|
35
|
+
const gatewaySource = isRecord(root.gateway)
|
|
36
|
+
? root.gateway
|
|
37
|
+
: hasLegacyGatewayShape(root)
|
|
38
|
+
? { global: root.global, overrides: root.overrides }
|
|
39
|
+
: undefined;
|
|
40
|
+
const cfg = {};
|
|
41
|
+
if (gatewaySource) {
|
|
42
|
+
cfg.gateway = parseGatewaySecurity(gatewaySource);
|
|
43
|
+
}
|
|
44
|
+
if (root.upstream !== undefined) {
|
|
45
|
+
cfg.upstream = parseUpstreamSecurity(root.upstream);
|
|
46
|
+
}
|
|
47
|
+
if (root.headers !== undefined) {
|
|
48
|
+
cfg.headers = parseHeaderForwarding(root.headers);
|
|
49
|
+
}
|
|
50
|
+
return cfg;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Builds the OpenAPI-facing security schemes, requirements, and header parameters.
|
|
54
|
+
*
|
|
55
|
+
* @param cfg - Normalized shared security config.
|
|
56
|
+
* @returns Deterministic OpenAPI security fragments consumed by the OpenAPI generator.
|
|
57
|
+
*/
|
|
58
|
+
export function buildSecurity(cfg) {
|
|
59
|
+
const securitySchemes = {};
|
|
60
|
+
const headerParameters = {};
|
|
61
|
+
const opSecurity = {};
|
|
62
|
+
const opHeaderParameters = {};
|
|
63
|
+
const gateway = cfg?.gateway;
|
|
64
|
+
const global = gateway?.global;
|
|
65
|
+
if (!global) {
|
|
66
|
+
return { securitySchemes: undefined, headerParameters, opSecurity, opHeaderParameters };
|
|
67
|
+
}
|
|
68
|
+
const schemeName = "defaultAuth";
|
|
69
|
+
const scheme = global.scheme || "none";
|
|
70
|
+
const hasGlobal = scheme !== "none";
|
|
71
|
+
if (hasGlobal) {
|
|
72
|
+
securitySchemes[schemeName] = buildSecurityScheme(scheme, global);
|
|
73
|
+
}
|
|
74
|
+
for (const h of global.headers || []) {
|
|
75
|
+
headerParameters[makeParamComponentName(h.name)] = buildHeaderParameter(h);
|
|
76
|
+
}
|
|
77
|
+
const operations = {
|
|
78
|
+
...(gateway.overrides || {}),
|
|
79
|
+
...(gateway.operations || {}),
|
|
80
|
+
};
|
|
81
|
+
for (const [opName, override] of Object.entries(operations)) {
|
|
82
|
+
const oScheme = override.scheme ?? scheme;
|
|
83
|
+
if (oScheme === "none") {
|
|
84
|
+
opSecurity[opName] = [{}];
|
|
85
|
+
}
|
|
86
|
+
else if (oScheme === scheme) {
|
|
87
|
+
opSecurity[opName] = hasGlobal ? [{ [schemeName]: [] }] : undefined;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const altName = `${schemeName}_${oScheme}`;
|
|
91
|
+
if (!securitySchemes[altName]) {
|
|
92
|
+
securitySchemes[altName] = buildSecurityScheme(oScheme, global);
|
|
93
|
+
}
|
|
94
|
+
opSecurity[opName] = [{ [altName]: [] }];
|
|
95
|
+
}
|
|
96
|
+
const headers = [...(global.headers || []), ...(override.headers || [])];
|
|
97
|
+
opHeaderParameters[opName] = headers.map(h => makeParamComponentName(h.name));
|
|
98
|
+
for (const h of override.headers || []) {
|
|
99
|
+
const compName = makeParamComponentName(h.name);
|
|
100
|
+
if (!headerParameters[compName]) {
|
|
101
|
+
headerParameters[compName] = buildHeaderParameter(h);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
securitySchemes: Object.keys(securitySchemes).length ? securitySchemes : undefined,
|
|
107
|
+
headerParameters,
|
|
108
|
+
opSecurity,
|
|
109
|
+
opHeaderParameters,
|
|
110
|
+
globalSecurity: hasGlobal ? [{ [schemeName]: [] }] : undefined,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Checks whether a generated app needs an upstream SOAP security helper.
|
|
115
|
+
*
|
|
116
|
+
* @param cfg - Normalized shared security config.
|
|
117
|
+
* @returns True when `upstream.profile` is configured to anything other than `none`.
|
|
118
|
+
*/
|
|
119
|
+
export function hasUpstreamRuntimeSecurity(cfg) {
|
|
120
|
+
return !!cfg?.upstream && (cfg.upstream.profile ?? "none") !== "none";
|
|
121
|
+
}
|
|
122
|
+
function parseGatewaySecurity(input) {
|
|
123
|
+
const global = input.global === undefined ? undefined : parseGatewayGlobal(input.global);
|
|
124
|
+
const operations = input.operations === undefined ? undefined : parseGatewayOperations(input.operations, "operations");
|
|
125
|
+
const overrides = input.overrides === undefined ? undefined : parseGatewayOperations(input.overrides, "overrides");
|
|
126
|
+
return { global, operations, overrides };
|
|
127
|
+
}
|
|
128
|
+
function parseGatewayGlobal(input) {
|
|
129
|
+
if (!isRecord(input)) {
|
|
130
|
+
throw new SecurityConfigError("gateway.global must be an object.");
|
|
131
|
+
}
|
|
132
|
+
const scheme = parseGatewayScheme(input.scheme, "gateway.global.scheme");
|
|
133
|
+
return {
|
|
134
|
+
...(scheme ? { scheme } : {}),
|
|
135
|
+
...(isRecord(input.apiKey) ? { apiKey: parseApiKey(input.apiKey) } : {}),
|
|
136
|
+
...(isRecord(input.bearer) ? { bearer: input.bearer } : {}),
|
|
137
|
+
...(isRecord(input.basic) ? { basic: {} } : {}),
|
|
138
|
+
...(isRecord(input.oauth2) ? { oauth2: input.oauth2 } : {}),
|
|
139
|
+
...(isRecord(input.openIdConnect) ? { openIdConnect: input.openIdConnect } : {}),
|
|
140
|
+
...(isRecord(input.mutualTLS) ? { mutualTLS: input.mutualTLS } : {}),
|
|
141
|
+
...(input.headers !== undefined ? { headers: parseHeaders(input.headers, "gateway.global.headers") } : {}),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function parseGatewayOperations(input, label) {
|
|
145
|
+
if (!isRecord(input)) {
|
|
146
|
+
throw new SecurityConfigError(`gateway.${label} must be an object keyed by operation name.`);
|
|
147
|
+
}
|
|
148
|
+
const out = {};
|
|
149
|
+
for (const [opName, value] of Object.entries(input)) {
|
|
150
|
+
if (!isRecord(value)) {
|
|
151
|
+
throw new SecurityConfigError(`gateway.${label}.${opName} must be an object.`);
|
|
152
|
+
}
|
|
153
|
+
const scheme = parseGatewayScheme(value.scheme, `gateway.${label}.${opName}.scheme`);
|
|
154
|
+
out[opName] = {
|
|
155
|
+
...(scheme ? { scheme } : {}),
|
|
156
|
+
...(value.headers !== undefined ? { headers: parseHeaders(value.headers, `gateway.${label}.${opName}.headers`) } : {}),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return out;
|
|
160
|
+
}
|
|
161
|
+
function parseUpstreamSecurity(input) {
|
|
162
|
+
if (!isRecord(input)) {
|
|
163
|
+
throw new SecurityConfigError("upstream must be an object.");
|
|
164
|
+
}
|
|
165
|
+
const profile = input.profile === undefined ? undefined : String(input.profile);
|
|
166
|
+
const allowed = new Set(["none", "basic", "bearer", "ws-security-username-token", "client-ssl", "client-ssl-pfx", "x509", "ntlm", "custom"]);
|
|
167
|
+
if (profile && !allowed.has(profile)) {
|
|
168
|
+
throw new SecurityConfigError(`Unsupported upstream.profile '${profile}'.`);
|
|
169
|
+
}
|
|
170
|
+
return input;
|
|
171
|
+
}
|
|
172
|
+
function parseHeaderForwarding(input) {
|
|
173
|
+
if (!isRecord(input)) {
|
|
174
|
+
throw new SecurityConfigError("headers must be an object.");
|
|
175
|
+
}
|
|
176
|
+
const passThrough = input.passThrough === undefined ? undefined : parseStringArray(input.passThrough, "headers.passThrough");
|
|
177
|
+
const mappings = input.mappings === undefined ? undefined : parseMappings(input.mappings);
|
|
178
|
+
return {
|
|
179
|
+
...(passThrough ? { passThrough } : {}),
|
|
180
|
+
...(mappings ? { mappings } : {}),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function parseHeaders(input, label) {
|
|
184
|
+
if (!Array.isArray(input)) {
|
|
185
|
+
throw new SecurityConfigError(`${label} must be an array.`);
|
|
186
|
+
}
|
|
187
|
+
return input.map((entry, index) => {
|
|
188
|
+
if (!isRecord(entry) || typeof entry.name !== "string" || !entry.name.trim()) {
|
|
189
|
+
throw new SecurityConfigError(`${label}[${index}].name must be a non-empty string.`);
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
name: entry.name,
|
|
193
|
+
...(entry.required !== undefined ? { required: Boolean(entry.required) } : {}),
|
|
194
|
+
...(entry.schema !== undefined ? { schema: entry.schema } : {}),
|
|
195
|
+
};
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
function parseGatewayScheme(input, label) {
|
|
199
|
+
if (input === undefined)
|
|
200
|
+
return undefined;
|
|
201
|
+
const scheme = String(input);
|
|
202
|
+
if (!["none", "basic", "bearer", "apiKey", "oauth2", "mutualTLS", "openIdConnect"].includes(scheme)) {
|
|
203
|
+
throw new SecurityConfigError(`Unsupported ${label} '${scheme}'.`);
|
|
204
|
+
}
|
|
205
|
+
return scheme;
|
|
206
|
+
}
|
|
207
|
+
function parseApiKey(input) {
|
|
208
|
+
const location = input.in === undefined ? "header" : String(input.in);
|
|
209
|
+
if (!["header", "query", "cookie"].includes(location)) {
|
|
210
|
+
throw new SecurityConfigError("apiKey.in must be header, query, or cookie.");
|
|
211
|
+
}
|
|
212
|
+
const name = input.name === undefined ? "X-API-Key" : String(input.name);
|
|
213
|
+
if (!name) {
|
|
214
|
+
throw new SecurityConfigError("apiKey.name must be a non-empty string.");
|
|
215
|
+
}
|
|
216
|
+
return { in: location, name };
|
|
217
|
+
}
|
|
218
|
+
function parseStringArray(input, label) {
|
|
219
|
+
if (!Array.isArray(input) || input.some(v => typeof v !== "string" || !v)) {
|
|
220
|
+
throw new SecurityConfigError(`${label} must be an array of non-empty strings.`);
|
|
221
|
+
}
|
|
222
|
+
return input;
|
|
223
|
+
}
|
|
224
|
+
function parseMappings(input) {
|
|
225
|
+
if (!Array.isArray(input)) {
|
|
226
|
+
throw new SecurityConfigError("headers.mappings must be an array.");
|
|
227
|
+
}
|
|
228
|
+
return input.map((entry, index) => {
|
|
229
|
+
if (!isRecord(entry) || typeof entry.from !== "string" || typeof entry.to !== "string" || !entry.from || !entry.to) {
|
|
230
|
+
throw new SecurityConfigError(`headers.mappings[${index}] must define non-empty from and to strings.`);
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
from: entry.from,
|
|
234
|
+
to: entry.to,
|
|
235
|
+
...(entry.required !== undefined ? { required: Boolean(entry.required) } : {}),
|
|
236
|
+
};
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
function buildSecurityScheme(scheme, global) {
|
|
240
|
+
switch (scheme) {
|
|
241
|
+
case "basic":
|
|
242
|
+
return { type: "http", scheme: "basic" };
|
|
243
|
+
case "bearer":
|
|
244
|
+
return { type: "http", scheme: "bearer", ...(global.bearer || {}) };
|
|
245
|
+
case "apiKey":
|
|
246
|
+
return { type: "apiKey", ...(global.apiKey || { in: "header", name: "X-API-Key" }) };
|
|
247
|
+
case "oauth2":
|
|
248
|
+
return { type: "oauth2", ...(global.oauth2 || { flows: {} }) };
|
|
249
|
+
case "mutualTLS":
|
|
250
|
+
return { type: "mutualTLS", ...(global.mutualTLS || {}) };
|
|
251
|
+
case "openIdConnect":
|
|
252
|
+
return { type: "openIdConnect", ...(global.openIdConnect || { openIdConnectUrl: "" }) };
|
|
253
|
+
case "none":
|
|
254
|
+
return undefined;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function buildHeaderParameter(h) {
|
|
258
|
+
return {
|
|
259
|
+
name: h.name,
|
|
260
|
+
in: "header",
|
|
261
|
+
required: !!h.required,
|
|
262
|
+
schema: h.schema || { type: "string" },
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function makeParamComponentName(headerName) {
|
|
266
|
+
return trimRepeatedEdgeChar(headerName.replace(/[^A-Za-z0-9]+/g, "_"), "_")
|
|
267
|
+
|| "X_Header";
|
|
268
|
+
}
|
|
269
|
+
function hasLegacyGatewayShape(root) {
|
|
270
|
+
return root.global !== undefined || root.overrides !== undefined;
|
|
271
|
+
}
|
|
272
|
+
function isRecord(value) {
|
|
273
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
274
|
+
}
|
package/dist/util/tools.d.ts
CHANGED
|
@@ -25,6 +25,14 @@ import type { CompiledCatalog } from "../compiler/schemaCompiler.js";
|
|
|
25
25
|
* @returns {T[]} - Array containing the value(s) or empty array if null/undefined
|
|
26
26
|
*/
|
|
27
27
|
export declare function normalizeArray<T>(x: T | T[] | undefined | null): T[];
|
|
28
|
+
/**
|
|
29
|
+
* Removes one repeated edge character without regex backtracking.
|
|
30
|
+
*
|
|
31
|
+
* @param value - Value to trim.
|
|
32
|
+
* @param char - Single character to remove from both edges.
|
|
33
|
+
* @returns Input without repeated leading or trailing `char` values.
|
|
34
|
+
*/
|
|
35
|
+
export declare function trimRepeatedEdgeChar(value: string, char: string): string;
|
|
28
36
|
/**
|
|
29
37
|
* Collects direct children whose local name matches (prefix-agnostic)
|
|
30
38
|
*
|
package/dist/util/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/util/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,+BAA+B,CAAC;AAEnE;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,SAAS,GAAG,IAAI,GAAG,CAAC,EAAE,CAGpE;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,CASxE;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAK/E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CA6BxC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAS/B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,eAAe,GACxB,MAAM,CAWR;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAMjD;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAInD"}
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/util/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,+BAA+B,CAAC;AAEnE;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,SAAS,GAAG,IAAI,GAAG,CAAC,EAAE,CAGpE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMxE;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,CASxE;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAK/E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CA6BxC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAS/B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,eAAe,GACxB,MAAM,CAWR;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAMjD;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAInD"}
|
package/dist/util/tools.js
CHANGED
|
@@ -13,6 +13,22 @@ export function normalizeArray(x) {
|
|
|
13
13
|
return [];
|
|
14
14
|
return Array.isArray(x) ? x : [x];
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Removes one repeated edge character without regex backtracking.
|
|
18
|
+
*
|
|
19
|
+
* @param value - Value to trim.
|
|
20
|
+
* @param char - Single character to remove from both edges.
|
|
21
|
+
* @returns Input without repeated leading or trailing `char` values.
|
|
22
|
+
*/
|
|
23
|
+
export function trimRepeatedEdgeChar(value, char) {
|
|
24
|
+
let start = 0;
|
|
25
|
+
let end = value.length;
|
|
26
|
+
while (start < end && value[start] === char)
|
|
27
|
+
start += 1;
|
|
28
|
+
while (end > start && value[end - 1] === char)
|
|
29
|
+
end -= 1;
|
|
30
|
+
return value.slice(start, end);
|
|
31
|
+
}
|
|
16
32
|
/**
|
|
17
33
|
* Collects direct children whose local name matches (prefix-agnostic)
|
|
18
34
|
*
|
package/docs/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Human-maintained reference documents for `@techspokes/typescript-wsdl-client`. T
|
|
|
12
12
|
|
|
13
13
|
- [cli-reference.md](cli-reference.md): all 6 commands with flags and examples
|
|
14
14
|
- [generated-code.md](generated-code.md): using clients, types, and operations
|
|
15
|
-
- [configuration.md](configuration.md): security
|
|
15
|
+
- [configuration.md](configuration.md): gateway security, upstream SOAP security, tags, operations config files
|
|
16
16
|
- [migration-playbook.md](migration-playbook.md): end-to-end SOAP modernization guide
|
|
17
17
|
|
|
18
18
|
## Operate
|
|
@@ -42,7 +42,7 @@ Human-maintained reference documents for `@techspokes/typescript-wsdl-client`. T
|
|
|
42
42
|
- [Root README](../README.md): project overview, quick start, and authoritative Documentation section
|
|
43
43
|
- [CONTRIBUTING.md](../CONTRIBUTING.md): development setup and workflow
|
|
44
44
|
- [CHANGELOG.md](../CHANGELOG.md): version history
|
|
45
|
-
- [examples
|
|
45
|
+
- [examples](../examples/README.md): sample WSDL files and generated output
|
|
46
46
|
|
|
47
47
|
## Not Here
|
|
48
48
|
|
package/docs/api-reference.md
CHANGED
|
@@ -33,7 +33,7 @@ await compileWsdlToProject({
|
|
|
33
33
|
### Type Signature
|
|
34
34
|
|
|
35
35
|
```typescript
|
|
36
|
-
function compileWsdlToProject(input: {
|
|
36
|
+
declare function compileWsdlToProject(input: {
|
|
37
37
|
wsdl: string;
|
|
38
38
|
outDir: string;
|
|
39
39
|
options?: Partial<CompilerOptions>;
|
|
@@ -92,7 +92,7 @@ const { doc, jsonPath, yamlPath } = await generateOpenAPI({
|
|
|
92
92
|
### Type Signature
|
|
93
93
|
|
|
94
94
|
```typescript
|
|
95
|
-
function generateOpenAPI(opts: GenerateOpenAPIOptions): Promise<{
|
|
95
|
+
declare function generateOpenAPI(opts: GenerateOpenAPIOptions): Promise<{
|
|
96
96
|
doc: any;
|
|
97
97
|
jsonPath?: string;
|
|
98
98
|
yamlPath?: string;
|
|
@@ -129,6 +129,10 @@ interface GenerateOpenAPIOptions {
|
|
|
129
129
|
}
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
+
`securityConfigFile` accepts the shared security configuration documented in
|
|
133
|
+
[Configuration](configuration.md#security-configuration). The config can describe
|
|
134
|
+
gateway OpenAPI security and upstream SOAP runtime security for generated apps.
|
|
135
|
+
|
|
132
136
|
## generateGateway
|
|
133
137
|
|
|
134
138
|
Generate Fastify gateway code from an OpenAPI specification.
|
|
@@ -150,7 +154,7 @@ await generateGateway({
|
|
|
150
154
|
### Type Signature
|
|
151
155
|
|
|
152
156
|
```typescript
|
|
153
|
-
function generateGateway(opts: GenerateGatewayOptions): Promise<void>;
|
|
157
|
+
declare function generateGateway(opts: GenerateGatewayOptions): Promise<void>;
|
|
154
158
|
```
|
|
155
159
|
|
|
156
160
|
### GenerateGatewayOptions
|
|
@@ -203,7 +207,7 @@ const { compiled, openapiDoc } = await runGenerationPipeline({
|
|
|
203
207
|
### Type Signature
|
|
204
208
|
|
|
205
209
|
```typescript
|
|
206
|
-
function runGenerationPipeline(opts: PipelineOptions): Promise<{
|
|
210
|
+
declare function runGenerationPipeline(opts: PipelineOptions): Promise<{
|
|
207
211
|
compiled: CompiledCatalog;
|
|
208
212
|
openapiDoc?: any;
|
|
209
213
|
}>;
|
|
@@ -332,6 +336,26 @@ interface OperationStreamMetadata {
|
|
|
332
336
|
|
|
333
337
|
Exactly one of `wsdlSource` or `catalogFile` must be set on each `ShapeCatalogRef`. `OperationStreamMetadata` is produced by the parser; `sourceOutputTypeName` is populated by the compiler when it binds the operation to the main WSDL.
|
|
334
338
|
|
|
339
|
+
## Security Configuration Helpers
|
|
340
|
+
|
|
341
|
+
Parse and build the shared security configuration used by OpenAPI generation and
|
|
342
|
+
the app scaffold.
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
import {
|
|
346
|
+
buildSecurity,
|
|
347
|
+
loadSecurityConfigFile,
|
|
348
|
+
parseSecurityConfig,
|
|
349
|
+
} from "@techspokes/typescript-wsdl-client";
|
|
350
|
+
|
|
351
|
+
const config = loadSecurityConfigFile("./security.json");
|
|
352
|
+
const built = buildSecurity(config);
|
|
353
|
+
console.log(built.securitySchemes);
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
`parseSecurityConfig` accepts the same JSON shape as `loadSecurityConfigFile`.
|
|
357
|
+
`SecurityConfigError` is thrown for invalid schemes or malformed sections.
|
|
358
|
+
|
|
335
359
|
## End-to-End Example
|
|
336
360
|
|
|
337
361
|
Compile with a stream config, verify the catalog carries the expected metadata, and run the full pipeline:
|
package/docs/architecture.md
CHANGED
|
@@ -53,7 +53,7 @@ generateClient.ts emits the client class with one method per operation. generate
|
|
|
53
53
|
|
|
54
54
|
### openapi/
|
|
55
55
|
|
|
56
|
-
generateOpenAPI.ts orchestrates the complete OpenAPI document. generateSchemas.ts converts compiled types to JSON Schema. generatePaths.ts generates path items from operations. security.ts
|
|
56
|
+
generateOpenAPI.ts orchestrates the complete OpenAPI document. generateSchemas.ts converts compiled types to JSON Schema. generatePaths.ts generates path items from operations. security.ts adapts the shared security configuration model for OpenAPI. casing.ts handles path style transformation.
|
|
57
57
|
|
|
58
58
|
### gateway/
|
|
59
59
|
|
package/docs/cli-reference.md
CHANGED
|
@@ -92,7 +92,7 @@ The catalog is auto-placed alongside the first available output directory: `{cli
|
|
|
92
92
|
| `--openapi-envelope-namespace` | `ResponseEnvelope` | Envelope component name suffix |
|
|
93
93
|
| `--openapi-error-namespace` | `ErrorObject` | Error object name suffix |
|
|
94
94
|
| `--openapi-validate` | `true` | Validate spec with swagger-parser |
|
|
95
|
-
| `--openapi-security-config-file` | | Path to security.json |
|
|
95
|
+
| `--openapi-security-config-file` | | Path to security.json; `--openapi-security-file` is accepted as an alias |
|
|
96
96
|
| `--openapi-tags-file` | | Path to tags.json |
|
|
97
97
|
| `--openapi-ops-file` | | Path to ops.json |
|
|
98
98
|
|
|
@@ -473,6 +473,7 @@ npx wsdl-tsc app \
|
|
|
473
473
|
| `--prefix` | (empty) | Route prefix |
|
|
474
474
|
| `--logger` | true | Enable Fastify logger |
|
|
475
475
|
| `--openapi-mode` | copy | copy or reference |
|
|
476
|
+
| `--security-config-file` | (none) | Path to security.json for upstream SOAP security scaffold |
|
|
476
477
|
| `--force` | false | Overwrite existing scaffold files |
|
|
477
478
|
|
|
478
479
|
### Generated Structure
|
|
@@ -499,6 +500,8 @@ app/
|
|
|
499
500
|
| `LOGGER` | true | Fastify logger |
|
|
500
501
|
| `OPENAPI_SERVER_URL` | (empty) | Override OpenAPI spec server URL at runtime |
|
|
501
502
|
|
|
503
|
+
When `--security-config-file` is supplied and it contains an `upstream` profile, `.env.example` also lists the environment variables referenced by that profile.
|
|
504
|
+
|
|
502
505
|
### Endpoints
|
|
503
506
|
|
|
504
507
|
- `GET /health` returns `{ "ok": true }`
|
package/docs/configuration.md
CHANGED
|
@@ -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
|
|
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
|
-
"
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
"
|
|
27
|
-
"
|
|
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
|
-
|
|
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/
|
|
125
|
+
Example configuration files are available in the `examples/config/` directory:
|
|
111
126
|
|
|
112
|
-
- `examples/
|
|
113
|
-
- `examples/
|
|
114
|
-
- `examples/
|
|
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
|