docs: show events emitted in an API route in the API reference (#12392)

* docs: show events emitted in an API route in the API reference

* fix build error

* support version tag

* add missing property
This commit is contained in:
Shahed Nasser authored and GitHub committed 2025-05-07 14:56:54 +03:00
1 parent 0dd4572964
commit 262064fe96
8 files changed
+166

No files matched your search

@@ -0,0 +1,135 @@
"use client"
import {
Badge,
DetailsSummary,
Link,
MarkdownContent,
Tabs,
TabsContent,
TabsContentWrapper,
TabsList,
TabsTrigger,
Tooltip,
} from "docs-ui"
import { useMemo } from "react"
import type { OpenAPI } from "types"
import TagOperationParameters from "../../Parameters"
export type TagsOperationDescriptionSectionEventsProps = {
events: OpenAPI.OasEvents[]
}
const TagsOperationDescriptionSectionEvents = ({
events,
}: TagsOperationDescriptionSectionEventsProps) => {
return (
<>
<DetailsSummary
title="Emitted Events"
subtitle={
<span>
The following events are emitted by the workflow used in this API
route. You can listen to and handle these events using a{" "}
<Link href="https://docs.medusajs.com/learn/fundamentals/events-and-subscribers">
Subscriber
</Link>
</span>
}
expandable={false}
className="border-t-0"
titleClassName="text-h3 mt-1.5"
/>
<Tabs defaultValue={events[0].name} className="mt-1">
<TabsList>
{events.map((event) => (
<TabsTrigger key={event.name} value={event.name}>
{event.name}
</TabsTrigger>
))}
</TabsList>
<TabsContentWrapper>
{events.map((event) => (
<TagsOperationDescriptionSectionEvent
key={event.name}
event={event}
/>
))}
</TabsContentWrapper>
</Tabs>
</>
)
}
export default TagsOperationDescriptionSectionEvents
const TagsOperationDescriptionSectionEvent = ({
event,
}: {
event: OpenAPI.OasEvents
}) => {
const parsedPayload: OpenAPI.SchemaObject = useMemo(() => {
const payloadParams = event.payload.matchAll(
/([\w_]+),? \/\/ (\(\w*\) )*(.*)/g
)
const payload = Array.from(payloadParams).map((match) => {
return {
name: match[1],
type: match[2]?.replace(/\(|\)/g, "") || "string",
description: match[3],
}
})
return {
type: "object",
required: ["payload"],
properties: {
payload: {
type: "object",
description: "The payload emitted with the event",
required: [...payload.map((param) => param.name)],
properties: payload.reduce(
(acc, curr) => {
acc[curr.name] = {
type: curr.type as OpenAPI.OpenAPIV3.NonArraySchemaObjectType,
description: curr.description,
properties: {},
}
return acc
},
{} as Record<string, OpenAPI.SchemaObject>
),
},
},
}
}, [event.payload])
return (
<TabsContent value={event.name}>
<div className="my-1 flex flex-wrap gap-1">
<MarkdownContent
allowedElements={["code", "p", "a"]}
className={"[&_p:last-child]:!mb-1"}
>
{`\`${event.name}\`: ${event.description}`}
</MarkdownContent>
{event.deprecated &&
(event.deprecated_message ? (
<Tooltip text={event.deprecated_message}>
<Badge variant="orange">Deprecated</Badge>
</Tooltip>
) : (
<Badge variant="orange">Deprecated</Badge>
))}
{event.version && (
<Tooltip text={`This event is emitted since v${event.version}`}>
<Badge variant="blue">v{event.version}</Badge>
</Tooltip>
)}
</div>
<TagOperationParameters
schemaObject={parsedPayload}
topLevel={true}
isExpanded={true}
/>
</TabsContent>
)
}
@@ -11,6 +11,7 @@ import { useArea } from "../../../../providers/area"
import { Feedback, Badge, Link, FeatureFlagNotice, H2 } from "docs-ui" import { Feedback, Badge, Link, FeatureFlagNotice, H2 } from "docs-ui"
import { usePathname } from "next/navigation" import { usePathname } from "next/navigation"
import { TagsOperationDescriptionSectionWorkflowBadgeProps } from "./WorkflowBadge" import { TagsOperationDescriptionSectionWorkflowBadgeProps } from "./WorkflowBadge"
import { TagsOperationDescriptionSectionEventsProps } from "./Events"
const TagsOperationDescriptionSectionSecurity = const TagsOperationDescriptionSectionSecurity =
dynamic<TagsOperationDescriptionSectionSecurityProps>( dynamic<TagsOperationDescriptionSectionSecurityProps>(
@@ -32,6 +33,11 @@ const TagsOperationDescriptionSectionWorkflowBadge =
async () => import("./WorkflowBadge") async () => import("./WorkflowBadge")
) as React.FC<TagsOperationDescriptionSectionWorkflowBadgeProps> ) as React.FC<TagsOperationDescriptionSectionWorkflowBadgeProps>
const TagsOperationDescriptionSectionEvents =
dynamic<TagsOperationDescriptionSectionEventsProps>(
async () => import("./Events")
) as React.FC<TagsOperationDescriptionSectionEventsProps>
type TagsOperationDescriptionSectionProps = { type TagsOperationDescriptionSectionProps = {
operation: OpenAPI.Operation operation: OpenAPI.Operation
} }
@@ -103,6 +109,11 @@ const TagsOperationDescriptionSection = ({
<TagsOperationDescriptionSectionResponses <TagsOperationDescriptionSectionResponses
responses={operation.responses} responses={operation.responses}
/> />
{(operation["x-events"]?.length || 0) > 0 && (
<TagsOperationDescriptionSectionEvents
events={operation["x-events"]!}
/>
)}
</> </>
) )
} }
@@ -36,6 +36,7 @@ export type TagOperationParametersObjectProps = {
schema: OpenAPI.SchemaObject schema: OpenAPI.SchemaObject
isRequired?: boolean isRequired?: boolean
topLevel?: boolean topLevel?: boolean
isExpanded?: boolean
} }
const TagOperationParametersObject = ({ const TagOperationParametersObject = ({
@@ -43,6 +44,7 @@ const TagOperationParametersObject = ({
schema, schema,
isRequired, isRequired,
topLevel = false, topLevel = false,
isExpanded = false,
}: TagOperationParametersObjectProps) => { }: TagOperationParametersObjectProps) => {
const isPropertiesEmpty = useMemo( const isPropertiesEmpty = useMemo(
() => !schema.properties || !Object.values(schema.properties).length, () => !schema.properties || !Object.values(schema.properties).length,
@@ -112,6 +114,7 @@ const TagOperationParametersObject = ({
properties[property].isRequired || properties[property].isRequired ||
checkRequired(schema, property) checkRequired(schema, property)
} }
isExpanded={isExpanded}
/> />
</Fragment> </Fragment>
))} ))}
@@ -141,6 +144,7 @@ const TagOperationParametersObject = ({
<Details <Details
summaryElm={getPropertyDescriptionElm(true)} summaryElm={getPropertyDescriptionElm(true)}
className="!border-y-0" className="!border-y-0"
openInitial={isExpanded}
> >
{getPropertyParameterElms(true)} {getPropertyParameterElms(true)}
</Details> </Details>
@@ -45,6 +45,7 @@ export type TagOperationParametersProps = {
topLevel?: boolean topLevel?: boolean
className?: string className?: string
isRequired?: boolean isRequired?: boolean
isExpanded?: boolean
} }
const TagOperationParameters = ({ const TagOperationParameters = ({
@@ -52,6 +53,7 @@ const TagOperationParameters = ({
className, className,
topLevel = false, topLevel = false,
isRequired: originalIsRequired = false, isRequired: originalIsRequired = false,
isExpanded = false,
}: TagOperationParametersProps) => { }: TagOperationParametersProps) => {
const isRequired = const isRequired =
originalIsRequired || checkRequired(schemaObject, schemaObject.title) originalIsRequired || checkRequired(schemaObject, schemaObject.title)
@@ -95,6 +97,7 @@ const TagOperationParameters = ({
schema={schemaObject} schema={schemaObject}
topLevel={topLevel} topLevel={topLevel}
isRequired={isRequired} isRequired={isRequired}
isExpanded={isExpanded}
/> />
) )
} }
+10
View File
@@ -22,6 +22,7 @@ export type Operation = OpenAPIV3.OperationObject<{
"x-featureFlag"?: string "x-featureFlag"?: string
"x-workflow"?: string "x-workflow"?: string
"x-sidebar-summary"?: string "x-sidebar-summary"?: string
"x-events"?: OasEvents[]
}> }>
export type RequestObject = OpenAPIV3.RequestBodyObject & { export type RequestObject = OpenAPIV3.RequestBodyObject & {
@@ -134,3 +135,12 @@ export type TagObject = OpenAPIV3.TagObject & {
export type ParsedPathItemObject = OpenAPIV3.PathItemObject<Operation> & { export type ParsedPathItemObject = OpenAPIV3.PathItemObject<Operation> & {
operationPath?: string operationPath?: string
} }
export type OasEvents = {
name: string
payload: string
description?: string
deprecated?: boolean
deprecated_message?: string
version?: string
}
@@ -2690,6 +2690,7 @@ class OasKindGenerator extends FunctionKindGenerator {
description: event.description, description: event.description,
deprecated: event.deprecated, deprecated: event.deprecated,
deprecated_message: event.deprecated_message, deprecated_message: event.deprecated_message,
version: event.version,
})) }))
) )
} }
@@ -46,4 +46,5 @@ export declare type OasEvent = {
description?: string description?: string
deprecated?: boolean deprecated?: boolean
deprecated_message?: string deprecated_message?: string
version?: string
} }
+1
View File
@@ -345,4 +345,5 @@ export declare type MedusaEvent = {
version?: string version?: string
deprecated?: boolean deprecated?: boolean
deprecated_message?: string deprecated_message?: string
version?: string
} }