- {result.type === "page" ? (
-
- ) : (
-
- )}
+ {getResultIcon(result)}
{result.type === "heading" ? (
<>
- {result.content}
+ {stripMethod(result.content)}
-
@@ -136,7 +135,7 @@ export function Search() {
>
) : (
- {result.content}
+ {stripMethod(result.content)}
)}
@@ -151,6 +150,40 @@ export function Search() {
);
}
+function deduplicateByUrl(results: SortedResult[]): SortedResult[] {
+ const seen = new Set
();
+ return results.filter((r) => {
+ const base = r.url.split("#")[0];
+ if (seen.has(base)) return false;
+ seen.add(base);
+ return true;
+ });
+}
+
+const API_METHODS = new Set(["GET", "POST", "PUT", "DELETE", "PATCH"]);
+
+function extractMethod(content: string): string | null {
+ const first = content.split(" ")[0];
+ return API_METHODS.has(first) ? first : null;
+}
+
+function stripMethod(content: string): string {
+ const first = content.split(" ")[0];
+ return API_METHODS.has(first) ? content.slice(first.length + 1) : content;
+}
+
+function getResultIcon(result: SortedResult): React.ReactNode {
+ if (!result.url.startsWith("/apis/")) {
+ return result.type === "page" ? (
+
+ ) : (
+
+ );
+ }
+ const method = extractMethod(result.content);
+ return method ? : null;
+}
+
function getPageTitle(url: string): string {
const path = url.split("#")[0];
const segments = path.split("/").filter(Boolean);
diff --git a/packages/chronicle/src/lib/api-routes.ts b/packages/chronicle/src/lib/api-routes.ts
new file mode 100644
index 00000000..18108161
--- /dev/null
+++ b/packages/chronicle/src/lib/api-routes.ts
@@ -0,0 +1,120 @@
+import type { OpenAPIV3 } from 'openapi-types'
+import slugify from 'slugify'
+import type { PageTree, PageTreeItem } from '../types/content'
+import type { ApiSpec } from './openapi'
+
+export function getSpecSlug(spec: ApiSpec): string {
+ return slugify(spec.name, { lower: true, strict: true })
+}
+
+
+export function buildApiRoutes(specs: ApiSpec[]): { slug: string[] }[] {
+ const routes: { slug: string[] }[] = []
+
+ for (const spec of specs) {
+ const specSlug = getSpecSlug(spec)
+ const paths = spec.document.paths ?? {}
+
+ for (const [, pathItem] of Object.entries(paths)) {
+ if (!pathItem) continue
+ for (const method of ['get', 'post', 'put', 'delete', 'patch'] as const) {
+ const op = pathItem[method]
+ if (!op?.operationId) continue
+ routes.push({ slug: [specSlug, encodeURIComponent(op.operationId)] })
+ }
+ }
+ }
+
+ return routes
+}
+
+export interface ApiRouteMatch {
+ spec: ApiSpec
+ operation: OpenAPIV3.OperationObject
+ method: string
+ path: string
+}
+
+export function findApiOperation(specs: ApiSpec[], slug: string[]): ApiRouteMatch | null {
+ if (slug.length !== 2) return null
+ const [specSlug, operationId] = slug
+
+ const spec = specs.find((s) => getSpecSlug(s) === specSlug)
+ if (!spec) return null
+
+ const paths = spec.document.paths ?? {}
+ for (const [pathStr, pathItem] of Object.entries(paths)) {
+ if (!pathItem) continue
+ for (const method of ['get', 'post', 'put', 'delete', 'patch'] as const) {
+ const op = pathItem[method]
+ if (op?.operationId && encodeURIComponent(op.operationId) === operationId) {
+ return { spec, operation: op, method: method.toUpperCase(), path: pathStr }
+ }
+ }
+ }
+
+ return null
+}
+
+export function buildApiPageTree(specs: ApiSpec[]): PageTree {
+ const children: PageTreeItem[] = []
+
+ for (const spec of specs) {
+ const specSlug = getSpecSlug(spec)
+ const paths = spec.document.paths ?? {}
+ const tags = spec.document.tags ?? []
+
+ // Group operations by tag (case-insensitive to avoid duplicates)
+ const opsByTag = new Map()
+ const tagDisplayName = new Map()
+
+ for (const [, pathItem] of Object.entries(paths)) {
+ if (!pathItem) continue
+ for (const method of ['get', 'post', 'put', 'delete', 'patch'] as const) {
+ const op = pathItem[method]
+ if (!op?.operationId) continue
+
+ const rawTag = op.tags?.[0] ?? 'default'
+ const tagKey = rawTag.toLowerCase()
+ if (!opsByTag.has(tagKey)) {
+ opsByTag.set(tagKey, [])
+ tagDisplayName.set(tagKey, rawTag.charAt(0).toUpperCase() + rawTag.slice(1))
+ }
+
+ opsByTag.get(tagKey)!.push({
+ type: 'page',
+ name: op.summary ?? op.operationId,
+ url: `/apis/${specSlug}/${encodeURIComponent(op.operationId)}`,
+ icon: `method-${method}`,
+ })
+ }
+ }
+
+ // Use doc.tags display names where available
+ for (const t of tags) {
+ const key = t.name.toLowerCase()
+ if (opsByTag.has(key)) {
+ tagDisplayName.set(key, t.name.charAt(0).toUpperCase() + t.name.slice(1))
+ }
+ }
+
+ const tagFolders: PageTreeItem[] = Array.from(opsByTag.entries()).map(([key, ops]) => ({
+ type: 'folder' as const,
+ name: tagDisplayName.get(key) ?? key,
+ icon: 'rectangle-stack',
+ children: ops,
+ }))
+
+ if (specs.length > 1) {
+ children.push({
+ type: 'folder',
+ name: spec.name,
+ children: tagFolders,
+ })
+ } else {
+ children.push(...tagFolders)
+ }
+ }
+
+ return { name: 'API Reference', children }
+}
diff --git a/packages/chronicle/src/lib/config.ts b/packages/chronicle/src/lib/config.ts
index 63de7404..96c9f7b4 100644
--- a/packages/chronicle/src/lib/config.ts
+++ b/packages/chronicle/src/lib/config.ts
@@ -31,5 +31,6 @@ export function loadConfig(): ChronicleConfig {
},
search: { ...defaultConfig.search, ...userConfig.search },
footer: userConfig.footer,
+ api: userConfig.api,
}
}
\ No newline at end of file
diff --git a/packages/chronicle/src/lib/openapi.ts b/packages/chronicle/src/lib/openapi.ts
new file mode 100644
index 00000000..6767fc73
--- /dev/null
+++ b/packages/chronicle/src/lib/openapi.ts
@@ -0,0 +1,188 @@
+import fs from 'fs'
+import path from 'path'
+import { parse as parseYaml } from 'yaml'
+import type { OpenAPIV2, OpenAPIV3 } from 'openapi-types'
+import type { ApiConfig, ApiServerConfig, ApiAuthConfig } from '../types/config'
+
+type JsonObject = Record
+
+export interface ApiSpec {
+ name: string
+ basePath: string
+ server: ApiServerConfig
+ auth?: ApiAuthConfig
+ document: OpenAPIV3.Document
+}
+
+export type { SchemaField } from './schema'
+export { flattenSchema } from './schema'
+
+export function loadApiSpecs(apiConfigs: ApiConfig[]): ApiSpec[] {
+ const contentDir = process.env.CHRONICLE_CONTENT_DIR ?? process.cwd()
+ return apiConfigs.map((config) => loadApiSpec(config, contentDir))
+}
+
+export function loadApiSpec(config: ApiConfig, contentDir: string): ApiSpec {
+ const specPath = path.resolve(contentDir, config.spec)
+ const raw = fs.readFileSync(specPath, 'utf-8')
+ const isYaml = specPath.endsWith('.yaml') || specPath.endsWith('.yml')
+ const doc = (isYaml ? parseYaml(raw) : JSON.parse(raw)) as OpenAPIV2.Document | OpenAPIV3.Document
+
+ let v3Doc: OpenAPIV3.Document
+
+ if ('swagger' in doc && doc.swagger === '2.0') {
+ v3Doc = convertV2toV3(doc as OpenAPIV2.Document)
+ } else if ('openapi' in doc && doc.openapi.startsWith('3.')) {
+ v3Doc = resolveDocument(doc as OpenAPIV3.Document)
+ } else {
+ throw new Error(`Unsupported spec version in ${config.spec}`)
+ }
+
+ return {
+ name: config.name,
+ basePath: config.basePath,
+ server: config.server,
+ auth: config.auth,
+ document: v3Doc,
+ }
+}
+
+// --- $ref resolution ---
+
+function resolveRef(ref: string, root: JsonObject): JsonObject {
+ const parts = ref.replace(/^#\//, '').split('/')
+ let current: unknown = root
+ for (const part of parts) {
+ if (current && typeof current === 'object' && !Array.isArray(current)) {
+ current = (current as JsonObject)[part]
+ } else {
+ throw new Error(`Cannot resolve $ref: ${ref}`)
+ }
+ }
+ return current as JsonObject
+}
+
+function deepResolveRefs(
+ obj: unknown,
+ root: JsonObject,
+ stack = new Set(),
+ cache = new Map(),
+): unknown {
+ if (obj === null || obj === undefined || typeof obj !== 'object') return obj
+
+ if (Array.isArray(obj)) {
+ return obj.map((item) => deepResolveRefs(item, root, stack, cache))
+ }
+
+ const record = obj as JsonObject
+
+ if (typeof record.$ref === 'string') {
+ const ref = record.$ref
+ if (cache.has(ref)) return cache.get(ref) as JsonObject
+ if (stack.has(ref)) return { type: 'object', description: '[circular]' }
+ stack.add(ref)
+ const resolved = deepResolveRefs(resolveRef(ref, root), root, stack, cache) as JsonObject
+ stack.delete(ref)
+ cache.set(ref, resolved)
+ return resolved
+ }
+
+ const result: JsonObject = {}
+ for (const [key, value] of Object.entries(record)) {
+ result[key] = deepResolveRefs(value, root, stack, cache)
+ }
+ return result
+}
+
+function resolveDocument(doc: OpenAPIV3.Document): OpenAPIV3.Document {
+ const root = doc as unknown as JsonObject
+ return deepResolveRefs(doc, root) as unknown as OpenAPIV3.Document
+}
+
+// --- V2 → V3 conversion ---
+
+function convertV2toV3(doc: OpenAPIV2.Document): OpenAPIV3.Document {
+ const root = doc as unknown as JsonObject
+ const resolved = deepResolveRefs(doc, root) as unknown as OpenAPIV2.Document
+
+ const v3Paths: OpenAPIV3.PathsObject = {}
+
+ for (const [pathStr, pathItem] of Object.entries(resolved.paths ?? {})) {
+ if (!pathItem) continue
+ const v3PathItem: OpenAPIV3.PathItemObject = {}
+
+ for (const method of ['get', 'post', 'put', 'delete', 'patch'] as const) {
+ const op = (pathItem as Record)[method] as OpenAPIV2.OperationObject | undefined
+ if (!op) continue
+ v3PathItem[method] = convertV2Operation(op)
+ }
+
+ v3Paths[pathStr] = v3PathItem
+ }
+
+ return {
+ openapi: '3.0.0',
+ info: resolved.info as unknown as OpenAPIV3.InfoObject,
+ paths: v3Paths,
+ tags: (resolved.tags ?? []) as unknown as OpenAPIV3.TagObject[],
+ }
+}
+
+function convertV2Operation(op: OpenAPIV2.OperationObject): OpenAPIV3.OperationObject {
+ const params = (op.parameters ?? []) as OpenAPIV2.Parameter[]
+
+ const v3Params: OpenAPIV3.ParameterObject[] = params
+ .filter((p) => p.in !== 'body')
+ .map((p) => ({
+ name: p.name,
+ in: p.in as 'path' | 'query' | 'header' | 'cookie',
+ required: p.required ?? false,
+ description: p.description,
+ schema: { type: ((p as JsonObject).type as string) ?? 'string', format: (p as JsonObject).format as string | undefined } as OpenAPIV3.SchemaObject,
+ }))
+
+ const bodyParam = params.find((p) => p.in === 'body') as JsonObject | undefined
+ let requestBody: OpenAPIV3.RequestBodyObject | undefined
+ if (bodyParam?.schema) {
+ requestBody = {
+ required: (bodyParam.required as boolean) ?? false,
+ content: {
+ 'application/json': {
+ schema: bodyParam.schema as OpenAPIV3.SchemaObject,
+ },
+ },
+ }
+ }
+
+ const v3Responses: OpenAPIV3.ResponsesObject = {}
+ for (const [status, resp] of Object.entries(op.responses ?? {})) {
+ const v2Resp = resp as OpenAPIV2.ResponseObject
+ const v3Resp: OpenAPIV3.ResponseObject = {
+ description: v2Resp.description ?? '',
+ }
+ if ((v2Resp as unknown as JsonObject).schema) {
+ v3Resp.content = {
+ 'application/json': {
+ schema: (v2Resp as unknown as JsonObject).schema as OpenAPIV3.SchemaObject,
+ },
+ }
+ }
+ v3Responses[status] = v3Resp
+ }
+
+ const result: OpenAPIV3.OperationObject = {
+ operationId: op.operationId,
+ summary: op.summary,
+ description: op.description,
+ tags: op.tags,
+ parameters: v3Params,
+ responses: v3Responses,
+ }
+
+ if (requestBody) {
+ result.requestBody = requestBody
+ }
+
+ return result
+}
+
diff --git a/packages/chronicle/src/lib/schema.ts b/packages/chronicle/src/lib/schema.ts
new file mode 100644
index 00000000..ff846161
--- /dev/null
+++ b/packages/chronicle/src/lib/schema.ts
@@ -0,0 +1,99 @@
+import type { OpenAPIV3 } from 'openapi-types'
+
+export interface SchemaField {
+ name: string
+ type: string
+ required: boolean
+ description?: string
+ default?: unknown
+ enum?: unknown[]
+ children?: SchemaField[]
+}
+
+export function flattenSchema(
+ schema: OpenAPIV3.SchemaObject,
+ requiredFields: string[] = [],
+): SchemaField[] {
+ if (schema.type === 'array' && schema.items) {
+ const items = schema.items as OpenAPIV3.SchemaObject
+ const itemType = inferType(items)
+ const children =
+ itemType === 'object' || items.properties
+ ? flattenSchema(items, items.required ?? [])
+ : itemType.endsWith('[]') && (items as OpenAPIV3.ArraySchemaObject).items
+ ? flattenSchema((items as OpenAPIV3.ArraySchemaObject).items as OpenAPIV3.SchemaObject)
+ : undefined
+ return [{
+ name: 'items',
+ type: `${itemType}[]`,
+ required: true,
+ description: items.description,
+ children: children?.length ? children : undefined,
+ }]
+ }
+
+ if (schema.type === 'object' || schema.properties) {
+ const properties = (schema.properties ?? {}) as Record
+ const required = schema.required ?? requiredFields
+
+ return Object.entries(properties).map(([name, prop]) => {
+ const fieldType = inferType(prop)
+ const children =
+ fieldType === 'object' || prop.properties
+ ? flattenSchema(prop, prop.required)
+ : fieldType.endsWith('[]') && (prop as OpenAPIV3.ArraySchemaObject).items
+ ? flattenSchema((prop as OpenAPIV3.ArraySchemaObject).items as OpenAPIV3.SchemaObject)
+ : undefined
+
+ return {
+ name,
+ type: fieldType,
+ required: required.includes(name),
+ description: prop.description,
+ default: prop.default,
+ enum: prop.enum,
+ children: children?.length ? children : undefined,
+ }
+ })
+ }
+
+ return []
+}
+
+export function generateExampleJson(schema: OpenAPIV3.SchemaObject): unknown {
+ if (schema.example !== undefined) return schema.example
+ if (schema.default !== undefined) return schema.default
+
+ if (schema.type === 'array') {
+ const items = schema.items as OpenAPIV3.SchemaObject | undefined
+ return items ? [generateExampleJson(items)] : []
+ }
+
+ if (schema.type === 'object' || schema.properties) {
+ const properties = (schema.properties ?? {}) as Record
+ const result: Record = {}
+ for (const [name, prop] of Object.entries(properties)) {
+ result[name] = generateExampleJson(prop)
+ }
+ return result
+ }
+
+ const defaults: Record = {
+ string: 'string',
+ integer: 0,
+ number: 0,
+ boolean: true,
+ }
+ return defaults[schema.type as string] ?? null
+}
+
+function inferType(schema: OpenAPIV3.SchemaObject): string {
+ if (schema.type === 'array') {
+ const items = schema.items as OpenAPIV3.SchemaObject | undefined
+ const itemType = items ? inferType(items) : 'unknown'
+ return `${itemType}[]`
+ }
+
+ if (schema.format) return `${schema.type}(${schema.format})`
+ return (schema.type as string) ?? 'object'
+}
diff --git a/packages/chronicle/src/lib/snippet-generators.ts b/packages/chronicle/src/lib/snippet-generators.ts
new file mode 100644
index 00000000..6b125a72
--- /dev/null
+++ b/packages/chronicle/src/lib/snippet-generators.ts
@@ -0,0 +1,87 @@
+interface SnippetOptions {
+ method: string
+ url: string
+ headers: Record
+ body?: string
+}
+
+export function generateCurl({ method, url, headers, body }: SnippetOptions): string {
+ const parts = [`curl -X ${method} '${url}'`]
+ for (const [key, value] of Object.entries(headers)) {
+ parts.push(` -H '${key}: ${value}'`)
+ }
+ if (body) {
+ parts.push(` -d '${body}'`)
+ }
+ return parts.join(' \\\n')
+}
+
+export function generatePython({ method, url, headers, body }: SnippetOptions): string {
+ const lines: string[] = ['import requests', '']
+ const methodLower = method.toLowerCase()
+ const headerEntries = Object.entries(headers)
+
+ lines.push(`response = requests.${methodLower}(`)
+ lines.push(` "${url}",`)
+
+ if (headerEntries.length > 0) {
+ lines.push(' headers={')
+ for (const [key, value] of headerEntries) {
+ lines.push(` "${key}": "${value}",`)
+ }
+ lines.push(' },')
+ }
+
+ if (body) {
+ lines.push(` json=${body},`)
+ }
+
+ lines.push(')')
+ lines.push('print(response.json())')
+ return lines.join('\n')
+}
+
+export function generateGo({ method, url, headers, body }: SnippetOptions): string {
+ const lines: string[] = []
+
+ if (body) {
+ lines.push('payload := strings.NewReader(`' + body + '`)')
+ lines.push('')
+ lines.push(`req, _ := http.NewRequest("${method}", "${url}", payload)`)
+ } else {
+ lines.push(`req, _ := http.NewRequest("${method}", "${url}", nil)`)
+ }
+
+ for (const [key, value] of Object.entries(headers)) {
+ lines.push(`req.Header.Set("${key}", "${value}")`)
+ }
+
+ lines.push('')
+ lines.push('resp, _ := http.DefaultClient.Do(req)')
+ lines.push('defer resp.Body.Close()')
+ return lines.join('\n')
+}
+
+export function generateTypeScript({ method, url, headers, body }: SnippetOptions): string {
+ const lines: string[] = []
+ const headerEntries = Object.entries(headers)
+
+ lines.push(`const response = await fetch("${url}", {`)
+ lines.push(` method: "${method}",`)
+
+ if (headerEntries.length > 0) {
+ lines.push(' headers: {')
+ for (const [key, value] of headerEntries) {
+ lines.push(` "${key}": "${value}",`)
+ }
+ lines.push(' },')
+ }
+
+ if (body) {
+ lines.push(` body: JSON.stringify(${body}),`)
+ }
+
+ lines.push('});')
+ lines.push('const data = await response.json();')
+ return lines.join('\n')
+}
diff --git a/packages/chronicle/src/themes/default/Layout.tsx b/packages/chronicle/src/themes/default/Layout.tsx
index d6319b5c..e63d9960 100644
--- a/packages/chronicle/src/themes/default/Layout.tsx
+++ b/packages/chronicle/src/themes/default/Layout.tsx
@@ -1,18 +1,31 @@
"use client";
+import { useMemo } from "react";
import { usePathname } from "next/navigation";
+import NextLink from "next/link";
+import { cx } from "class-variance-authority";
import { Flex, Navbar, Headline, Link, Sidebar } from "@raystack/apsara";
+import { RectangleStackIcon } from "@heroicons/react/24/outline";
import { ClientThemeSwitcher } from "../../components/ui/client-theme-switcher";
import { Search } from "../../components/ui/search";
import { Footer } from "../../components/ui/footer";
+import { MethodBadge } from "../../components/api/method-badge";
import type { ThemeLayoutProps, PageTreeItem } from "../../types";
import styles from "./Layout.module.css";
-export function Layout({ children, config, tree }: ThemeLayoutProps) {
+const iconMap: Record = {
+ "rectangle-stack": ,
+ "method-get": ,
+ "method-post": ,
+ "method-put": ,
+ "method-delete": ,
+ "method-patch": ,
+};
+
+export function Layout({ children, config, tree, classNames }: ThemeLayoutProps) {
const pathname = usePathname();
- console.log(config);
return (
-
+
@@ -31,8 +44,8 @@ export function Layout({ children, config, tree }: ThemeLayoutProps) {
-
-
+
+
{tree.children.map((item) => (
- {children}
+ {children}
@@ -65,6 +78,7 @@ function SidebarNode({
return (
{item.children.map((child) => (
@@ -79,9 +93,16 @@ function SidebarNode({
}
const isActive = pathname === item.url;
+ const href = item.url ?? "#";
+ const link = useMemo(() => , [href]);
return (
-
+
{item.name}
);
diff --git a/packages/chronicle/src/types/config.ts b/packages/chronicle/src/types/config.ts
index 02525a73..51332ad8 100644
--- a/packages/chronicle/src/types/config.ts
+++ b/packages/chronicle/src/types/config.ts
@@ -6,6 +6,26 @@ export interface ChronicleConfig {
navigation?: NavigationConfig
search?: SearchConfig
footer?: FooterConfig
+ api?: ApiConfig[]
+}
+
+export interface ApiConfig {
+ name: string
+ spec: string
+ basePath: string
+ server: ApiServerConfig
+ auth?: ApiAuthConfig
+}
+
+export interface ApiServerConfig {
+ url: string
+ description?: string
+}
+
+export interface ApiAuthConfig {
+ type: string
+ header: string
+ placeholder?: string
}
export interface LogoConfig {
diff --git a/packages/chronicle/src/types/content.ts b/packages/chronicle/src/types/content.ts
index 9b6e47c9..bfd9332f 100644
--- a/packages/chronicle/src/types/content.ts
+++ b/packages/chronicle/src/types/content.ts
@@ -25,6 +25,7 @@ export interface PageTreeItem {
name: string
url?: string
order?: number
+ icon?: string
children?: PageTreeItem[]
}
diff --git a/packages/chronicle/src/types/theme.ts b/packages/chronicle/src/types/theme.ts
index 18a840f8..a6b0a4f3 100644
--- a/packages/chronicle/src/types/theme.ts
+++ b/packages/chronicle/src/types/theme.ts
@@ -6,6 +6,7 @@ export interface ThemeLayoutProps {
children: ReactNode
config: ChronicleConfig
tree: PageTree
+ classNames?: { layout?: string; body?: string; sidebar?: string; content?: string }
}
export interface ThemePageProps {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d3bd0f4f..f265389c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -10,6 +10,18 @@ importers:
packages/chronicle:
dependencies:
+ '@codemirror/lang-json':
+ specifier: ^6.0.2
+ version: 6.0.2
+ '@codemirror/state':
+ specifier: ^6.5.4
+ version: 6.5.4
+ '@codemirror/theme-one-dark':
+ specifier: ^6.1.3
+ version: 6.1.3
+ '@codemirror/view':
+ specifier: ^6.39.14
+ version: 6.39.14
'@heroicons/react':
specifier: ^2.2.0
version: 2.2.0(react@19.2.4)
@@ -19,6 +31,12 @@ importers:
chalk:
specifier: ^5.6.2
version: 5.6.2
+ class-variance-authority:
+ specifier: ^0.7.1
+ version: 0.7.1
+ codemirror:
+ specifier: ^6.0.2
+ version: 6.0.2
commander:
specifier: ^14.0.2
version: 14.0.2
@@ -46,6 +64,9 @@ importers:
remark-attr:
specifier: ^0.11.1
version: 0.11.1
+ slugify:
+ specifier: ^1.6.6
+ version: 1.6.6
yaml:
specifier: ^2.8.2
version: 2.8.2
@@ -74,6 +95,9 @@ importers:
'@types/react-dom':
specifier: ^19.2.3
version: 19.2.3(@types/react@19.2.10)
+ openapi-types:
+ specifier: ^12.1.3
+ version: 12.1.3
tsup:
specifier: ^8.5.1
version: 8.5.1(postcss@8.4.31)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)
@@ -154,6 +178,33 @@ packages:
cpu: [x64]
os: [win32]
+ '@codemirror/autocomplete@6.20.0':
+ resolution: {integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==}
+
+ '@codemirror/commands@6.10.2':
+ resolution: {integrity: sha512-vvX1fsih9HledO1c9zdotZYUZnE4xV0m6i3m25s5DIfXofuprk6cRcLUZvSk3CASUbwjQX21tOGbkY2BH8TpnQ==}
+
+ '@codemirror/lang-json@6.0.2':
+ resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==}
+
+ '@codemirror/language@6.12.1':
+ resolution: {integrity: sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ==}
+
+ '@codemirror/lint@6.9.4':
+ resolution: {integrity: sha512-ABc9vJ8DEmvOWuH26P3i8FpMWPQkduD9Rvba5iwb6O3hxASgclm3T3krGo8NASXkHCidz6b++LWlzWIUfEPSWw==}
+
+ '@codemirror/search@6.6.0':
+ resolution: {integrity: sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw==}
+
+ '@codemirror/state@6.5.4':
+ resolution: {integrity: sha512-8y7xqG/hpB53l25CIoit9/ngxdfoG+fx+V3SHBrinnhOtLvKHRyAJJuHzkWrR4YXXLX8eXBsejgAAxHUOdW1yw==}
+
+ '@codemirror/theme-one-dark@6.1.3':
+ resolution: {integrity: sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==}
+
+ '@codemirror/view@6.39.14':
+ resolution: {integrity: sha512-WJcvgHm/6Q7dvGT0YFv/6PSkoc36QlR0VCESS6x9tGsnF1lWLmmYxOgX3HH6v8fo6AvSLgpcs+H0Olre6MKXlg==}
+
'@date-fns/tz@1.4.1':
resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==}
@@ -492,6 +543,21 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+ '@lezer/common@1.5.1':
+ resolution: {integrity: sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw==}
+
+ '@lezer/highlight@1.2.3':
+ resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==}
+
+ '@lezer/json@1.0.3':
+ resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==}
+
+ '@lezer/lr@1.4.8':
+ resolution: {integrity: sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==}
+
+ '@marijn/find-cluster-break@1.0.2':
+ resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
+
'@mdx-js/mdx@3.1.1':
resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==}
@@ -1603,6 +1669,9 @@ packages:
react: ^18 || ^19 || ^19.0.0-rc
react-dom: ^18 || ^19 || ^19.0.0-rc
+ codemirror@6.0.2:
+ resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==}
+
collapse-white-space@2.1.0:
resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==}
@@ -1643,6 +1712,9 @@ packages:
resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==}
engines: {node: ^14.18.0 || >=16.10.0}
+ crelt@1.0.6:
+ resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
+
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
@@ -2108,6 +2180,9 @@ packages:
oniguruma-to-es@4.3.4:
resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==}
+ openapi-types@12.1.3:
+ resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==}
+
parse-entities@4.0.2:
resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
@@ -2316,6 +2391,10 @@ packages:
shiki@3.21.0:
resolution: {integrity: sha512-N65B/3bqL/TI2crrXr+4UivctrAGEjmsib5rPMMPpFp1xAx/w03v8WZ9RDDFYteXoEgY7qZ4HGgl5KBIu1153w==}
+ slugify@1.6.6:
+ resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==}
+ engines: {node: '>=8.0.0'}
+
sonner@2.0.7:
resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==}
peerDependencies:
@@ -2336,6 +2415,9 @@ packages:
stringify-entities@4.0.4:
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
+ style-mod@4.1.3:
+ resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==}
+
style-to-js@1.1.21:
resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==}
@@ -2488,6 +2570,9 @@ packages:
vfile@6.0.3:
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
+ w3c-keyname@2.2.8:
+ resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
+
yaml@2.8.2:
resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==}
engines: {node: '>= 14.6'}
@@ -2552,6 +2637,64 @@ snapshots:
'@biomejs/cli-win32-x64@2.3.13':
optional: true
+ '@codemirror/autocomplete@6.20.0':
+ dependencies:
+ '@codemirror/language': 6.12.1
+ '@codemirror/state': 6.5.4
+ '@codemirror/view': 6.39.14
+ '@lezer/common': 1.5.1
+
+ '@codemirror/commands@6.10.2':
+ dependencies:
+ '@codemirror/language': 6.12.1
+ '@codemirror/state': 6.5.4
+ '@codemirror/view': 6.39.14
+ '@lezer/common': 1.5.1
+
+ '@codemirror/lang-json@6.0.2':
+ dependencies:
+ '@codemirror/language': 6.12.1
+ '@lezer/json': 1.0.3
+
+ '@codemirror/language@6.12.1':
+ dependencies:
+ '@codemirror/state': 6.5.4
+ '@codemirror/view': 6.39.14
+ '@lezer/common': 1.5.1
+ '@lezer/highlight': 1.2.3
+ '@lezer/lr': 1.4.8
+ style-mod: 4.1.3
+
+ '@codemirror/lint@6.9.4':
+ dependencies:
+ '@codemirror/state': 6.5.4
+ '@codemirror/view': 6.39.14
+ crelt: 1.0.6
+
+ '@codemirror/search@6.6.0':
+ dependencies:
+ '@codemirror/state': 6.5.4
+ '@codemirror/view': 6.39.14
+ crelt: 1.0.6
+
+ '@codemirror/state@6.5.4':
+ dependencies:
+ '@marijn/find-cluster-break': 1.0.2
+
+ '@codemirror/theme-one-dark@6.1.3':
+ dependencies:
+ '@codemirror/language': 6.12.1
+ '@codemirror/state': 6.5.4
+ '@codemirror/view': 6.39.14
+ '@lezer/highlight': 1.2.3
+
+ '@codemirror/view@6.39.14':
+ dependencies:
+ '@codemirror/state': 6.5.4
+ crelt: 1.0.6
+ style-mod: 4.1.3
+ w3c-keyname: 2.2.8
+
'@date-fns/tz@1.4.1': {}
'@emnapi/runtime@1.8.1':
@@ -2778,6 +2921,24 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
+ '@lezer/common@1.5.1': {}
+
+ '@lezer/highlight@1.2.3':
+ dependencies:
+ '@lezer/common': 1.5.1
+
+ '@lezer/json@1.0.3':
+ dependencies:
+ '@lezer/common': 1.5.1
+ '@lezer/highlight': 1.2.3
+ '@lezer/lr': 1.4.8
+
+ '@lezer/lr@1.4.8':
+ dependencies:
+ '@lezer/common': 1.5.1
+
+ '@marijn/find-cluster-break@1.0.2': {}
+
'@mdx-js/mdx@3.1.1':
dependencies:
'@types/estree': 1.0.8
@@ -3891,6 +4052,16 @@ snapshots:
- '@types/react'
- '@types/react-dom'
+ codemirror@6.0.2:
+ dependencies:
+ '@codemirror/autocomplete': 6.20.0
+ '@codemirror/commands': 6.10.2
+ '@codemirror/language': 6.12.1
+ '@codemirror/lint': 6.9.4
+ '@codemirror/search': 6.6.0
+ '@codemirror/state': 6.5.4
+ '@codemirror/view': 6.39.14
+
collapse-white-space@2.1.0: {}
color-convert@3.1.3:
@@ -3920,6 +4091,8 @@ snapshots:
consola@3.4.2: {}
+ crelt@1.0.6: {}
+
csstype@3.2.3: {}
date-fns-jalali@4.1.0-0: {}
@@ -4703,6 +4876,8 @@ snapshots:
regex: 6.1.0
regex-recursion: 6.0.2
+ openapi-types@12.1.3: {}
+
parse-entities@4.0.2:
dependencies:
'@types/unist': 2.0.11
@@ -5060,6 +5235,8 @@ snapshots:
'@shikijs/vscode-textmate': 10.0.2
'@types/hast': 3.0.4
+ slugify@1.6.6: {}
+
sonner@2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
dependencies:
react: 19.2.4
@@ -5076,6 +5253,8 @@ snapshots:
character-entities-html4: 2.1.0
character-entities-legacy: 3.0.0
+ style-mod@4.1.3: {}
+
style-to-js@1.1.21:
dependencies:
style-to-object: 1.0.14
@@ -5240,6 +5419,8 @@ snapshots:
'@types/unist': 3.0.3
vfile-message: 4.0.3
+ w3c-keyname@2.2.8: {}
+
yaml@2.8.2: {}
zod@4.3.6: {}