diff --git a/packages/www/src/docs/components/OpenApiReference.astro b/packages/www/src/docs/components/OpenApiReference.astro new file mode 100644 index 00000000000..e2d658f8a86 --- /dev/null +++ b/packages/www/src/docs/components/OpenApiReference.astro @@ -0,0 +1,151 @@ +--- +import openapi from "../../../openapi.json" +import type { OpenApiOperation, OpenApiSchema } from "../lib/openapi" +import { openApiSchemaLabel } from "../lib/openapi" +import OpenApiSchemaView from "./OpenApiSchema.astro" + +const methods = ["get", "post", "put", "patch", "delete", "options", "head"] as const +type Method = (typeof methods)[number] + +const paths = openapi.paths as unknown as Record>> +const operations = Object.entries(paths).flatMap(([path, item]) => + methods.flatMap((method) => { + const operation = item[method] + if (!operation) return [] + return [{ ...operation, path, method, id: operation.operationId ?? `${method}-${path}`.replace(/[^a-z0-9]+/gi, "-") }] + }), +) +const groups = [...new Set(operations.map((operation) => operation.tags?.[0] ?? "other"))].map((tag) => ({ + tag, + id: `tag-${tag.replace(/[^a-z0-9]+/gi, "-").toLowerCase()}`, + description: openapi.tags.find((item) => item.name === tag)?.description, + operations: operations.filter((operation) => (operation.tags?.[0] ?? "other") === tag), +})) +const schemas = Object.entries(openapi.components.schemas) as [string, OpenApiSchema][] +--- + +
+ + +
+
+

OpenAPI {openapi.openapi}

+

HTTP API

+

{openapi.info.description}

+
+ {operations.length} operations + {schemas.length} schemas + OpenAPI JSON +
+
+ + { + groups.map((group) => ( +
+
+

Resource

+

{group.tag}

+ {group.description &&

{group.description}

} +
+
+ {group.operations.map((operation) => ( +
+ + {operation.method} + {operation.path} + {operation.summary} + +
+ {operation.description &&

{operation.description}

} +

Operation ID{operation.operationId}

+ {!!operation.parameters?.length && ( +
+

Parameters

+
+ + + + {operation.parameters.map((parameter) => ( + + + + + + + ))} + +
NameLocationTypeDescription
{parameter.name}{parameter.required && required}{parameter.in}{parameter.description ?? No description}
+
+
+ )} + {operation.requestBody && ( +
+

Request body {operation.requestBody.required && required}

+ {operation.requestBody.description &&

{operation.requestBody.description}

} +
+ {Object.entries(operation.requestBody.content ?? {}).map(([mediaType, content]) => ( +
{mediaType}
+ ))} +
+
+ )} +
+

Responses

+
+ {Object.entries(operation.responses ?? {}).map(([status, response]) => ( +
+
+ {status} + {response.description ?? "Response"} +
+ {Object.entries(response.content ?? {}).map(([mediaType, content]) => ( +
{mediaType}
+ ))} +
+ ))} +
+
+
+
+ ))} +
+
+ )) + } + +
+
+

Components

+

Schemas

+

Reusable data types referenced by API operations.

+
+
+ { + schemas.map(([name, schema]) => ( +
+ {name}{openApiSchemaLabel(schema)} +
+
+ )) + } +
+
+
+
diff --git a/packages/www/src/docs/components/OpenApiSchema.astro b/packages/www/src/docs/components/OpenApiSchema.astro new file mode 100644 index 00000000000..ae4d63f03aa --- /dev/null +++ b/packages/www/src/docs/components/OpenApiSchema.astro @@ -0,0 +1,69 @@ +--- +import { formatOpenApiValue, openApiSchemaLabel, type OpenApiSchema } from "../lib/openapi" + +interface Props { + schema?: OpenApiSchema + required?: boolean +} + +const schema = Astro.props.schema +const reference = schema?.$ref?.split("/").at(-1) +const variants = schema?.anyOf ?? schema?.oneOf ?? schema?.allOf +const variantOperator = schema?.allOf ? "and" : "or" +const constraints = schema + ? [ + schema.pattern && `pattern ${schema.pattern}`, + schema.minimum !== undefined && `min ${schema.minimum}`, + schema.maximum !== undefined && `max ${schema.maximum}`, + schema.exclusiveMinimum !== undefined && `> ${schema.exclusiveMinimum}`, + schema.exclusiveMaximum !== undefined && `< ${schema.exclusiveMaximum}`, + schema.minLength !== undefined && `min length ${schema.minLength}`, + schema.maxLength !== undefined && `max length ${schema.maxLength}`, + schema.minItems !== undefined && `min items ${schema.minItems}`, + schema.maxItems !== undefined && `max items ${schema.maxItems}`, + ].filter((value): value is string => typeof value === "string") + : [] +--- + +{ + reference ? ( + {reference} + ) : ( +
+
+ {openApiSchemaLabel(schema)} + {Astro.props.required && required} + {schema?.deprecated && deprecated} +
+ {schema?.description &&

{schema.description}

} + {schema?.enum &&
Values{schema.enum.map(formatOpenApiValue).join(" | ")}
} + {schema?.const !== undefined &&
Constant{formatOpenApiValue(schema.const)}
} + {schema?.default !== undefined &&
Default{formatOpenApiValue(schema.default)}
} + {constraints.length > 0 &&
{constraints.join(", ")}
} + {variants && ( +
+ {variants.map((variant, index) => ( +
+ {index > 0 && {variantOperator}} + +
+ ))} +
+ )} + {schema?.type === "array" && schema.items &&
Items
} + {schema?.properties && ( +
+ {Object.entries(schema.properties).map(([name, property]) => ( +
+ {name} + +
+ ))} +
+ )} + {typeof schema?.additionalProperties === "object" && ( +
Additional properties
+ )} +
+ ) +} diff --git a/packages/www/src/docs/layouts/DocsLayout.astro b/packages/www/src/docs/layouts/DocsLayout.astro index 68fca7b5c31..a7e6a047ae9 100644 --- a/packages/www/src/docs/layouts/DocsLayout.astro +++ b/packages/www/src/docs/layouts/DocsLayout.astro @@ -13,9 +13,11 @@ interface Props { currentSlug: string headings: MarkdownHeading[] showTableOfContents?: boolean + fullWidth?: boolean } const section = getDocsSection(Astro.props.currentSlug) +const fullWidth = Astro.props.fullWidth ?? false const description = Astro.props.description ?? `${Astro.props.title} documentation for OpenCode.` const canonical = new URL(Astro.url.pathname, "https://opencode.ai").href --- @@ -35,24 +37,34 @@ const canonical = new URL(Astro.url.pathname, "https://opencode.ai").href -
- {section.title} navigation - -
-
- -
-
-

{Astro.props.title}

+ { + fullWidth ? ( +
-
-
- -
+ + ) : ( + <> +
+ {section.title} navigation + +
+
+ +
+
+

{Astro.props.title}

+ +
+
+ +
+ + ) + }