diff --git a/packages/commons/fdr-utils/src/__test__/__snapshots__/octoai.test.ts.snap b/packages/commons/fdr-utils/src/__test__/__snapshots__/octoai.test.ts.snap index 9d14752e18..fea589bc6f 100644 --- a/packages/commons/fdr-utils/src/__test__/__snapshots__/octoai.test.ts.snap +++ b/packages/commons/fdr-utils/src/__test__/__snapshots__/octoai.test.ts.snap @@ -177,7 +177,7 @@ exports[`getNavigationRoot > octoai > gets navigation root for /api-reference/as "description": undefined, "hidden": false, "icon": undefined, - "id": "list", + "id": "subpackage_asset-library.list", "method": "GET", "slug": [ "api-reference", @@ -204,7 +204,7 @@ exports[`getNavigationRoot > octoai > gets navigation root for /api-reference/oc "description": "Return fields on an account", "hidden": false, "icon": undefined, - "id": "getAccount", + "id": "subpackage_account.getAccount", "method": "GET", "slug": [ "api-reference", diff --git a/packages/commons/fdr-utils/src/flattenApiDefinition.ts b/packages/commons/fdr-utils/src/flattenApiDefinition.ts index 1ec33fcbab..a2de30aa14 100644 --- a/packages/commons/fdr-utils/src/flattenApiDefinition.ts +++ b/packages/commons/fdr-utils/src/flattenApiDefinition.ts @@ -1,6 +1,7 @@ import { APIV1Read, DocsV1Read, FdrAPI } from "@fern-api/fdr-sdk"; import { isNonNullish, titleCase, visitDiscriminatedUnion } from "@fern-ui/core-utils"; import { stringifyEndpointPathParts } from "./stringifyEndpointPathParts"; +import { isSubpackage } from "./subpackage"; /** * Flattened API Definition lightly transforms the APIV1Read.ApiDefinition into a more usable format: @@ -200,10 +201,12 @@ function flattenPackage( const endpoints: FlattenedEndpointDefinition[] = []; const methodAndPathToEndpoint = new Map(); + const packageId = isSubpackage(currentPackage) ? currentPackage.subpackageId : "root"; + currentPackage.endpoints.forEach((endpoint) => { const flattenedEndpoint: FlattenedEndpointDefinition = { type: "endpoint", - id: endpoint.id, + id: endpoint.originalEndpointId ?? `${packageId}.${endpoint.id}`, slug: [...parentSlugs, endpoint.urlSlug], name: endpoint.name ?? stringifyEndpointPathParts(endpoint.path.parts), description: endpoint.description, @@ -251,7 +254,7 @@ function flattenPackage( const websockets = currentPackage.websockets.map( (websocket): FlattenedWebSocketChannel => ({ type: "websocket", - id: websocket.id, + id: `${packageId}.${websocket.id}`, slug: [...parentSlugs, websocket.urlSlug], name: websocket.name, description: websocket.description, @@ -272,7 +275,7 @@ function flattenPackage( const webhooks = currentPackage.webhooks.map( (webhook): FlattenedWebhookDefinition => ({ type: "webhook", - id: webhook.id, + id: `${packageId}.${webhook.id}`, slug: [...parentSlugs, webhook.urlSlug], name: webhook.name, description: webhook.description, diff --git a/packages/ui/app/src/api-page/endpoints/EndpointContentCodeSnippets.tsx b/packages/ui/app/src/api-page/endpoints/EndpointContentCodeSnippets.tsx index 98938df741..4fe27acfc2 100644 --- a/packages/ui/app/src/api-page/endpoints/EndpointContentCodeSnippets.tsx +++ b/packages/ui/app/src/api-page/endpoints/EndpointContentCodeSnippets.tsx @@ -173,7 +173,7 @@ const UnmemoizedEndpointContentCodeSnippets: React.FC diff --git a/packages/ui/app/src/api-playground/PlaygroundContext.tsx b/packages/ui/app/src/api-playground/PlaygroundContext.tsx index 78b7ffb08b..b48630a097 100644 --- a/packages/ui/app/src/api-playground/PlaygroundContext.tsx +++ b/packages/ui/app/src/api-playground/PlaygroundContext.tsx @@ -1,3 +1,4 @@ +import * as Sentry from "@sentry/nextjs"; import { useAtom } from "jotai"; import { atomWithStorage } from "jotai/utils"; import { mapValues, noop } from "lodash-es"; @@ -61,7 +62,7 @@ export const PlaygroundContextProvider: FC = ({ children }) = const { basePath } = useDocsContext(); const [selectionState, setSelectionState] = useState(); - const key = urljoin(basePath ?? "", "/api/fern-docs/resolve-api"); + const key = urljoin(basePath ?? "/", "/api/fern-docs/resolve-api"); const { data } = useSWR | null>(key, fetcher); useEffect(() => { @@ -90,14 +91,17 @@ export const PlaygroundContextProvider: FC = ({ children }) = async (newSelectionState: PlaygroundSelectionState) => { const matchedPackage = flattenedApis[newSelectionState.api]; if (matchedPackage == null) { + Sentry.captureMessage("Could not find package for API playground selection state", "fatal"); return; } if (newSelectionState.type === "endpoint") { const matchedEndpoint = matchedPackage.apiDefinitions.find( - (definition) => - isEndpoint(definition) && definition.slug.join("/") === newSelectionState.endpointId, + (definition) => isEndpoint(definition) && definition.id === newSelectionState.endpointId, ) as ResolvedApiDefinition.Endpoint | undefined; + if (matchedEndpoint == null) { + Sentry.captureMessage("Could not find endpoint for API playground selection state", "fatal"); + } setSelectionState(newSelectionState); expandPlayground(); capturePosthogEvent("api_playground_opened", { @@ -119,9 +123,11 @@ export const PlaygroundContextProvider: FC = ({ children }) = } } else if (newSelectionState.type === "websocket") { const matchedWebSocket = matchedPackage.apiDefinitions.find( - (definition) => - isWebSocket(definition) && definition.slug.join("/") === newSelectionState.webSocketId, + (definition) => isWebSocket(definition) && definition.id === newSelectionState.webSocketId, ) as ResolvedApiDefinition.Endpoint | undefined; + if (matchedWebSocket == null) { + Sentry.captureMessage("Could not find websocket for API playground selection state", "fatal"); + } setSelectionState(newSelectionState); expandPlayground(); capturePosthogEvent("api_playground_opened", { diff --git a/packages/ui/app/src/api-playground/PlaygroundDrawer.tsx b/packages/ui/app/src/api-playground/PlaygroundDrawer.tsx index 9610e705a0..c97d66e895 100644 --- a/packages/ui/app/src/api-playground/PlaygroundDrawer.tsx +++ b/packages/ui/app/src/api-playground/PlaygroundDrawer.tsx @@ -197,14 +197,14 @@ export const PlaygroundDrawer: FC = ({ apis }) => { const matchedEndpoint = selectionState?.type === "endpoint" ? (matchedSection?.apiDefinitions.find( - (definition) => isEndpoint(definition) && definition.slug.join("/") === selectionState.endpointId, + (definition) => isEndpoint(definition) && definition.id === selectionState.endpointId, ) as ResolvedApiDefinition.Endpoint | undefined) : undefined; const matchedWebSocket = selectionState?.type === "websocket" ? (matchedSection?.apiDefinitions.find( - (definition) => isWebSocket(definition) && definition.slug.join("/") === selectionState.webSocketId, + (definition) => isWebSocket(definition) && definition.id === selectionState.webSocketId, ) as ResolvedApiDefinition.WebSocket | undefined) : undefined; diff --git a/packages/ui/app/src/api-playground/PlaygroundEndpointSelectorContent.tsx b/packages/ui/app/src/api-playground/PlaygroundEndpointSelectorContent.tsx index 51ba72a82d..a8e2c92d7c 100644 --- a/packages/ui/app/src/api-playground/PlaygroundEndpointSelectorContent.tsx +++ b/packages/ui/app/src/api-playground/PlaygroundEndpointSelectorContent.tsx @@ -103,7 +103,7 @@ export const PlaygroundEndpointSelectorContent = forwardRef - matchesEndpoint(filterValue, apiGroup, endpoint), + const endpoints = apiGroup.items.filter( + (endpoint): endpoint is SidebarNode.ApiPage => + matchesEndpoint(filterValue, apiGroup, endpoint) && + (endpoint.apiType === "endpoint" || endpoint.apiType === "websocket"), ); if (endpoints.length === 0) { return null; diff --git a/packages/ui/app/src/resolver/__test__/__snapshots__/ApiDefinitionResolver.test.ts.snap b/packages/ui/app/src/resolver/__test__/__snapshots__/ApiDefinitionResolver.test.ts.snap index 5d50698f83..dcca7b3e46 100644 --- a/packages/ui/app/src/resolver/__test__/__snapshots__/ApiDefinitionResolver.test.ts.snap +++ b/packages/ui/app/src/resolver/__test__/__snapshots__/ApiDefinitionResolver.test.ts.snap @@ -28,7 +28,7 @@ exports[`resolveApiDefinition > should finish resolving 1`] = ` "errors": [], "examples": [], "headers": [], - "id": "getMerchants", + "id": "subpackage_merchants.getMerchants", "method": "GET", "path": [], "pathParameters": [],