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
2025-05-07 14:56:54 +03:00
committed by GitHub
parent 0dd4572964
commit 262064fe96
8 changed files with 166 additions and 0 deletions

View File

@@ -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>
)
}

View File

@@ -11,6 +11,7 @@ import { useArea } from "../../../../providers/area"
import { Feedback, Badge, Link, FeatureFlagNotice, H2 } from "docs-ui"
import { usePathname } from "next/navigation"
import { TagsOperationDescriptionSectionWorkflowBadgeProps } from "./WorkflowBadge"
import { TagsOperationDescriptionSectionEventsProps } from "./Events"
const TagsOperationDescriptionSectionSecurity =
dynamic<TagsOperationDescriptionSectionSecurityProps>(
@@ -32,6 +33,11 @@ const TagsOperationDescriptionSectionWorkflowBadge =
async () => import("./WorkflowBadge")
) as React.FC<TagsOperationDescriptionSectionWorkflowBadgeProps>
const TagsOperationDescriptionSectionEvents =
dynamic<TagsOperationDescriptionSectionEventsProps>(
async () => import("./Events")
) as React.FC<TagsOperationDescriptionSectionEventsProps>
type TagsOperationDescriptionSectionProps = {
operation: OpenAPI.Operation
}
@@ -103,6 +109,11 @@ const TagsOperationDescriptionSection = ({
<TagsOperationDescriptionSectionResponses
responses={operation.responses}
/>
{(operation["x-events"]?.length || 0) > 0 && (
<TagsOperationDescriptionSectionEvents
events={operation["x-events"]!}
/>
)}
</>
)
}

View File

@@ -36,6 +36,7 @@ export type TagOperationParametersObjectProps = {
schema: OpenAPI.SchemaObject
isRequired?: boolean
topLevel?: boolean
isExpanded?: boolean
}
const TagOperationParametersObject = ({
@@ -43,6 +44,7 @@ const TagOperationParametersObject = ({
schema,
isRequired,
topLevel = false,
isExpanded = false,
}: TagOperationParametersObjectProps) => {
const isPropertiesEmpty = useMemo(
() => !schema.properties || !Object.values(schema.properties).length,
@@ -112,6 +114,7 @@ const TagOperationParametersObject = ({
properties[property].isRequired ||
checkRequired(schema, property)
}
isExpanded={isExpanded}
/>
</Fragment>
))}
@@ -141,6 +144,7 @@ const TagOperationParametersObject = ({
<Details
summaryElm={getPropertyDescriptionElm(true)}
className="!border-y-0"
openInitial={isExpanded}
>
{getPropertyParameterElms(true)}
</Details>

View File

@@ -45,6 +45,7 @@ export type TagOperationParametersProps = {
topLevel?: boolean
className?: string
isRequired?: boolean
isExpanded?: boolean
}
const TagOperationParameters = ({
@@ -52,6 +53,7 @@ const TagOperationParameters = ({
className,
topLevel = false,
isRequired: originalIsRequired = false,
isExpanded = false,
}: TagOperationParametersProps) => {
const isRequired =
originalIsRequired || checkRequired(schemaObject, schemaObject.title)
@@ -95,6 +97,7 @@ const TagOperationParameters = ({
schema={schemaObject}
topLevel={topLevel}
isRequired={isRequired}
isExpanded={isExpanded}
/>
)
}

View File

@@ -22,6 +22,7 @@ export type Operation = OpenAPIV3.OperationObject<{
"x-featureFlag"?: string
"x-workflow"?: string
"x-sidebar-summary"?: string
"x-events"?: OasEvents[]
}>
export type RequestObject = OpenAPIV3.RequestBodyObject & {
@@ -134,3 +135,12 @@ export type TagObject = OpenAPIV3.TagObject & {
export type ParsedPathItemObject = OpenAPIV3.PathItemObject<Operation> & {
operationPath?: string
}
export type OasEvents = {
name: string
payload: string
description?: string
deprecated?: boolean
deprecated_message?: string
version?: string
}

View File

@@ -2690,6 +2690,7 @@ class OasKindGenerator extends FunctionKindGenerator {
description: event.description,
deprecated: event.deprecated,
deprecated_message: event.deprecated_message,
version: event.version,
}))
)
}

View File

@@ -46,4 +46,5 @@ export declare type OasEvent = {
description?: string
deprecated?: boolean
deprecated_message?: string
version?: string
}

View File

@@ -345,4 +345,5 @@ export declare type MedusaEvent = {
version?: string
deprecated?: boolean
deprecated_message?: string
version?: string
}