Skip to content

Commit f8c21e0

Browse files
feat(api): generate v2 OpenAPI from contracts (#6509)
* feat(api): generate v2 OpenAPI from contracts * fix(api): preserve string boolean wire defaults * fix(api): document file download headers * fix(docs): use TypeScript CLI with Next.js * fix(docs): avoid client-rendered theme script * fix(api): document departed audit default * feat(api): replace legacy core docs with v2 * feat(api): generate v2 OpenAPI from contracts * feat(api): refine generated v2 OpenAPI docs * fix(docs): align localized v2 execution examples
1 parent da3442e commit f8c21e0

101 files changed

Lines changed: 28233 additions & 22689 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/docs/app/[lang]/[[...slug]]/page.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { PageFooter } from '@/components/docs-layout/page-footer'
1111
import { PageNavigationArrows } from '@/components/docs-layout/page-navigation-arrows'
1212
import { LLMCopyButton } from '@/components/page-actions'
1313
import { StructuredData } from '@/components/structured-data'
14+
import { APIExampleSelector } from '@/components/ui/api-example-selector'
1415
import { CodeBlock } from '@/components/ui/code-block'
1516
import { Heading } from '@/components/ui/heading'
1617
import { ResponseSection } from '@/components/ui/response-section'
@@ -70,12 +71,16 @@ function stripLocalePrefix(url: string, lang: string): string {
7071

7172
const APIPage = createAPIPage(openapi, {
7273
playground: { enabled: false },
74+
client: {
75+
operation: { APIExampleSelector },
76+
},
7377
content: {
74-
renderOperationLayout: async (slots) => {
78+
renderOperationLayout: (slots) => {
7579
return (
7680
<div className='flex @4xl:flex-row flex-col @4xl:items-start gap-x-6 gap-y-4'>
7781
<div className='min-w-0 flex-1'>
7882
{slots.header}
83+
{slots.description}
7984
{slots.apiPlayground}
8085
{slots.authSchemes && <div className='api-section-divider'>{slots.authSchemes}</div>}
8186
{slots.parameters}

apps/docs/app/[lang]/layout.tsx

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { defineI18nUI } from 'fumadocs-ui/i18n'
33
import { DocsLayout } from 'fumadocs-ui/layouts/docs'
44
import { RootProvider } from 'fumadocs-ui/provider/next'
55
import { Geist_Mono, Inter } from 'next/font/google'
6+
import Script from 'next/script'
7+
import { ThemeProvider } from 'next-themes'
68
import {
79
SidebarFolder,
810
SidebarItem,
@@ -90,40 +92,49 @@ export default async function Layout({ children, params }: LayoutProps) {
9092
suppressHydrationWarning
9193
>
9294
<head>
93-
<script
95+
<Script
96+
id='website-json-ld'
9497
type='application/ld+json'
98+
strategy='beforeInteractive'
9599
dangerouslySetInnerHTML={{ __html: serializeJsonLd(structuredData) }}
96100
/>
97101
</head>
98102
<body className='flex min-h-screen flex-col font-sans'>
99-
<RootProvider i18n={provider(lang)}>
100-
<Navbar />
101-
<DocsLayout
102-
tree={source.pageTree[lang]}
103-
nav={{
104-
title: <SimWordmark className='h-[18px]' />,
105-
}}
106-
sidebar={{
107-
tabs: false,
108-
defaultOpenLevel: 0,
109-
collapsible: false,
110-
footer: null,
111-
banner: null,
112-
prefetch: false,
113-
components: {
114-
Item: SidebarItem,
115-
Folder: SidebarFolder,
116-
Separator: SidebarSeparator,
117-
},
118-
}}
119-
containerProps={{
120-
className: '!pt-0',
121-
}}
122-
>
123-
{children}
124-
</DocsLayout>
125-
<Footer />
126-
</RootProvider>
103+
<ThemeProvider
104+
attribute='class'
105+
defaultTheme='system'
106+
enableSystem
107+
disableTransitionOnChange
108+
>
109+
<RootProvider i18n={provider(lang)} theme={{ enabled: false }}>
110+
<Navbar />
111+
<DocsLayout
112+
tree={source.pageTree[lang]}
113+
nav={{
114+
title: <SimWordmark className='h-[18px]' />,
115+
}}
116+
sidebar={{
117+
tabs: false,
118+
defaultOpenLevel: 0,
119+
collapsible: false,
120+
footer: null,
121+
banner: null,
122+
prefetch: false,
123+
components: {
124+
Item: SidebarItem,
125+
Folder: SidebarFolder,
126+
Separator: SidebarSeparator,
127+
},
128+
}}
129+
containerProps={{
130+
className: '!pt-0',
131+
}}
132+
>
133+
{children}
134+
</DocsLayout>
135+
<Footer />
136+
</RootProvider>
137+
</ThemeProvider>
127138
</body>
128139
</html>
129140
)

apps/docs/components/structured-data.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Script from 'next/script'
12
import { serializeJsonLd } from '@/lib/json-ld'
23
import { DOCS_BASE_URL } from '@/lib/urls'
34

@@ -19,6 +20,7 @@ export function StructuredData({
1920
breadcrumb,
2021
}: StructuredDataProps) {
2122
const baseUrl = DOCS_BASE_URL
23+
const structuredDataId = encodeURIComponent(url)
2224

2325
const articleStructuredData = {
2426
'@context': 'https://schema.org',
@@ -101,22 +103,25 @@ export function StructuredData({
101103

102104
return (
103105
<>
104-
<script
106+
<Script
107+
id={`article-json-ld-${structuredDataId}`}
105108
type='application/ld+json'
106109
dangerouslySetInnerHTML={{
107110
__html: serializeJsonLd(articleStructuredData),
108111
}}
109112
/>
110113
{breadcrumbStructuredData && (
111-
<script
114+
<Script
115+
id={`breadcrumb-json-ld-${structuredDataId}`}
112116
type='application/ld+json'
113117
dangerouslySetInnerHTML={{
114118
__html: serializeJsonLd(breadcrumbStructuredData),
115119
}}
116120
/>
117121
)}
118122
{(url === baseUrl || url === `${baseUrl}/`) && (
119-
<script
123+
<Script
124+
id={`software-json-ld-${structuredDataId}`}
120125
type='application/ld+json'
121126
dangerouslySetInnerHTML={{
122127
__html: serializeJsonLd(softwareStructuredData),
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use client'
2+
3+
import type { ComponentProps } from 'react'
4+
import { useId } from 'react'
5+
import { ChevronDown } from '@sim/emcn/icons'
6+
import type { APIPageClientOptions } from 'fumadocs-openapi/ui/client'
7+
8+
type FumadocsAPIExampleSelector = NonNullable<
9+
NonNullable<APIPageClientOptions['operation']>['APIExampleSelector']
10+
>
11+
12+
interface APIExampleSelectorProps extends ComponentProps<FumadocsAPIExampleSelector> {}
13+
14+
export function APIExampleSelector({ items, value, onValueChange }: APIExampleSelectorProps) {
15+
const id = useId()
16+
17+
if (items.length <= 1) return null
18+
19+
const selectedValue = value ?? items[0].id
20+
const selectedItem = items.find((item) => item.id === selectedValue)
21+
22+
return (
23+
<div className='not-prose mb-2 flex flex-col gap-1.5'>
24+
<label htmlFor={id} className='sr-only'>
25+
Request example
26+
</label>
27+
<div className='relative'>
28+
<select
29+
id={id}
30+
value={selectedValue}
31+
onChange={(event) => onValueChange(event.target.value)}
32+
className='w-full appearance-none rounded-md border bg-fd-secondary py-2 ps-3 pe-9 text-start font-medium text-fd-secondary-foreground text-sm outline-none transition-colors hover:bg-fd-accent focus-visible:ring-2 focus-visible:ring-fd-ring'
33+
>
34+
{items.map((item) => (
35+
<option key={item.id} value={item.id}>
36+
{item.name}
37+
</option>
38+
))}
39+
</select>
40+
<ChevronDown className='-translate-y-1/2 pointer-events-none absolute end-3 top-1/2 size-[14px] text-fd-muted-foreground' />
41+
</div>
42+
{selectedItem?.description && (
43+
<p className='text-fd-muted-foreground text-xs'>{selectedItem.description}</p>
44+
)}
45+
</div>
46+
)
47+
}

apps/docs/components/ui/faq.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
'use client'
22

3-
import { useState } from 'react'
3+
import { useId, useState } from 'react'
44
import { ChevronRight } from '@sim/emcn/icons'
5+
import Script from 'next/script'
56
import { serializeJsonLd } from '@/lib/json-ld'
67
import { cn } from '@/lib/utils'
78

@@ -58,6 +59,7 @@ function FAQItemRow({
5859
}
5960

6061
export function FAQ({ items, title = 'Common Questions' }: FAQProps) {
62+
const structuredDataId = useId()
6163
/**
6264
* Rows open independently rather than as a single-open accordion. Auto-closing
6365
* a sibling collapses content *above* the row being opened, which yanks that
@@ -89,7 +91,8 @@ export function FAQ({ items, title = 'Common Questions' }: FAQProps) {
8991

9092
return (
9193
<div className='mt-12'>
92-
<script
94+
<Script
95+
id={`faq-json-ld-${structuredDataId}`}
9396
type='application/ld+json'
9497
dangerouslySetInnerHTML={{ __html: serializeJsonLd(faqSchema) }}
9598
/>

apps/docs/content/docs/de/api-reference/authentication.mdx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,23 +41,23 @@ Pass your API key in the `X-API-Key` header with every request:
4141
<Tabs items={['curl', 'TypeScript', 'Python']}>
4242
<Tab value="curl">
4343
```bash
44-
curl -X POST https://www.sim.ai/api/workflows/{workflowId}/execute \
44+
curl -X POST https://www.sim.ai/api/v2/workflows/{workflowId}/execute \
4545
-H "Content-Type: application/json" \
4646
-H "X-API-Key: YOUR_API_KEY" \
47-
-d '{"inputs": {}}'
47+
-d '{"input": {}}'
4848
```
4949
</Tab>
5050
<Tab value="TypeScript">
5151
```typescript
5252
const response = await fetch(
53-
'https://www.sim.ai/api/workflows/{workflowId}/execute',
53+
'https://www.sim.ai/api/v2/workflows/{workflowId}/execute',
5454
{
5555
method: 'POST',
5656
headers: {
5757
'Content-Type': 'application/json',
5858
'X-API-Key': process.env.SIM_API_KEY!,
5959
},
60-
body: JSON.stringify({ inputs: {} }),
60+
body: JSON.stringify({ input: {} }),
6161
}
6262
)
6363
```
@@ -67,12 +67,12 @@ Pass your API key in the `X-API-Key` header with every request:
6767
import requests
6868

6969
response = requests.post(
70-
"https://www.sim.ai/api/workflows/{workflowId}/execute",
70+
"https://www.sim.ai/api/v2/workflows/{workflowId}/execute",
7171
headers={
7272
"Content-Type": "application/json",
7373
"X-API-Key": os.environ["SIM_API_KEY"],
7474
},
75-
json={"inputs": {}},
75+
json={"input": {}},
7676
)
7777
```
7878
</Tab>

0 commit comments

Comments
 (0)