oapiex 0.2.2 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1142,11 +1142,18 @@ var TypeScriptModuleRenderer = class {
1142
1142
  "export interface OpenApiMediaTypeDefinition<TExample = unknown> {\n schema?: OpenApiSchemaDefinition\n example?: TExample\n}",
1143
1143
  "export interface OpenApiResponseDefinition<_TResponse = unknown, TExample = unknown> {\n description: string\n content?: Record<string, OpenApiMediaTypeDefinition<TExample>>\n}",
1144
1144
  "export interface OpenApiRequestBodyDefinition<TInput = unknown> {\n description?: string\n required: boolean\n content: Record<string, OpenApiMediaTypeDefinition<TInput>>\n}",
1145
- "export interface OpenApiOperationDefinition<_TResponse = unknown, TResponseExample = unknown, TInput = Record<string, never>, _TQuery = Record<string, never>, _THeader = Record<string, never>, _TParams = Record<string, never>> {\n summary?: string\n description?: string\n operationId?: string\n parameters?: OpenApiParameterDefinition[]\n requestBody?: OpenApiRequestBodyDefinition<TInput>\n responses: Record<string, OpenApiResponseDefinition<_TResponse, TResponseExample>>\n}",
1145
+ "export interface OpenApiOauthFlowDefinition {\n authorizationUrl?: string\n tokenUrl?: string\n refreshUrl?: string\n scopes?: Record<string, string>\n}",
1146
+ "export type OpenApiSecurityRequirementDefinition = Record<string, string[]>",
1147
+ "export type OpenApiSecuritySchemeDefinition =\n | {\n type: 'http'\n description?: string\n scheme: string\n bearerFormat?: string\n }\n | {\n type: 'apiKey'\n description?: string\n name: string\n in: 'query' | 'header' | 'cookie'\n }\n | {\n type: 'oauth2'\n description?: string\n flows?: Record<string, OpenApiOauthFlowDefinition>\n }\n | {\n type: 'openIdConnect'\n description?: string\n openIdConnectUrl: string\n }",
1148
+ "export interface OpenApiComponentsDefinition {\n securitySchemes?: Record<string, OpenApiSecuritySchemeDefinition>\n}",
1149
+ "export interface OpenApiOperationDefinition<_TResponse = unknown, TResponseExample = unknown, TInput = Record<string, never>, _TQuery = Record<string, never>, _THeader = Record<string, never>, _TParams = Record<string, never>> {\n summary?: string\n description?: string\n operationId?: string\n security?: OpenApiSecurityRequirementDefinition[]\n parameters?: OpenApiParameterDefinition[]\n requestBody?: OpenApiRequestBodyDefinition<TInput>\n responses: Record<string, OpenApiResponseDefinition<_TResponse, TResponseExample>>\n}",
1146
1150
  "export interface OpenApiSdkParameterManifest {\n name: string\n accessor: string\n in: 'query' | 'header' | 'path'\n required: boolean\n description?: string\n}",
1147
- "export interface OpenApiSdkOperationManifest {\n path: string\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n methodName: string\n summary?: string\n description?: string\n operationId?: string\n requestBodyDescription?: string\n responseDescription?: string\n responseType: string\n inputType: string\n queryType: string\n headerType: string\n paramsType: string\n hasBody: boolean\n bodyRequired: boolean\n pathParams: OpenApiSdkParameterManifest[]\n queryParams: OpenApiSdkParameterManifest[]\n headerParams: OpenApiSdkParameterManifest[]\n}",
1151
+ "export interface OpenApiSdkSecurityRequirementSchemeManifest {\n name: string\n scopes: string[]\n}",
1152
+ "export interface OpenApiSdkSecurityRequirementManifest {\n schemes: OpenApiSdkSecurityRequirementSchemeManifest[]\n}",
1153
+ "export interface OpenApiSdkSecuritySchemeManifest {\n name: string\n helperName: string\n description?: string\n type: 'http' | 'apiKey' | 'oauth2' | 'openIdConnect'\n authType: 'bearer' | 'basic' | 'apiKey' | 'oauth2'\n scheme?: string\n bearerFormat?: string\n in?: 'header' | 'query' | 'cookie'\n parameterName?: string\n openIdConnectUrl?: string\n scopes?: string[]\n}",
1154
+ "export interface OpenApiSdkOperationManifest {\n path: string\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'\n methodName: string\n summary?: string\n description?: string\n operationId?: string\n requestBodyDescription?: string\n responseDescription?: string\n responseType: string\n inputType: string\n queryType: string\n headerType: string\n paramsType: string\n hasBody: boolean\n bodyRequired: boolean\n pathParams: OpenApiSdkParameterManifest[]\n queryParams: OpenApiSdkParameterManifest[]\n headerParams: OpenApiSdkParameterManifest[]\n security?: OpenApiSdkSecurityRequirementManifest[]\n}",
1148
1155
  "export interface OpenApiSdkGroupManifest {\n className: string\n propertyName: string\n operations: OpenApiSdkOperationManifest[]\n}",
1149
- "export interface OpenApiSdkManifest {\n groups: OpenApiSdkGroupManifest[]\n}",
1156
+ "export interface OpenApiSdkManifest {\n groups: OpenApiSdkGroupManifest[]\n securitySchemes: OpenApiSdkSecuritySchemeManifest[]\n security?: OpenApiSdkSecurityRequirementManifest[]\n}",
1150
1157
  "export interface OpenApiRuntimeBundle<TApi = unknown> {\n document: unknown\n manifest: OpenApiSdkManifest\n __api?: TApi\n}",
1151
1158
  Object.entries(document.paths).map(([path, operations]) => {
1152
1159
  const pathTypeName = this.derivePathTypeName(path);
@@ -1164,7 +1171,7 @@ var TypeScriptModuleRenderer = class {
1164
1171
  }).join("\n\n"), `export interface ${pathTypeName} {\n${Object.keys(operations).map((method) => ` ${method}: ${this.deriveOperationInterfaceName(path, method)}`).join("\n")}\n}`].join("\n\n");
1165
1172
  }).join("\n\n"),
1166
1173
  `export interface Paths {\n${Object.keys(document.paths).map((path) => ` ${this.formatPropertyKey(path)}: ${this.derivePathTypeName(path)}`).join("\n")}\n}`,
1167
- `export interface ${rootTypeName} {\n openapi: '3.1.0'\n info: OpenApiInfo\n paths: Paths\n}`
1174
+ `export interface ${rootTypeName} {\n openapi: '3.1.0'\n info: OpenApiInfo\n components?: OpenApiComponentsDefinition\n security?: OpenApiSecurityRequirementDefinition[]\n paths: Paths\n}`
1168
1175
  ].join("\n\n");
1169
1176
  }
1170
1177
  renderSdkApiInterface(rootTypeName, manifest) {
@@ -1259,7 +1266,7 @@ var TypeScriptModuleRenderer = class {
1259
1266
  if (value.length === 0) return "[]";
1260
1267
  const nextIndent = this.indent(indentLevel + 1);
1261
1268
  const currentIndent = this.indent(indentLevel);
1262
- return `[\n${value.map((entry) => `${nextIndent}${this.renderLiteral(entry, indentLevel + 1)}`).join(",\n")}\n${currentIndent}]`;
1269
+ return `\n[`.startsWith("\n[") ? `[\n${value.map((entry) => `${nextIndent}${this.renderLiteral(entry, indentLevel + 1)}`).join(",\n")}\n${currentIndent}]` : "[]";
1263
1270
  }
1264
1271
  if (typeof value === "object") {
1265
1272
  const entries = Object.entries(value);
@@ -2042,9 +2049,22 @@ var TypeScriptShapeBuilder = class {
2042
2049
  var TypeScriptTypeBuilder = class {
2043
2050
  naming = new TypeScriptNamingSupport();
2044
2051
  shapes = new TypeScriptShapeBuilder(this.naming);
2052
+ /**
2053
+ * Creates a new generator context, which holds the state of the type generation process.
2054
+ *
2055
+ * @returns
2056
+ */
2045
2057
  createContext() {
2046
2058
  return this.shapes.createContext();
2047
2059
  }
2060
+ /**
2061
+ * Collects semantic models from the given OpenAPI document, which represent the various
2062
+ * shapes and types that need to be generated for the SDK, along with their associated
2063
+ * metadata such as paths, methods, and roles.
2064
+ *
2065
+ * @param document The OpenAPI document to extract semantic models from.
2066
+ * @returns An array of semantic models representing the shapes and types for the SDK.
2067
+ */
2048
2068
  collectSemanticModels(document) {
2049
2069
  const models = [];
2050
2070
  for (const [path, operations] of Object.entries(document.paths)) {
@@ -2107,9 +2127,20 @@ var TypeScriptTypeBuilder = class {
2107
2127
  }
2108
2128
  return models;
2109
2129
  }
2130
+ /**
2131
+ * Builds the SDK manifest from the given OpenAPI document, using the provided operation
2132
+ * type references and naming strategy options.
2133
+ *
2134
+ * @param document The OpenAPI document to build the SDK manifest from.
2135
+ * @param operationTypeRefs A map of operation type references.
2136
+ * @param options Naming strategy options for the SDK manifest.
2137
+ * @returns The generated SDK manifest.
2138
+ */
2110
2139
  buildSdkManifest(document, operationTypeRefs, options = {}) {
2111
2140
  const sdkGroupNamesBySignature = this.naming.deriveSdkGroupNamesBySignature(document, options.namespaceStrategy ?? "smart");
2112
2141
  const groups = /* @__PURE__ */ new Map();
2142
+ const securitySchemes = this.buildSecuritySchemes(document);
2143
+ const globalSecurity = this.buildSecurityRequirements(document.security);
2113
2144
  for (const [path, operations] of Object.entries(document.paths)) {
2114
2145
  const staticSignature = this.naming.getStaticPathSegments(path).join("/");
2115
2146
  const className = sdkGroupNamesBySignature.get(staticSignature) ?? "Resource";
@@ -2146,34 +2177,96 @@ var TypeScriptTypeBuilder = class {
2146
2177
  bodyRequired: operation.requestBody?.required ?? false,
2147
2178
  pathParams: this.naming.createSdkParameterManifest(operation.parameters, "path", path),
2148
2179
  queryParams: this.naming.createSdkParameterManifest(operation.parameters, "query", path),
2149
- headerParams: this.naming.createSdkParameterManifest(operation.parameters, "header", path)
2180
+ headerParams: this.naming.createSdkParameterManifest(operation.parameters, "header", path),
2181
+ security: this.buildSecurityRequirements(operation.security)
2150
2182
  });
2151
2183
  }
2152
2184
  groups.set(propertyName, group);
2153
2185
  }
2154
- return { groups: Array.from(groups.values()).map((group) => ({
2155
- ...group,
2156
- operations: this.naming.ensureUniqueSdkMethodNames(group.operations)
2157
- })).sort((left, right) => left.propertyName.localeCompare(right.propertyName)) };
2186
+ return {
2187
+ groups: Array.from(groups.values()).map((group) => ({
2188
+ ...group,
2189
+ operations: this.naming.ensureUniqueSdkMethodNames(group.operations)
2190
+ })).sort((left, right) => left.propertyName.localeCompare(right.propertyName)),
2191
+ securitySchemes,
2192
+ security: globalSecurity
2193
+ };
2158
2194
  }
2195
+ /**
2196
+ * Infers a shape node from a given example value, using the provided name hint for
2197
+ * type naming purposes.
2198
+ *
2199
+ * @param value The example value to infer the shape from.
2200
+ * @param nameHint A hint for naming the inferred type.
2201
+ * @returns The inferred shape node.
2202
+ */
2159
2203
  inferShapeFromExample(value, nameHint) {
2160
2204
  return this.shapes.inferShapeFromExample(value, nameHint);
2161
2205
  }
2206
+ /**
2207
+ * Sanitizes a given string to be used as a type name in TypeScript.
2208
+ *
2209
+ * @param value The string to sanitize.
2210
+ * @returns The sanitized type name.
2211
+ */
2162
2212
  sanitizeTypeName(value) {
2163
2213
  return this.naming.sanitizeTypeName(value);
2164
2214
  }
2215
+ /**
2216
+ * Registers a shape with a preferred name and returns the assigned type name, ensuring
2217
+ * that it is unique within the given context.
2218
+ *
2219
+ * @param shape The shape node to register.
2220
+ * @param preferredName The preferred name for the type.
2221
+ * @param context The generator context.
2222
+ * @param collisionSuffix The suffix to use in case of name collisions.
2223
+ * @returns The assigned type name.
2224
+ */
2165
2225
  registerNamedShape(shape, preferredName, context, collisionSuffix) {
2166
2226
  return this.shapes.registerNamedShape(shape, preferredName, context, collisionSuffix);
2167
2227
  }
2228
+ /**
2229
+ * Determines the top-level shape for a given shape and its semantic role, which can
2230
+ * be used for namespace grouping in the generated SDK.
2231
+ *
2232
+ * @param shape The shape node to evaluate.
2233
+ * @param role The semantic role of the shape.
2234
+ * @returns The top-level shape node for the given shape and role.
2235
+ */
2168
2236
  namespaceTopLevelShape(shape, role) {
2169
2237
  return this.shapes.namespaceTopLevelShape(shape, role);
2170
2238
  }
2239
+ /**
2240
+ * Registers the given object shape and returns the assigned type name.
2241
+ *
2242
+ * @param shape The object shape to register.
2243
+ * @param preferredName The preferred name for the type.
2244
+ * @param context The generator context.
2245
+ * @param collisionSuffix The suffix to use in case of name collisions.
2246
+ * @param emitAlias Whether to emit a type alias.
2247
+ * @returns The assigned type name.
2248
+ */
2171
2249
  registerObjectShape(shape, preferredName, context, collisionSuffix, emitAlias = false) {
2172
2250
  return this.shapes.registerObjectShape(shape, preferredName, context, collisionSuffix, emitAlias);
2173
2251
  }
2252
+ /**
2253
+ * Determines the priority of an operation based on its characteristics, such as the
2254
+ * presence of a request body, which can be used for sorting operations when generating the SDK.
2255
+ *
2256
+ * @param operation The operation object to evaluate.
2257
+ * @returns The priority of the operation.
2258
+ */
2174
2259
  getOperationPriority(operation) {
2175
2260
  return Number(Boolean(operation.requestBody)) * 10;
2176
2261
  }
2262
+ /**
2263
+ * Resolves the description for a successful response from the given responses
2264
+ * object, preferring common success status codes and falling back to any available
2265
+ * description if necessary.
2266
+ *
2267
+ * @param responses The responses object to evaluate.
2268
+ * @returns The description of the successful response, or undefined if none is found.
2269
+ */
2177
2270
  resolveSuccessResponseDescription(responses) {
2178
2271
  for (const statusCode of [
2179
2272
  "200",
@@ -2189,6 +2282,85 @@ var TypeScriptTypeBuilder = class {
2189
2282
  if (description) return description;
2190
2283
  }
2191
2284
  }
2285
+ /**
2286
+ * Builds the security schemes for the entire API, based on the provided OpenAPI document.
2287
+ *
2288
+ * @param document The OpenAPI document to build the security schemes from.
2289
+ * @returns The security scheme manifest objects.
2290
+ */
2291
+ buildSecuritySchemes(document) {
2292
+ return Object.entries(document.components?.securitySchemes ?? {}).map(([name, scheme]) => this.createSecuritySchemeManifest(name, scheme)).filter((entry) => entry !== null).sort((left, right) => left.name.localeCompare(right.name));
2293
+ }
2294
+ /**
2295
+ * Builds the security requirements for an operation or the entire API, based on the
2296
+ * provided OpenAPI security requirement objects.
2297
+ *
2298
+ * @param name The name of the security requirement (used for logging or error messages).
2299
+ * @param scheme The OpenAPI security scheme object to create the manifest from.
2300
+ * @returns The security scheme manifest object, or null if the scheme type is not supported.
2301
+ */
2302
+ createSecuritySchemeManifest(name, scheme) {
2303
+ const helperName = this.createSecurityHelperName(name);
2304
+ if (scheme.type === "apiKey") return {
2305
+ name,
2306
+ helperName,
2307
+ description: scheme.description,
2308
+ type: "apiKey",
2309
+ authType: "apiKey",
2310
+ in: scheme.in,
2311
+ parameterName: scheme.name
2312
+ };
2313
+ if (scheme.type === "oauth2") return {
2314
+ name,
2315
+ helperName,
2316
+ description: scheme.description,
2317
+ type: "oauth2",
2318
+ authType: "oauth2",
2319
+ scopes: this.collectSecurityScopes(scheme)
2320
+ };
2321
+ if (scheme.type === "openIdConnect") return {
2322
+ name,
2323
+ helperName,
2324
+ description: scheme.description,
2325
+ type: "openIdConnect",
2326
+ authType: "oauth2",
2327
+ openIdConnectUrl: scheme.openIdConnectUrl
2328
+ };
2329
+ const normalizedScheme = scheme.scheme.toLowerCase();
2330
+ return {
2331
+ name,
2332
+ helperName,
2333
+ description: scheme.description,
2334
+ type: "http",
2335
+ authType: normalizedScheme === "basic" ? "basic" : "bearer",
2336
+ scheme: scheme.scheme,
2337
+ bearerFormat: scheme.bearerFormat
2338
+ };
2339
+ }
2340
+ /**
2341
+ * Builds the security requirements for an operation or the entire API, based on the
2342
+ * provided OpenAPI security requirement objects.
2343
+ *
2344
+ * @param requirements The OpenAPI security requirement objects to build the manifest from.
2345
+ * @returns The security requirement manifest objects, or undefined if none are provided.
2346
+ */
2347
+ buildSecurityRequirements(requirements) {
2348
+ if (!requirements || requirements.length === 0) return;
2349
+ const normalized = requirements.map((requirement) => ({ schemes: Object.entries(requirement).map(([name, scopes]) => ({
2350
+ name,
2351
+ scopes: [...scopes].sort()
2352
+ })).sort((left, right) => left.name.localeCompare(right.name)) })).filter((requirement) => requirement.schemes.length > 0);
2353
+ return normalized.length > 0 ? normalized : void 0;
2354
+ }
2355
+ collectSecurityScopes(scheme) {
2356
+ const scopes = /* @__PURE__ */ new Set();
2357
+ for (const flow of Object.values(scheme.flows ?? {})) for (const scope of Object.keys(flow.scopes ?? {})) scopes.add(scope);
2358
+ return scopes.size > 0 ? Array.from(scopes).sort() : void 0;
2359
+ }
2360
+ createSecurityHelperName(name) {
2361
+ const sanitized = this.naming.sanitizeTypeName(name);
2362
+ return sanitized.endsWith("Auth") ? `create${sanitized}` : `create${sanitized}Auth`;
2363
+ }
2192
2364
  };
2193
2365
 
2194
2366
  //#endregion
@@ -2375,7 +2547,7 @@ var SdkPackageGenerator = class {
2375
2547
  "package.json": this.renderPackageJson(options),
2376
2548
  "README.md": this.renderReadme(manifest, options, outputMode, signatureStyle),
2377
2549
  "src/Schema.ts": schemaModule,
2378
- "src/index.ts": this.renderIndexFile(classNames, outputMode, rootTypeName),
2550
+ "src/index.ts": this.renderIndexFile(classNames, outputMode, rootTypeName, manifest),
2379
2551
  "tsconfig.json": this.renderTsconfig(),
2380
2552
  "tsdown.config.ts": this.renderTsdownConfig(),
2381
2553
  "vitest.config.ts": this.renderVitestConfig(),
@@ -2625,7 +2797,7 @@ var SdkPackageGenerator = class {
2625
2797
  const title = `# ${packageName}`;
2626
2798
  const description = this.renderReadmeDescription(outputMode);
2627
2799
  const usage = this.renderReadmeUsage(manifest, packageName, outputMode, signatureStyle);
2628
- const exports = this.renderReadmeExports(outputMode);
2800
+ const exports = this.renderReadmeExports(outputMode, manifest);
2629
2801
  return [
2630
2802
  title,
2631
2803
  "",
@@ -2667,8 +2839,13 @@ var SdkPackageGenerator = class {
2667
2839
  const classSnippet = this.renderReadmeClientSnippet(packageName, "classes", signatureStyle, exampleOperation);
2668
2840
  if (outputMode === "classes") return classSnippet;
2669
2841
  const typeImports = exampleOperation ? this.collectReadmeTypeImports(exampleOperation.operation) : [];
2842
+ const valueImports = [
2843
+ "Core",
2844
+ "createClient",
2845
+ ...exampleOperation ? this.collectReadmeAuthHelperImports(exampleOperation) : []
2846
+ ];
2670
2847
  return [
2671
- typeImports.length > 0 ? `import { Core, createClient, type ${typeImports.join(", type ")} } from '${packageName}'` : `import { Core, createClient } from '${packageName}'`,
2848
+ typeImports.length > 0 ? `import { ${valueImports.join(", ")}, type ${typeImports.join(", type ")} } from '${packageName}'` : `import { ${valueImports.join(", ")} } from '${packageName}'`,
2672
2849
  "",
2673
2850
  ...this.renderReadmeClientBody("sdk", "classes", signatureStyle, exampleOperation),
2674
2851
  "",
@@ -2680,7 +2857,9 @@ var SdkPackageGenerator = class {
2680
2857
  renderReadmeClientSnippet(packageName, mode, signatureStyle, exampleOperation) {
2681
2858
  const importNames = mode === "runtime" ? ["createClient"] : ["Core"];
2682
2859
  const typeImports = exampleOperation ? this.collectReadmeTypeImports(exampleOperation.operation) : [];
2683
- const importLine = typeImports.length > 0 ? `import { ${importNames.join(", ")}, type ${typeImports.join(", type ")} } from '${packageName}'` : `import { ${importNames.join(", ")} } from '${packageName}'`;
2860
+ const helperImports = exampleOperation ? this.collectReadmeAuthHelperImports(exampleOperation) : [];
2861
+ const valueImports = [...importNames, ...helperImports];
2862
+ const importLine = typeImports.length > 0 ? `import { ${valueImports.join(", ")}, type ${typeImports.join(", type ")} } from '${packageName}'` : `import { ${valueImports.join(", ")} } from '${packageName}'`;
2684
2863
  const sdkVariable = mode === "runtime" ? "runtimeSdk" : "sdk";
2685
2864
  return [
2686
2865
  importLine,
@@ -2696,16 +2875,27 @@ var SdkPackageGenerator = class {
2696
2875
  " clientId: process.env.CLIENT_ID!,",
2697
2876
  " clientSecret: process.env.CLIENT_SECRET!,",
2698
2877
  " environment: 'sandbox',",
2878
+ ...exampleOperation ? this.renderReadmeAuthLines(exampleOperation.operation.security ?? exampleOperation.groupSecurity ?? exampleOperation.globalSecurity) : [],
2699
2879
  "})",
2700
2880
  ...callLines.length > 0 ? ["", ...callLines] : []
2701
2881
  ];
2702
2882
  }
2703
- renderReadmeExports(outputMode) {
2704
- if (outputMode === "runtime") return ["`createClient()` for a typed runtime SDK instance", "`Schema` exports for request, response, params, query, and header types"];
2705
- if (outputMode === "classes") return ["`Core` as the class-based SDK entrypoint", "generated API classes plus `Schema` type exports"];
2883
+ renderReadmeExports(outputMode, manifest) {
2884
+ const authLine = manifest.securitySchemes.length > 0 ? ["generated auth helpers derived from OpenAPI security schemes"] : [];
2885
+ if (outputMode === "runtime") return [
2886
+ "`createClient()` for a typed runtime SDK instance",
2887
+ ...authLine,
2888
+ "`Schema` exports for request, response, params, query, and header types"
2889
+ ];
2890
+ if (outputMode === "classes") return [
2891
+ "`Core` as the class-based SDK entrypoint",
2892
+ ...authLine,
2893
+ "generated API classes plus `Schema` type exports"
2894
+ ];
2706
2895
  return [
2707
2896
  "`Core` for class-based usage",
2708
2897
  "`createClient()` for runtime-first usage",
2898
+ ...authLine,
2709
2899
  "`Schema` exports for generated request, response, params, query, and header types"
2710
2900
  ];
2711
2901
  }
@@ -2715,9 +2905,33 @@ var SdkPackageGenerator = class {
2715
2905
  if (!group || !operation) return null;
2716
2906
  return {
2717
2907
  group,
2718
- operation
2908
+ operation,
2909
+ groupSecurity: void 0,
2910
+ globalSecurity: manifest.security
2719
2911
  };
2720
2912
  }
2913
+ renderReadmeAuthLines(security) {
2914
+ if (!security || security.length === 0) return [];
2915
+ const selectedRequirement = security[0];
2916
+ if (!selectedRequirement || selectedRequirement.schemes.length === 0) return [];
2917
+ const value = selectedRequirement.schemes.length === 1 ? this.renderReadmeAuthFactoryCall(selectedRequirement.schemes[0].name) : `[
2918
+ ${selectedRequirement.schemes.map((scheme) => this.renderReadmeAuthFactoryCall(scheme.name)).join(",\n ")}
2919
+ ]`;
2920
+ const lines = security.length > 1 ? [" // Choose a generated auth helper that matches your API access setup."] : [];
2921
+ lines.push(` auth: ${value},`);
2922
+ return lines;
2923
+ }
2924
+ renderReadmeAuthFactoryCall(schemeName) {
2925
+ const helperName = this.createSecurityHelperName(schemeName);
2926
+ const envName = this.toConstantCase(schemeName);
2927
+ if (/basic/i.test(schemeName)) return `${helperName}(process.env.${envName}_USERNAME!, process.env.${envName}_PASSWORD!)`;
2928
+ return `${helperName}(process.env.${envName}_VALUE!)`;
2929
+ }
2930
+ collectReadmeAuthHelperImports(exampleOperation) {
2931
+ const selectedRequirement = (exampleOperation.operation.security ?? exampleOperation.groupSecurity ?? exampleOperation.globalSecurity)?.[0];
2932
+ if (!selectedRequirement) return [];
2933
+ return selectedRequirement.schemes.map((scheme) => this.createSecurityHelperName(scheme.name));
2934
+ }
2721
2935
  collectReadmeTypeImports(operation) {
2722
2936
  const types = /* @__PURE__ */ new Set();
2723
2937
  if (operation.pathParams.length > 0) types.add(operation.paramsType);
@@ -2824,13 +3038,13 @@ var SdkPackageGenerator = class {
2824
3038
  "})"
2825
3039
  ].join("\n");
2826
3040
  }
2827
- renderIndexFile(classNames, outputMode, rootTypeName) {
3041
+ renderIndexFile(classNames, outputMode, rootTypeName, manifest) {
2828
3042
  const rootExportName = `${rootTypeName.charAt(0).toLowerCase()}${rootTypeName.slice(1)}`;
2829
3043
  const lines = [
2830
3044
  `import type { ${rootTypeName}Api } from './Schema'`,
2831
- `import { ${rootExportName}Sdk } from './Schema'`,
3045
+ `import { ${rootExportName}Manifest, ${rootExportName}Sdk } from './Schema'`,
2832
3046
  "import { createSdk as createBoundSdk } from '@oapiex/sdk-kit'",
2833
- "import type { BaseApi as KitBaseApi, Core as KitCore, InitOptions } from '@oapiex/sdk-kit'",
3047
+ "import type { AuthConfig, BaseApi as KitBaseApi, Core as KitCore, InitOptions } from '@oapiex/sdk-kit'",
2834
3048
  "",
2835
3049
  "export * from './Schema'"
2836
3050
  ];
@@ -2841,6 +3055,15 @@ var SdkPackageGenerator = class {
2841
3055
  lines.push("export { Core } from './Core'");
2842
3056
  }
2843
3057
  lines.push("");
3058
+ lines.push(`export const securitySchemes = ${rootExportName}Manifest.securitySchemes`);
3059
+ lines.push(`export const security = ${rootExportName}Manifest.security`);
3060
+ if (manifest.securitySchemes.length > 0) {
3061
+ lines.push("");
3062
+ for (const scheme of manifest.securitySchemes) {
3063
+ lines.push(...this.renderSecurityHelper(scheme));
3064
+ lines.push("");
3065
+ }
3066
+ }
2844
3067
  lines.push("export const createClient = (");
2845
3068
  lines.push(" options: InitOptions");
2846
3069
  lines.push(`): KitCore & { api: KitBaseApi & ${rootTypeName}Api } =>`);
@@ -2858,6 +3081,7 @@ var SdkPackageGenerator = class {
2858
3081
  lines.push("} from '@oapiex/sdk-kit'");
2859
3082
  lines.push("");
2860
3083
  lines.push("export type {");
3084
+ lines.push(" AuthConfig,");
2861
3085
  lines.push(" InitOptions,");
2862
3086
  lines.push(" UnifiedResponse,");
2863
3087
  lines.push(" XGenericObject,");
@@ -2869,6 +3093,47 @@ var SdkPackageGenerator = class {
2869
3093
  return !["Record", "Promise"].includes(identifier);
2870
3094
  })));
2871
3095
  }
3096
+ renderSecurityHelper(scheme) {
3097
+ if (scheme.authType === "basic") return [
3098
+ `export const ${scheme.helperName} = (username: string, password: string): AuthConfig => ({`,
3099
+ " type: 'basic',",
3100
+ " username,",
3101
+ " password,",
3102
+ "})"
3103
+ ];
3104
+ if (scheme.authType === "apiKey") return [
3105
+ `export const ${scheme.helperName} = (value: string): AuthConfig => ({`,
3106
+ " type: 'apiKey',",
3107
+ ` name: ${JSON.stringify(scheme.parameterName ?? scheme.name)},`,
3108
+ " value,",
3109
+ ` in: ${JSON.stringify(scheme.in ?? "header")},`,
3110
+ "})"
3111
+ ];
3112
+ if (scheme.authType === "oauth2") return [
3113
+ `export const ${scheme.helperName} = (accessToken: string, tokenType = 'Bearer'): AuthConfig => ({`,
3114
+ " type: 'oauth2',",
3115
+ " accessToken,",
3116
+ " tokenType,",
3117
+ "})"
3118
+ ];
3119
+ return [
3120
+ `export const ${scheme.helperName} = (token: string): AuthConfig => ({`,
3121
+ " type: 'bearer',",
3122
+ " token,",
3123
+ ...scheme.scheme && scheme.scheme.toLowerCase() !== "bearer" ? [` prefix: ${JSON.stringify(this.normalizeHttpAuthPrefix(scheme.scheme))},`] : [],
3124
+ "})"
3125
+ ];
3126
+ }
3127
+ createSecurityHelperName(schemeName) {
3128
+ const sanitized = this.typeBuilder.sanitizeTypeName(schemeName);
3129
+ return sanitized.endsWith("Auth") ? `create${sanitized}` : `create${sanitized}Auth`;
3130
+ }
3131
+ normalizeHttpAuthPrefix(scheme) {
3132
+ return scheme.charAt(0).toUpperCase() + scheme.slice(1);
3133
+ }
3134
+ toConstantCase(value) {
3135
+ return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase() || "AUTH";
3136
+ }
2872
3137
  };
2873
3138
 
2874
3139
  //#endregion
package/dist/index.d.ts CHANGED
@@ -117,10 +117,37 @@ interface OpenApiResponse {
117
117
  description: string;
118
118
  content?: Record<string, OpenApiMediaType>;
119
119
  }
120
+ interface OpenApiOauthFlowLike {
121
+ authorizationUrl?: string;
122
+ tokenUrl?: string;
123
+ refreshUrl?: string;
124
+ scopes?: Record<string, string>;
125
+ }
126
+ type OpenApiSecurityRequirementLike = Record<string, string[]>;
127
+ type OpenApiSecuritySchemeLike = {
128
+ type: 'http';
129
+ description?: string;
130
+ scheme: string;
131
+ bearerFormat?: string;
132
+ } | {
133
+ type: 'apiKey';
134
+ description?: string;
135
+ name: string;
136
+ in: 'query' | 'header' | 'cookie';
137
+ } | {
138
+ type: 'oauth2';
139
+ description?: string;
140
+ flows?: Record<string, OpenApiOauthFlowLike>;
141
+ } | {
142
+ type: 'openIdConnect';
143
+ description?: string;
144
+ openIdConnectUrl: string;
145
+ };
120
146
  interface OpenApiOperationLike {
121
147
  summary?: string;
122
148
  description?: string;
123
149
  operationId?: string;
150
+ security?: OpenApiSecurityRequirementLike[];
124
151
  parameters?: OpenApiParameterLike[];
125
152
  requestBody?: {
126
153
  description?: string;
@@ -135,6 +162,10 @@ interface OpenApiDocumentLike {
135
162
  title: string;
136
163
  version: string;
137
164
  };
165
+ components?: {
166
+ securitySchemes?: Record<string, OpenApiSecuritySchemeLike>;
167
+ };
168
+ security?: OpenApiSecurityRequirementLike[];
138
169
  paths: Record<string, Record<string, OpenApiOperationLike>>;
139
170
  }
140
171
  //#endregion
@@ -391,6 +422,26 @@ interface SdkParameterManifest {
391
422
  required: boolean;
392
423
  description?: string;
393
424
  }
425
+ interface SdkSecurityRequirementSchemeManifest {
426
+ name: string;
427
+ scopes: string[];
428
+ }
429
+ interface SdkSecurityRequirementManifest {
430
+ schemes: SdkSecurityRequirementSchemeManifest[];
431
+ }
432
+ interface SdkSecuritySchemeManifest {
433
+ name: string;
434
+ helperName: string;
435
+ description?: string;
436
+ type: 'http' | 'apiKey' | 'oauth2' | 'openIdConnect';
437
+ authType: 'bearer' | 'basic' | 'apiKey' | 'oauth2';
438
+ scheme?: string;
439
+ bearerFormat?: string;
440
+ in?: 'header' | 'query' | 'cookie';
441
+ parameterName?: string;
442
+ openIdConnectUrl?: string;
443
+ scopes?: string[];
444
+ }
394
445
  interface SdkOperationManifest {
395
446
  path: string;
396
447
  method: string;
@@ -410,6 +461,7 @@ interface SdkOperationManifest {
410
461
  pathParams: SdkParameterManifest[];
411
462
  queryParams: SdkParameterManifest[];
412
463
  headerParams: SdkParameterManifest[];
464
+ security?: SdkSecurityRequirementManifest[];
413
465
  }
414
466
  interface SdkGroupManifest {
415
467
  className: string;
@@ -418,6 +470,8 @@ interface SdkGroupManifest {
418
470
  }
419
471
  interface SdkManifest {
420
472
  groups: SdkGroupManifest[];
473
+ securitySchemes: SdkSecuritySchemeManifest[];
474
+ security?: SdkSecurityRequirementManifest[];
421
475
  }
422
476
  interface PayloadSchemaCandidate {
423
477
  schema?: OpenApiSchema;
@@ -500,6 +554,9 @@ declare class SdkPackageGenerator {
500
554
  private renderReadmeClientBody;
501
555
  private renderReadmeExports;
502
556
  private pickExampleOperation;
557
+ private renderReadmeAuthLines;
558
+ private renderReadmeAuthFactoryCall;
559
+ private collectReadmeAuthHelperImports;
503
560
  private collectReadmeTypeImports;
504
561
  private renderReadmeOperationCall;
505
562
  private renderReadmeGroupedArgs;
@@ -510,6 +567,10 @@ declare class SdkPackageGenerator {
510
567
  private renderExportsTest;
511
568
  private renderIndexFile;
512
569
  private collectTypeIdentifiers;
570
+ private renderSecurityHelper;
571
+ private createSecurityHelperName;
572
+ private normalizeHttpAuthPrefix;
573
+ private toConstantCase;
513
574
  }
514
575
  //#endregion
515
576
  //#region src/generator/TypeScriptGenerator.d.ts
@@ -623,4 +684,4 @@ interface ReadmeCrawledOperation extends ReadmeOperation {
623
684
  }
624
685
  declare const resolveReadmeSidebarUrls: (operation: Pick<ReadmeOperation, "sidebarLinks">, baseUrl: string) => string[];
625
686
  //#endregion
626
- export { Application, AttributeQueryNode, AttributedNode, BrowserName, Declaration, GenerateCommand, GeneratorContext, InitCommand, InterfaceAliasDeclaration, InterfaceDeclaration, JsonLike, JsonRepair, OpenApiDocumentLike, OpenApiMediaType, OpenApiOperationLike, OpenApiParameterLike, OpenApiResponse, OpenApiSchema, OpenApiTransformer, OperationTypeRefs, OutputGenerator, ParseCommand, PayloadSchemaCandidate, QueryableNode, ReadmeCodeSnippet, ReadmeCrawledOperation, ReadmeNormalizedRequestExample, ReadmeOperation, ReadmeParameter, ReadmeResponseBody, ReadmeResponseSchema, ReadmeSidebarLink, SdkGroupManifest, SdkManifest, SdkMethodNamingStrategy, SdkNamespaceNamingStrategy, SdkNamingStrategyOptions, SdkOperationManifest, SdkPackageGenerator, SdkPackageGeneratorOptions, SdkParameterManifest, SemanticModel, ShapeAliasDeclaration, ShapeNode, ShapeProperty, TextNodeLike, TypeReferenceAliasDeclaration, TypeScriptGenerator, UserConfig, browser, buildOperationUrl, defaultConfig, defineConfig, endBrowserSession, escapeSelector, extractBalancedSegment, extractButtonText, extractCodeMirrorText, extractCodeSnippets, extractFetchBody, extractFetchHeaders, extractObjectPropertyValue, extractOperationDescription, extractOperationParametersFromOpenApi, extractParameterDescription, extractReadmeOperationFromHtml, extractReadmeOperationFromSsrProps, extractRequestCodeSnippets, extractRequestParams, extractRequestParamsFromOpenApi, extractRequestSnippetLabel, extractResponseBodies, extractResponseBodiesFromOpenApi, extractResponseContentTypes, extractResponseLabels, extractResponseSchemas, extractResponseSchemasFromOpenApi, extractSidebarLinkLabel, extractSidebarLinks, extractStablePageHtml, extractStringLiteralValue, findParameterRoot, flattenOpenApiSchemaProperties, getBrowserSession, globalConfig, inferParameterLocation, inferParameterLocationFromText, inferParameterPath, inferParameterType, isRecord, isRequiredParameter, isSupportedBrowser, loadUserConfig, mergeReadmeOperations, mergeSsrPropsIntoRenderedHtml, normalizeCurlSnippet, normalizeFetchSnippet, normalizeRequestCodeSnippet, normalizeResponseBody, normalizeStructuredRequestBody, parseLooseStructuredValue, readInputValue, readText, readTexts, resolveConfig, resolveOpenApiMediaExample, resolveParameterInput, resolveReadmeSidebarUrls, resolveSsrOperation, startBrowserSession, supportedBrowsers, transformer };
687
+ export { Application, AttributeQueryNode, AttributedNode, BrowserName, Declaration, GenerateCommand, GeneratorContext, InitCommand, InterfaceAliasDeclaration, InterfaceDeclaration, JsonLike, JsonRepair, OpenApiDocumentLike, OpenApiMediaType, OpenApiOauthFlowLike, OpenApiOperationLike, OpenApiParameterLike, OpenApiResponse, OpenApiSchema, OpenApiSecurityRequirementLike, OpenApiSecuritySchemeLike, OpenApiTransformer, OperationTypeRefs, OutputGenerator, ParseCommand, PayloadSchemaCandidate, QueryableNode, ReadmeCodeSnippet, ReadmeCrawledOperation, ReadmeNormalizedRequestExample, ReadmeOperation, ReadmeParameter, ReadmeResponseBody, ReadmeResponseSchema, ReadmeSidebarLink, SdkGroupManifest, SdkManifest, SdkMethodNamingStrategy, SdkNamespaceNamingStrategy, SdkNamingStrategyOptions, SdkOperationManifest, SdkPackageGenerator, SdkPackageGeneratorOptions, SdkParameterManifest, SdkSecurityRequirementManifest, SdkSecurityRequirementSchemeManifest, SdkSecuritySchemeManifest, SemanticModel, ShapeAliasDeclaration, ShapeNode, ShapeProperty, TextNodeLike, TypeReferenceAliasDeclaration, TypeScriptGenerator, UserConfig, browser, buildOperationUrl, defaultConfig, defineConfig, endBrowserSession, escapeSelector, extractBalancedSegment, extractButtonText, extractCodeMirrorText, extractCodeSnippets, extractFetchBody, extractFetchHeaders, extractObjectPropertyValue, extractOperationDescription, extractOperationParametersFromOpenApi, extractParameterDescription, extractReadmeOperationFromHtml, extractReadmeOperationFromSsrProps, extractRequestCodeSnippets, extractRequestParams, extractRequestParamsFromOpenApi, extractRequestSnippetLabel, extractResponseBodies, extractResponseBodiesFromOpenApi, extractResponseContentTypes, extractResponseLabels, extractResponseSchemas, extractResponseSchemasFromOpenApi, extractSidebarLinkLabel, extractSidebarLinks, extractStablePageHtml, extractStringLiteralValue, findParameterRoot, flattenOpenApiSchemaProperties, getBrowserSession, globalConfig, inferParameterLocation, inferParameterLocationFromText, inferParameterPath, inferParameterType, isRecord, isRequiredParameter, isSupportedBrowser, loadUserConfig, mergeReadmeOperations, mergeSsrPropsIntoRenderedHtml, normalizeCurlSnippet, normalizeFetchSnippet, normalizeRequestCodeSnippet, normalizeResponseBody, normalizeStructuredRequestBody, parseLooseStructuredValue, readInputValue, readText, readTexts, resolveConfig, resolveOpenApiMediaExample, resolveParameterInput, resolveReadmeSidebarUrls, resolveSsrOperation, startBrowserSession, supportedBrowsers, transformer };