import { Fragment } from 'react'
import ReactMarkdown from 'react-markdown'
import {
Badge,
cn,
Tabs_Shadcn_,
TabsContent_Shadcn_,
TabsList_Shadcn_,
TabsTrigger_Shadcn_,
} from 'ui'
import { isFeatureEnabled } from 'common'
import ApiSchema from '~/components/ApiSchema'
import { clientSdkIds, REFERENCES } from '~/content/navigation.references'
import {
getApiEndpointById,
getCliSpec,
getFlattenedSections,
getFunctionsList,
getSelfHostedApiEndpointById,
getTypeSpec,
} from '~/features/docs/Reference.generated.singleton'
import { getRefMarkdown, MDXRemoteRefs } from '~/features/docs/Reference.mdx'
import type { MethodTypes } from '~/features/docs/Reference.typeSpec'
import { formatMethodSignature } from '~/features/docs/Reference.typeSpec'
import {
ApiOperationRequestBodyDetails,
ApiSchemaParamDetails,
CollapsibleDetails,
FnParameterDetails,
RefSubLayout,
ReturnTypeDetails,
StickyHeader,
} from '~/features/docs/Reference.ui'
import type { AbbrevApiReferenceSection } from '~/features/docs/Reference.utils'
import { normalizeMarkdown } from '~/features/docs/Reference.utils'
import { CodeBlock } from '~/features/ui/CodeBlock/CodeBlock'
import { type IApiEndPoint } from './Reference.api.utils'
import { RefInternalLink } from './Reference.navigation.client'
import { ApiOperationBodySchemeSelector } from './Reference.ui.client'
type RefSectionsProps = {
libraryId: string
version: string
}
async function RefSections({ libraryId, version }: RefSectionsProps) {
let flattenedSections = await getFlattenedSections(libraryId, version)
if (flattenedSections) {
flattenedSections = trimIntro(flattenedSections)
}
if (!isFeatureEnabled('sdk:auth') && clientSdkIds.includes(libraryId)) {
flattenedSections = flattenedSections?.filter(
(section) =>
'product' in section && section.product !== 'auth' && section.product !== 'auth-admin'
)
}
return (
{(flattenedSections || [])
.filter((section) => section.type !== 'category')
.map((section, idx) => (
))}
)
}
function trimIntro(sections: Array) {
const hasIntro = sections[0]?.type === 'markdown' && sections[0]?.slug === 'introduction'
if (hasIntro) {
return sections.slice(1)
}
return sections
}
function SectionDivider() {
return
}
type SectionSwitchProps = {
libraryId: string
version: string
section: AbbrevApiReferenceSection
}
export function SectionSwitch({ libraryId, version, section }: SectionSwitchProps) {
const libPath = REFERENCES[libraryId.replaceAll('-', '_')].libPath
const allAvailableVersions = REFERENCES[libraryId.replaceAll('-', '_')].versions
const isLatestVersion = allAvailableVersions.length === 0 || version === allAvailableVersions[0]
const sectionLink = `/docs/reference/${libPath}/${isLatestVersion ? '' : `${version}/`}${section.slug}`
switch (section.type) {
case 'markdown':
return (
)
case 'function':
return (
)
case 'cli-command':
return
case 'operation':
return
case 'self-hosted-operation':
return
default:
console.error(`Unhandled type in reference sections: ${section.type}`)
return null
}
}
interface MarkdownSectionProps {
libPath: string
version: string
isLatestVersion: boolean
link: string
section: AbbrevApiReferenceSection
}
async function MarkdownSection({
libPath,
version,
isLatestVersion,
link,
section,
}: MarkdownSectionProps) {
const content = await getRefMarkdown(
section.meta?.shared
? `shared/${section.id}`
: `${libPath}/${isLatestVersion ? '' : `${version}/`}${section.id}`
)
return (
)
}
interface CliCommandSectionProps {
link: string
section: AbbrevApiReferenceSection
}
async function CliCommandSection({ link, section }: CliCommandSectionProps) {
const cliSpec = await getCliSpec()
const command = ((cliSpec as any).commands ?? []).find((cmd) => cmd.id === section.id)
if (!command) return null
return (
{command.description && (
{command.description}
)}
{command.usage && (
Usage
{command.usage}
)}
{(command.subcommands ?? []).length > 0 && (
<>
Subcommands
{command.subcommands.map((subcommand, index) => {
const subcommandDetails = (cliSpec as any).commands.find(
(cmd) => cmd.id === subcommand
)
if (!subcommandDetails) return null
return (
{subcommandDetails.title}
)
})}
>
)}
{(command.flags ?? []).length > 0 && (
<>
Flags
>
)}
{'examples' in command &&
Array.isArray(command.examples) &&
command.examples.length > 0 && (
{command.examples.map((example) => (
{example.name}
))}
{command.examples.map((example) => (
{example.code}
Response
{example.response}
))}
)}
)
}
interface ApiEndpointSectionProps {
link: string
section: AbbrevApiReferenceSection
servicePath?: string
}
async function ApiEndpointSection({ link, section, servicePath }: ApiEndpointSectionProps) {
const endpointDetails = servicePath
? await getSelfHostedApiEndpointById(servicePath, section.id)
: await getApiEndpointById(section.id)
if (!endpointDetails) return null
const pathParameters = (endpointDetails.parameters ?? []).filter((param) => param.in === 'path')
const queryParameters = (endpointDetails.parameters ?? []).filter((param) => param.in === 'query')
const bodyParameters =
endpointDetails.requestBody ??
(endpointDetails.parameters ?? [])
.filter((param) => param.in === 'body')
.map(
(bodyParam) =>
({
content: {
'application/json': {
schema: bodyParam.schema,
},
},
}) satisfies IApiEndPoint['requestBody']
)[0]
const first2xxCode = Object.keys(endpointDetails.responses ?? {})
.filter((code) => code.startsWith('2'))
.sort()[0]
return (
{endpointDetails.summary}
{endpointDetails.deprecated && (
deprecated
)}
>
}
className="col-[1_/_-1]"
/>
{endpointDetails.method}
{endpointDetails.path}
{endpointDetails.description && (
{endpointDetails.description}
)}
{endpointDetails['x-oauth-scope'] && (
OAuth scopes
{endpointDetails['x-oauth-scope']}
)}
{pathParameters.length > 0 && (
Path parameters
{pathParameters.map((param, index) => (
))}
)}
{queryParameters.length > 0 && (
Query parameters
{queryParameters.map((param, index) => (
))}
)}
{bodyParameters && (
)}
{endpointDetails.responses && (
Response codes
{Object.keys(endpointDetails.responses).map((code) => (
{code}
))}
)}
{endpointDetails.responses && first2xxCode && (
{`Response (${first2xxCode})`}
)}
)
}
interface FunctionSectionProps {
sdkId: string
version: string
link: string
section: AbbrevApiReferenceSection
useTypeSpec: boolean
}
async function FunctionSection({
sdkId,
version,
link,
section,
useTypeSpec,
}: FunctionSectionProps) {
const fns = await getFunctionsList(sdkId, version)
const fn = fns?.find((fn) => fn.id === section.id)
if (!fn) return null
let types: MethodTypes | undefined
if (useTypeSpec && '$ref' in fn) {
types = await getTypeSpec(fn['$ref'] as string)
}
const fullDescription = [
types?.comment?.shortText,
'description' in fn && (fn.description as string),
'notes' in fn && (fn.notes as string),
]
.filter(Boolean)
.map(normalizeMarkdown)
.join('\n\n')
return (
{/* Display method signature below title */}
{types && formatMethodSignature(types) && (
{formatMethodSignature(types)}
)}
).map((overwrittenParams) => ({
...overwrittenParams,
__overwritten: true,
}))
: 'params' in fn
? (fn.params as Array).map((param) => ({ ...param, __overwritten: true }))
: types?.params
}
altParameters={types?.altSignatures?.map(({ params }) => params)}
className="max-w-[80ch]"
/>
{!!types?.ret && }
{(() => {
// Prefer YAML examples, fallback to TypeDoc examples
const yamlExamples =
'examples' in fn && Array.isArray(fn.examples) && fn.examples.length > 0
? fn.examples
: []
const examples = yamlExamples.length > 0 ? yamlExamples : types?.comment?.examples || []
if (examples.length === 0) return null
return (
{examples.map((example) => (
{example.name}
))}
{examples.map((example) => (
{/* Only YAML examples have data/response/description fields */}
{'data' in example && !!example.data?.sql && (
)}
{'response' in example && !!example.response && (
)}
{'description' in example && !!example.description && (
)}
))}
)
})()}
)
}
export { RefSections }