@techspokes/typescript-wsdl-client 0.9.9 → 0.10.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.
@@ -1 +1 @@
1
- {"version":3,"file":"generateGateway.d.ts","sourceRoot":"","sources":["../../src/gateway/generateGateway.ts"],"names":[],"mappings":"AA4CA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAC;IACtC,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IAE/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqJjF"}
1
+ {"version":3,"file":"generateGateway.d.ts","sourceRoot":"","sources":["../../src/gateway/generateGateway.ts"],"names":[],"mappings":"AA6CA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAC;IACtC,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IAE/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsJjF"}
@@ -24,7 +24,7 @@ import fs from "node:fs";
24
24
  import path from "node:path";
25
25
  import * as yaml from "js-yaml";
26
26
  import { buildParamSchemasForOperation, getJsonSchemaRefName, isNumericStatus, resolveClientMeta, resolveOperationMeta, } from "./helpers.js";
27
- import { emitModelSchemas, emitOperationSchemas, emitPluginModule, emitRouteFiles, emitRouteFilesWithHandlers, emitRuntimeModule, emitSchemasModule, } from "./generators.js";
27
+ import { emitModelSchemas, emitOperationSchemas, emitPluginModule, emitTypeCheckFixture, emitRouteFiles, emitRouteFilesWithHandlers, emitRuntimeModule, emitSchemasModule, } from "./generators.js";
28
28
  /**
29
29
  * Generates Fastify gateway code from an OpenAPI 3.1 specification
30
30
  *
@@ -179,8 +179,9 @@ export async function generateGateway(opts) {
179
179
  if (emitRuntime) {
180
180
  emitRuntimeModule(outDir, versionSlug, serviceSlug);
181
181
  }
182
- // Step 7: Emit plugin.ts (if enabled)
182
+ // Step 7: Emit plugin.ts and type-check fixture (if enabled)
183
183
  if (emitPlugin) {
184
- emitPluginModule(outDir, versionSlug, serviceSlug, clientMeta, importsMode);
184
+ emitPluginModule(outDir, versionSlug, serviceSlug, clientMeta, importsMode, operations);
185
+ emitTypeCheckFixture(outDir, clientMeta, importsMode);
185
186
  }
186
187
  }
@@ -122,6 +122,7 @@ export declare function emitRuntimeModule(outDir: string, versionSlug: string, s
122
122
  *
123
123
  * Generated code includes:
124
124
  * - Plugin options interface with client and prefix support
125
+ * - Named operations interface for decorator type autocomplete
125
126
  * - Fastify decorator type augmentation
126
127
  * - Plugin implementation that registers schemas, routes, and error handler
127
128
  *
@@ -130,8 +131,21 @@ export declare function emitRuntimeModule(outDir: string, versionSlug: string, s
130
131
  * @param {string} serviceSlug - Service slug for function naming
131
132
  * @param {ClientMeta} clientMeta - Client class metadata
132
133
  * @param {"js"|"ts"|"bare"} importsMode - Import-extension mode
134
+ * @param {OperationMetadata[]} operations - Operation metadata for generating the operations interface
133
135
  */
134
- export declare function emitPluginModule(outDir: string, versionSlug: string, serviceSlug: string, clientMeta: ClientMeta, importsMode: "js" | "ts" | "bare"): void;
136
+ export declare function emitPluginModule(outDir: string, versionSlug: string, serviceSlug: string, clientMeta: ClientMeta, importsMode: "js" | "ts" | "bare", operations: OperationMetadata[]): void;
137
+ /**
138
+ * Emits a type-check fixture that verifies plugin-client type compatibility
139
+ *
140
+ * Generates `_typecheck.ts` in the gateway output directory. This file is
141
+ * picked up by tsconfig.smoke.json and will fail to compile if the plugin
142
+ * options interface diverges from the concrete client class.
143
+ *
144
+ * @param {string} outDir - Gateway output directory
145
+ * @param {ClientMeta} clientMeta - Client metadata (className, pluginImportPath)
146
+ * @param {"js"|"ts"|"bare"} importsMode - Import-extension mode
147
+ */
148
+ export declare function emitTypeCheckFixture(outDir: string, clientMeta: ClientMeta, importsMode: "js" | "ts" | "bare"): void;
135
149
  /**
136
150
  * Emits individual route files with full handler implementations
137
151
  *
@@ -1 +1 @@
1
- {"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../src/gateway/generators.ts"],"names":[],"mappings":"AAcA,OAAO,EAAC,KAAK,UAAU,EAAE,KAAK,eAAe,EAA6C,MAAM,cAAc,CAAC;AAE/G;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC5B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA6BxB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACtC,0BAA0B,EAAE,MAAM,EAAE,EACpC,iBAAiB,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,GAAG,EACvH,UAAU,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,MAAM,EACnC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GACnC,iBAAiB,EAAE,CA2HrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,IAAI,CAsBN;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,iBAAiB,EAAE,EAC/B,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,GAChC,IAAI,CA2CN;AAGD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,IAAI,CAkLN;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,UAAU,EACtB,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,GAChC,IAAI,CAyFN;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,iBAAiB,EAAE,EAC/B,WAAW,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,EACjC,UAAU,EAAE,UAAU,GACrB,IAAI,CAwEN"}
1
+ {"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../src/gateway/generators.ts"],"names":[],"mappings":"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"}
@@ -470,6 +470,7 @@ export function createGatewayErrorHandler_${vSlug}_${sSlug}() {
470
470
  *
471
471
  * Generated code includes:
472
472
  * - Plugin options interface with client and prefix support
473
+ * - Named operations interface for decorator type autocomplete
473
474
  * - Fastify decorator type augmentation
474
475
  * - Plugin implementation that registers schemas, routes, and error handler
475
476
  *
@@ -478,11 +479,17 @@ export function createGatewayErrorHandler_${vSlug}_${sSlug}() {
478
479
  * @param {string} serviceSlug - Service slug for function naming
479
480
  * @param {ClientMeta} clientMeta - Client class metadata
480
481
  * @param {"js"|"ts"|"bare"} importsMode - Import-extension mode
482
+ * @param {OperationMetadata[]} operations - Operation metadata for generating the operations interface
481
483
  */
482
- export function emitPluginModule(outDir, versionSlug, serviceSlug, clientMeta, importsMode) {
484
+ export function emitPluginModule(outDir, versionSlug, serviceSlug, clientMeta, importsMode, operations) {
483
485
  const vSlug = slugName(versionSlug);
484
486
  const sSlug = slugName(serviceSlug);
485
487
  const suffix = importsMode === "bare" ? "" : `.${importsMode}`;
488
+ // Build named operations interface methods from operation metadata
489
+ const operationMethods = operations
490
+ .filter(op => op.clientMethodName)
491
+ .map(op => ` ${op.clientMethodName}(args: unknown): Promise<{ response: unknown; headers: unknown }>;`)
492
+ .join("\n");
486
493
  const pluginTs = `/**
487
494
  * ${clientMeta.className} Gateway Plugin
488
495
  *
@@ -491,6 +498,7 @@ export function emitPluginModule(outDir, versionSlug, serviceSlug, clientMeta, i
491
498
  */
492
499
  import fp from "fastify-plugin";
493
500
  import type { FastifyInstance, FastifyPluginOptions } from "fastify";
501
+ import type { ${clientMeta.className} } from "${clientMeta.pluginImportPath}";
494
502
  import { registerSchemas_${vSlug}_${sSlug} } from "./schemas${suffix}";
495
503
  import { registerRoutes_${vSlug}_${sSlug} } from "./routes${suffix}";
496
504
  import { createGatewayErrorHandler_${vSlug}_${sSlug} } from "./runtime${suffix}";
@@ -503,9 +511,7 @@ export interface ${clientMeta.className}GatewayOptions extends FastifyPluginOpti
503
511
  * SOAP client instance (pre-configured).
504
512
  * The client should be instantiated with appropriate source and security settings.
505
513
  */
506
- client: {
507
- [method: string]: (args: unknown) => Promise<{ response: unknown; headers: unknown }>;
508
- };
514
+ client: ${clientMeta.className};
509
515
  /**
510
516
  * Optional additional route prefix applied at runtime.
511
517
  * Note: If you used --openapi-base-path during generation, routes already have that prefix baked in.
@@ -515,13 +521,20 @@ export interface ${clientMeta.className}GatewayOptions extends FastifyPluginOpti
515
521
  }
516
522
 
517
523
  /**
518
- * Fastify decorator type augmentation
524
+ * Convenience type listing all SOAP operations with \`args: unknown\` signatures.
525
+ *
526
+ * This interface is NOT used for the decorator type (which uses the concrete
527
+ * client class for full type safety). It is exported as a lightweight alternative
528
+ * for mocking or testing scenarios where importing the full client class is
529
+ * undesirable.
519
530
  */
531
+ export interface ${clientMeta.className}Operations {
532
+ ${operationMethods}
533
+ }
534
+
520
535
  declare module "fastify" {
521
536
  interface FastifyInstance {
522
- ${clientMeta.decoratorName}: {
523
- [method: string]: (args: unknown) => Promise<{ response: unknown; headers: unknown }>;
524
- };
537
+ ${clientMeta.decoratorName}: ${clientMeta.className};
525
538
  }
526
539
  }
527
540
 
@@ -567,6 +580,37 @@ export { ${sSlug}GatewayPlugin };
567
580
  `;
568
581
  fs.writeFileSync(path.join(outDir, "plugin.ts"), pluginTs, "utf8");
569
582
  }
583
+ /**
584
+ * Emits a type-check fixture that verifies plugin-client type compatibility
585
+ *
586
+ * Generates `_typecheck.ts` in the gateway output directory. This file is
587
+ * picked up by tsconfig.smoke.json and will fail to compile if the plugin
588
+ * options interface diverges from the concrete client class.
589
+ *
590
+ * @param {string} outDir - Gateway output directory
591
+ * @param {ClientMeta} clientMeta - Client metadata (className, pluginImportPath)
592
+ * @param {"js"|"ts"|"bare"} importsMode - Import-extension mode
593
+ */
594
+ export function emitTypeCheckFixture(outDir, clientMeta, importsMode) {
595
+ const suffix = importsMode === "bare" ? "" : `.${importsMode}`;
596
+ const content = `/**
597
+ * Type-check fixture — verifies plugin options accept the concrete client class.
598
+ * Auto-generated. Not intended for runtime use.
599
+ */
600
+ import type { ${clientMeta.className} } from "${clientMeta.pluginImportPath}";
601
+ import type { ${clientMeta.className}GatewayOptions } from "./plugin${suffix}";
602
+
603
+ // This function verifies structural compatibility at the type level.
604
+ // If the plugin options interface diverges from the client class, this
605
+ // will produce a compile error with a clear message.
606
+ function _assertClientCompatible(client: ${clientMeta.className}): void {
607
+ const _opts: ${clientMeta.className}GatewayOptions = { client };
608
+ void _opts;
609
+ }
610
+ void _assertClientCompatible;
611
+ `;
612
+ fs.writeFileSync(path.join(outDir, "_typecheck.ts"), content, "utf8");
613
+ }
570
614
  /**
571
615
  * Emits individual route files with full handler implementations
572
616
  *
@@ -600,9 +644,23 @@ export function emitRouteFilesWithHandlers(outDir, routesDir, versionSlug, servi
600
644
  routesTs += `import { ${fnName} } from "./routes/${routeFileBase}${suffix}";\n`;
601
645
  // Generate individual route file with full handler
602
646
  const clientMethod = op.clientMethodName || op.operationId || op.operationSlug;
603
- // Type names for documentation; we use unknown at runtime since schema validation handles it
604
647
  const reqTypeName = op.requestTypeName || "unknown";
605
648
  const resTypeName = op.responseTypeName || "unknown";
649
+ const hasRequestType = op.requestTypeName && op.requestTypeName !== "unknown";
650
+ // Build type import and route generic when request type is available.
651
+ // The Body generic narrows request.body for types with properties. For empty
652
+ // request types (e.g. no-arg operations), Fastify's KeysOf<Body> resolves to
653
+ // never and the generic is ignored — the `as` assertion at the call site
654
+ // handles this edge case. The cast is safe: JSON Schema validates at runtime.
655
+ const typeImport = hasRequestType
656
+ ? `import type { ${reqTypeName} } from "${clientMeta.typesImportPath}";\n`
657
+ : "";
658
+ const routeGeneric = hasRequestType
659
+ ? `<{ Body: ${reqTypeName} }>`
660
+ : "";
661
+ const bodyArg = hasRequestType
662
+ ? `request.body as ${reqTypeName}`
663
+ : "request.body";
606
664
  // Note: op.path comes from OpenAPI and already includes any base path
607
665
  let routeTs = `/**
608
666
  * Route: ${op.method.toUpperCase()} ${op.path}
@@ -612,17 +670,17 @@ export function emitRouteFilesWithHandlers(outDir, routesDir, versionSlug, servi
612
670
  * Auto-generated - do not edit manually.
613
671
  */
614
672
  import type { FastifyInstance } from "fastify";
615
- import schema from "../schemas/operations/${op.operationSlug}.json" with { type: "json" };
673
+ ${typeImport}import schema from "../schemas/operations/${op.operationSlug}.json" with { type: "json" };
616
674
  import { buildSuccessEnvelope } from "../runtime${suffix}";
617
675
 
618
676
  export async function ${fnName}(fastify: FastifyInstance) {
619
- fastify.route({
677
+ fastify.route${routeGeneric}({
620
678
  method: "${op.method.toUpperCase()}",
621
679
  url: "${op.path}",
622
680
  schema,
623
681
  handler: async (request) => {
624
682
  const client = fastify.${clientMeta.decoratorName};
625
- const result = await client.${clientMethod}(request.body);
683
+ const result = await client.${clientMethod}(${bodyArg});
626
684
  return buildSuccessEnvelope(result.response);
627
685
  },
628
686
  });
@@ -141,14 +141,16 @@ export declare function buildParamSchemasForOperation(pathItem: any, operation:
141
141
  * @interface ClientMeta
142
142
  * @property {string} className - Client class name (e.g., "EVRNService")
143
143
  * @property {string} decoratorName - Fastify decorator name (e.g., "evrnserviceClient")
144
- * @property {string} importPath - Import path relative to routes directory
145
- * @property {string} typesImportPath - Import path for types
144
+ * @property {string} importPath - Import path relative to routes/ directory — for future typed route handlers
145
+ * @property {string} typesImportPath - Types import path relative to routes/ directory — for future typed route handlers
146
+ * @property {string} pluginImportPath - Import path relative to gateway output directory — used by emitPluginModule()
146
147
  */
147
148
  export interface ClientMeta {
148
149
  className: string;
149
150
  decoratorName: string;
150
151
  importPath: string;
151
152
  typesImportPath: string;
153
+ pluginImportPath: string;
152
154
  }
153
155
  /**
154
156
  * Extended operation metadata for full handler generation
@@ -171,13 +173,6 @@ export interface ResolvedOperationMeta {
171
173
  requestTypeName?: string;
172
174
  responseTypeName?: string;
173
175
  }
174
- /**
175
- * PascalCase conversion utility
176
- *
177
- * @param {string} str - String to convert to PascalCase
178
- * @returns {string} - PascalCase version of the string
179
- */
180
- export declare function pascalCase(str: string): string;
181
176
  /**
182
177
  * Options for resolving client metadata
183
178
  *
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/gateway/helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/gateway/helpers.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,7 @@
10
10
  * - Parameter resolution with path-level and operation-level override support
11
11
  * - Automatic version/service detection from OpenAPI paths
12
12
  */
13
+ import { pascal } from "../util/tools.js";
13
14
  /**
14
15
  * Converts a name to a deterministic slug for use in file names and URN IDs
15
16
  *
@@ -339,17 +340,6 @@ export function buildParamSchemasForOperation(pathItem, operation, doc, schemaId
339
340
  headersSchema,
340
341
  };
341
342
  }
342
- /**
343
- * PascalCase conversion utility
344
- *
345
- * @param {string} str - String to convert to PascalCase
346
- * @returns {string} - PascalCase version of the string
347
- */
348
- export function pascalCase(str) {
349
- return str
350
- .replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ""))
351
- .replace(/^(.)/, (c) => c.toUpperCase());
352
- }
353
343
  /**
354
344
  * Resolves client metadata from available sources
355
345
  *
@@ -370,10 +360,10 @@ export function resolveClientMeta(opts, catalog) {
370
360
  className = opts.clientClassName;
371
361
  }
372
362
  else if (catalog?.serviceName) {
373
- className = pascalCase(catalog.serviceName);
363
+ className = pascal(catalog.serviceName);
374
364
  }
375
365
  else {
376
- className = pascalCase(opts.serviceSlug);
366
+ className = pascal(opts.serviceSlug);
377
367
  }
378
368
  // Determine decorator name
379
369
  let decoratorName;
@@ -383,18 +373,29 @@ export function resolveClientMeta(opts, catalog) {
383
373
  else {
384
374
  decoratorName = slugName(className) + "Client";
385
375
  }
386
- // Build import paths (relative from routes/ to client/)
376
+ // Build import paths for different directory depths.
377
+ //
378
+ // Standard layout (enforced by pipeline convention):
379
+ // {parent}/
380
+ // client/client.ts ← --client-dir
381
+ // gateway/ ← --gateway-dir
382
+ // plugin.ts ← pluginImportPath: one level up
383
+ // routes/foo.ts ← importPath: two levels up
387
384
  const importPath = opts.clientDir
388
385
  ? `../../client/client${suffix}`
389
386
  : `../client/client${suffix}`;
390
387
  const typesImportPath = opts.clientDir
391
388
  ? `../../client/types${suffix}`
392
389
  : `../client/types${suffix}`;
390
+ const pluginImportPath = opts.clientDir
391
+ ? `../client/client${suffix}`
392
+ : `./client/client${suffix}`;
393
393
  return {
394
394
  className,
395
395
  decoratorName,
396
396
  importPath,
397
397
  typesImportPath,
398
+ pluginImportPath,
398
399
  };
399
400
  }
400
401
  /**
@@ -411,8 +412,8 @@ export function resolveOperationMeta(operationId, operationSlug, method, path, c
411
412
  // Try to find matching operation in catalog
412
413
  const catalogOp = catalogOperations?.find(op => op.name === operationId || slugName(op.name) === operationSlug);
413
414
  // Use catalog type names if available, otherwise derive by convention
414
- const requestTypeName = catalogOp?.inputTypeName ?? pascalCase(operationId);
415
- const responseTypeName = catalogOp?.outputTypeName ?? pascalCase(operationId);
415
+ const requestTypeName = catalogOp?.inputTypeName ?? pascal(operationId);
416
+ const responseTypeName = catalogOp?.outputTypeName ?? pascal(operationId);
416
417
  return {
417
418
  operationId,
418
419
  operationSlug,
@@ -0,0 +1,223 @@
1
+ # Programmatic API
2
+
3
+ All CLI commands are available as TypeScript functions. This document covers each exported function, its usage, and its type signatures.
4
+
5
+ See the main [README](../README.md) for installation, CLI usage, and project overview.
6
+
7
+ ## compileWsdlToProject
8
+
9
+ Generate a TypeScript SOAP client from WSDL.
10
+
11
+ ```typescript
12
+ import { compileWsdlToProject } from "@techspokes/typescript-wsdl-client";
13
+
14
+ await compileWsdlToProject({
15
+ wsdl: "./wsdl/Hotel.wsdl",
16
+ outDir: "./src/services/hotel",
17
+ options: {
18
+ imports: "js",
19
+ catalog: true,
20
+ primitive: {
21
+ int64As: "number",
22
+ bigIntegerAs: "string",
23
+ decimalAs: "string",
24
+ dateAs: "string"
25
+ },
26
+ choice: "all-optional",
27
+ clientName: "HotelClient",
28
+ nillableAsOptional: false
29
+ }
30
+ });
31
+ ```
32
+
33
+ ### Type Signature
34
+
35
+ ```typescript
36
+ function compileWsdlToProject(input: {
37
+ wsdl: string;
38
+ outDir: string;
39
+ options?: Partial<CompilerOptions>;
40
+ }): Promise<void>;
41
+ ```
42
+
43
+ ### CompilerOptions
44
+
45
+ ```typescript
46
+ interface CompilerOptions {
47
+ wsdl: string;
48
+ out: string;
49
+ imports: "js" | "ts" | "bare";
50
+ catalog: boolean;
51
+ primitive: PrimitiveOptions;
52
+ choice?: "all-optional" | "union";
53
+ failOnUnresolved?: boolean;
54
+ attributesKey?: string;
55
+ clientName?: string;
56
+ nillableAsOptional?: boolean;
57
+ }
58
+
59
+ interface PrimitiveOptions {
60
+ int64As?: "string" | "number" | "bigint";
61
+ bigIntegerAs?: "string" | "number";
62
+ decimalAs?: "string" | "number";
63
+ dateAs?: "string" | "Date";
64
+ }
65
+ ```
66
+
67
+ ## generateOpenAPI
68
+
69
+ Generate an OpenAPI 3.1 specification from WSDL or catalog.
70
+
71
+ ```typescript
72
+ import { generateOpenAPI } from "@techspokes/typescript-wsdl-client";
73
+
74
+ const { doc, jsonPath, yamlPath } = await generateOpenAPI({
75
+ wsdl: "./wsdl/Hotel.wsdl",
76
+ outFile: "./docs/hotel-api",
77
+ format: "both",
78
+ title: "Hotel Booking API",
79
+ version: "1.0.0",
80
+ servers: ["https://api.example.com/v1"],
81
+ basePath: "/booking",
82
+ pathStyle: "kebab",
83
+ tagStyle: "service",
84
+ validate: true
85
+ });
86
+ ```
87
+
88
+ ### Type Signature
89
+
90
+ ```typescript
91
+ function generateOpenAPI(opts: GenerateOpenAPIOptions): Promise<{
92
+ doc: any;
93
+ jsonPath?: string;
94
+ yamlPath?: string;
95
+ }>;
96
+ ```
97
+
98
+ ### GenerateOpenAPIOptions
99
+
100
+ ```typescript
101
+ interface GenerateOpenAPIOptions {
102
+ wsdl?: string;
103
+ catalogFile?: string;
104
+ compiledCatalog?: CompiledCatalog;
105
+ outFile?: string;
106
+ format?: "json" | "yaml" | "both";
107
+ title?: string;
108
+ version?: string;
109
+ description?: string;
110
+ servers?: string[];
111
+ basePath?: string;
112
+ pathStyle?: "kebab" | "asis" | "lower";
113
+ defaultMethod?: string;
114
+ closedSchemas?: boolean;
115
+ pruneUnusedSchemas?: boolean;
116
+ tagStyle?: "default" | "first" | "service";
117
+ tagsFile?: string;
118
+ securityConfigFile?: string;
119
+ opsFile?: string;
120
+ envelopeNamespace?: string;
121
+ errorNamespace?: string;
122
+ validate?: boolean;
123
+ skipValidate?: boolean;
124
+ asYaml?: boolean; // deprecated
125
+ }
126
+ ```
127
+
128
+ ## generateGateway
129
+
130
+ Generate Fastify gateway code from an OpenAPI specification.
131
+
132
+ ```typescript
133
+ import { generateGateway } from "@techspokes/typescript-wsdl-client";
134
+
135
+ await generateGateway({
136
+ openapiFile: "./docs/hotel-api.json",
137
+ outDir: "./src/gateway/hotel",
138
+ clientDir: "./src/services/hotel",
139
+ versionSlug: "v1",
140
+ serviceSlug: "hotel",
141
+ defaultResponseStatusCodes: [200, 400, 401, 403, 404, 409, 422, 429, 500, 502, 503, 504],
142
+ imports: "js"
143
+ });
144
+ ```
145
+
146
+ ### Type Signature
147
+
148
+ ```typescript
149
+ function generateGateway(opts: GenerateGatewayOptions): Promise<void>;
150
+ ```
151
+
152
+ ### GenerateGatewayOptions
153
+
154
+ ```typescript
155
+ interface GenerateGatewayOptions {
156
+ openapiFile?: string;
157
+ openapiDocument?: any;
158
+ outDir: string;
159
+ clientDir?: string;
160
+ versionSlug?: string;
161
+ serviceSlug?: string;
162
+ defaultResponseStatusCodes?: number[];
163
+ imports?: "js" | "ts" | "bare";
164
+ }
165
+ ```
166
+
167
+ ## runGenerationPipeline
168
+
169
+ Run the complete pipeline: client, OpenAPI, and gateway in one pass.
170
+
171
+ ```typescript
172
+ import { runGenerationPipeline } from "@techspokes/typescript-wsdl-client";
173
+
174
+ const { compiled, openapiDoc } = await runGenerationPipeline({
175
+ wsdl: "./wsdl/Hotel.wsdl",
176
+ catalogOut: "./build/hotel-catalog.json",
177
+ clientOutDir: "./src/services/hotel",
178
+ compiler: {
179
+ imports: "js",
180
+ primitive: {
181
+ int64As: "number",
182
+ decimalAs: "string"
183
+ }
184
+ },
185
+ openapi: {
186
+ outFile: "./docs/hotel-api.json",
187
+ format: "both",
188
+ servers: ["https://api.example.com/v1"],
189
+ tagStyle: "service"
190
+ },
191
+ gateway: {
192
+ outDir: "./src/gateway/hotel",
193
+ versionSlug: "v1",
194
+ serviceSlug: "hotel"
195
+ }
196
+ });
197
+ ```
198
+
199
+ ### Type Signature
200
+
201
+ ```typescript
202
+ function runGenerationPipeline(opts: PipelineOptions): Promise<{
203
+ compiled: CompiledCatalog;
204
+ openapiDoc?: any;
205
+ }>;
206
+ ```
207
+
208
+ ### PipelineOptions
209
+
210
+ ```typescript
211
+ interface PipelineOptions {
212
+ wsdl: string;
213
+ catalogOut: string;
214
+ clientOutDir?: string;
215
+ compiler?: Partial<CompilerOptions>;
216
+ openapi?: Omit<GenerateOpenAPIOptions, "wsdl" | "catalogFile" | "compiledCatalog"> & {
217
+ outFile?: string;
218
+ };
219
+ gateway?: Omit<GenerateGatewayOptions, "openapiFile" | "openapiDocument"> & {
220
+ outDir?: string;
221
+ };
222
+ }
223
+ ```