Release v3.8.30 (#4267)

Release v3.8.30 — see CHANGELOG.md [3.8.30] for the full release notes.
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-06-20 07:09:43 -03:00
committed by GitHub
parent ab8096071c
commit db362b0126
356 changed files with 14268 additions and 1140 deletions

View File

@@ -18,6 +18,99 @@ const OPENAPI_SPEC_CANDIDATES = [
path.join(/* turbopackIgnore: true */ process.cwd(), "app", "docs", "openapi.yaml"),
];
/**
* Generate example value from OpenAPI schema.
*
* Exported for unit testing: the dashboard "Try It" panel pre-fills request
* bodies from this. Bounded to depth 3 to prevent infinite recursion on
* self-referential `$ref` schemas.
*/
export function generateExampleFromSchema(
schema: any,
components: any,
depth = 0,
propertyName = ""
): any {
if (!schema || depth > 3) return null; // Prevent infinite recursion
// Use example if provided
if (schema.example !== undefined) return schema.example;
if (schema.default !== undefined) return schema.default;
if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0) {
return generateExampleFromSchema(schema.oneOf[0], components, depth + 1, propertyName);
}
if (Array.isArray(schema.anyOf) && schema.anyOf.length > 0) {
return generateExampleFromSchema(schema.anyOf[0], components, depth + 1, propertyName);
}
if (Array.isArray(schema.allOf) && schema.allOf.length > 0) {
return schema.allOf.reduce((acc: any, item: any) => {
const value = generateExampleFromSchema(item, components, depth + 1, propertyName);
return value && typeof value === "object" && !Array.isArray(value)
? { ...acc, ...value }
: acc;
}, {});
}
// Handle $ref
if (schema.$ref) {
const refPath = schema.$ref.replace("#/components/schemas/", "");
return generateExampleFromSchema(components[refPath], components, depth + 1, propertyName);
}
// Handle type
switch (schema.type) {
case "string":
if (schema.enum) return schema.enum[0];
if (schema.format === "date-time") return "2024-01-01T00:00:00Z";
if (schema.format === "email") return "user@example.com";
if (schema.format === "uri") return "https://example.com";
if (/model/i.test(propertyName)) return "openai/gpt-4o";
if (/prompt/i.test(propertyName)) return "Write a function to sort an array";
if (/system/i.test(propertyName)) return "You are a concise, helpful assistant.";
if (/query/i.test(propertyName)) return "What is the capital of France?";
if (/input|text|content/i.test(propertyName)) return "Sample text";
if (/provider/i.test(propertyName)) return "openai";
if (/url/i.test(propertyName)) return "https://example.com";
return "string";
case "number":
case "integer":
return schema.default !== undefined ? schema.default : schema.minimum || 0;
case "boolean":
return schema.default !== undefined ? schema.default : false;
case "array":
if (schema.items) {
const item = generateExampleFromSchema(schema.items, components, depth + 1, propertyName);
return item ? [item] : [];
}
return [];
case "object":
const obj: any = {};
if (schema.properties) {
const required = schema.required || [];
// Include required fields + first 3 optional fields
const propsToInclude = [
...required,
...Object.keys(schema.properties)
.filter((k) => !required.includes(k))
.slice(0, 3),
];
for (const key of propsToInclude) {
const propSchema = schema.properties[key];
obj[key] = generateExampleFromSchema(propSchema, components, depth + 1, key);
}
}
return obj;
default:
return null;
}
}
export async function GET() {
try {
let specPath = "";
@@ -58,6 +151,18 @@ export async function GET() {
if (!methods || typeof methods !== "object") continue;
for (const [method, spec] of Object.entries(methods as Record<string, any>)) {
if (["get", "post", "put", "patch", "delete"].includes(method) && spec) {
// Extract example from request body schema if available
let exampleBody: any = null;
const jsonBody = spec.requestBody?.content?.["application/json"];
if (jsonBody?.example !== undefined) {
exampleBody = jsonBody.example;
} else if (jsonBody?.examples && typeof jsonBody.examples === "object") {
const firstExample = Object.values(jsonBody.examples)[0] as any;
exampleBody = firstExample?.value ?? firstExample;
} else if (jsonBody?.schema) {
exampleBody = generateExampleFromSchema(jsonBody.schema, raw.components?.schemas || {});
}
catalog.endpoints.push({
method: method.toUpperCase(),
path: pathStr,
@@ -67,6 +172,7 @@ export async function GET() {
security: spec.security ? true : false,
parameters: spec.parameters || [],
requestBody: spec.requestBody ? true : false,
exampleBody,
responses: Object.keys(spec.responses || {}),
loopbackOnly: spec["x-loopback-only"] === true,
alwaysProtected: spec["x-always-protected"] === true,