From 9e13b999c64537857fddc067753d43cec65436ab Mon Sep 17 00:00:00 2001
From: Rohin Bhargava <rohin@buildwithfern.com>
Date: Thu, 19 Dec 2024 22:18:02 +0000
Subject: [PATCH 01/11] docs dev

---
 packages/cli/cli/package.json                 |   2 +-
 packages/cli/cli/src/cli.ts                   |   8 +-
 .../src/commands/docs-dev/devDocsWorkspace.ts |   7 +-
 ...eOpenApiToFdrApiDefinitionForWorkspaces.ts |  54 +-------
 .../cli/configuration-loader/package.json     |   2 +-
 packages/cli/configuration/package.json       |   2 +-
 .../cli/docs-importers/commons/package.json   |   2 +-
 .../cli/docs-importers/mintlify/package.json  |   2 +-
 packages/cli/docs-markdown-utils/package.json |   2 +-
 packages/cli/docs-preview/package.json        |   2 +-
 packages/cli/docs-preview/src/previewDocs.ts  |  20 ++-
 .../cli/docs-preview/src/runPreviewServer.ts  |   8 +-
 packages/cli/docs-resolver/package.json       |   8 +-
 packages/cli/docs-resolver/src/index.ts       |   1 +
 .../utils/generateFdrFromOpenApiWorkspace.ts  |  52 ++++++++
 packages/cli/ete-tests/package.json           |   2 +-
 .../remote-workspace-runner/package.json      |   2 +-
 packages/cli/register/package.json            |   2 +-
 packages/core/package.json                    |   2 +-
 pnpm-lock.yaml                                | 121 ++++++++++++------
 20 files changed, 191 insertions(+), 110 deletions(-)
 create mode 100644 packages/cli/docs-resolver/src/utils/generateFdrFromOpenApiWorkspace.ts

diff --git a/packages/cli/cli/package.json b/packages/cli/cli/package.json
index 5e55db7a1cc..b06f1763b27 100644
--- a/packages/cli/cli/package.json
+++ b/packages/cli/cli/package.json
@@ -46,7 +46,7 @@
     "@fern-api/configuration-loader": "workspace:*",
     "@fern-api/core": "workspace:*",
     "@fern-api/core-utils": "workspace:*",
-    "@fern-api/docs-parsers": "^0.0.12",  
+    "@fern-api/docs-parsers": "^0.0.13",  
     "@fern-api/docs-preview": "workspace:*",
     "@fern-api/docs-resolver": "workspace:*",
     "@fern-api/docs-validator": "workspace:*", 
diff --git a/packages/cli/cli/src/cli.ts b/packages/cli/cli/src/cli.ts
index a015859b267..94d9c60d9b3 100644
--- a/packages/cli/cli/src/cli.ts
+++ b/packages/cli/cli/src/cli.ts
@@ -992,6 +992,10 @@ function addDocsPreviewCommand(cli: Argv<GlobalCliOptions>, cliContext: CliConte
                     string: true,
                     hidden: true,
                     description: "Path of the local docs bundle to use"
+                })
+                .option("v2", {
+                    boolean: true,
+                    description: "Use openapi parser v2"
                 }),
         async (argv) => {
             let port: number;
@@ -1001,6 +1005,7 @@ function addDocsPreviewCommand(cli: Argv<GlobalCliOptions>, cliContext: CliConte
                 port = await getPort({ port: [3000, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010] });
             }
             const bundlePath: string | undefined = argv.bundlePath;
+            const v2 = argv.v2;
             await previewDocsWorkspace({
                 loadProject: () =>
                     loadProjectAndRegisterWorkspacesWithContext(cliContext, {
@@ -1009,7 +1014,8 @@ function addDocsPreviewCommand(cli: Argv<GlobalCliOptions>, cliContext: CliConte
                     }),
                 cliContext,
                 port,
-                bundlePath
+                bundlePath,
+                v2
             });
         }
     );
diff --git a/packages/cli/cli/src/commands/docs-dev/devDocsWorkspace.ts b/packages/cli/cli/src/commands/docs-dev/devDocsWorkspace.ts
index 244231a0ac1..18660ebc2f8 100644
--- a/packages/cli/cli/src/commands/docs-dev/devDocsWorkspace.ts
+++ b/packages/cli/cli/src/commands/docs-dev/devDocsWorkspace.ts
@@ -8,12 +8,14 @@ export async function previewDocsWorkspace({
     loadProject,
     cliContext,
     port,
-    bundlePath
+    bundlePath,
+    v2
 }: {
     loadProject: () => Promise<Project>;
     cliContext: CliContext;
     port: number;
     bundlePath?: string;
+    v2?: boolean;
 }): Promise<void> {
     const project = await loadProject();
     const docsWorkspace = project.docsWorkspaces;
@@ -58,7 +60,8 @@ export async function previewDocsWorkspace({
             },
             context,
             port,
-            bundlePath
+            bundlePath,
+            v2
         });
     });
 }
diff --git a/packages/cli/cli/src/commands/generate-openapi-fdr/generateOpenApiToFdrApiDefinitionForWorkspaces.ts b/packages/cli/cli/src/commands/generate-openapi-fdr/generateOpenApiToFdrApiDefinitionForWorkspaces.ts
index d7df7f8c4f8..c1296f93ede 100644
--- a/packages/cli/cli/src/commands/generate-openapi-fdr/generateOpenApiToFdrApiDefinitionForWorkspaces.ts
+++ b/packages/cli/cli/src/commands/generate-openapi-fdr/generateOpenApiToFdrApiDefinitionForWorkspaces.ts
@@ -3,13 +3,7 @@ import { Project } from "@fern-api/project-loader";
 import { writeFile } from "fs/promises";
 import path from "path";
 import { CliContext } from "../../cli-context/CliContext";
-import { getAllOpenAPISpecs, LazyFernWorkspace, OSSWorkspace, OpenAPILoader } from "@fern-api/lazy-fern-workspace";
-// TODO: clean up imports
-import { OpenApiDocumentConverterNode } from "@fern-api/docs-parsers";
-import { ErrorCollector } from "@fern-api/docs-parsers";
-import { BaseOpenApiV3_1ConverterNodeContext } from "@fern-api/docs-parsers";
-import { OpenAPIV3_1 } from "openapi-types";
-import { merge } from "lodash-es";
+import { generateFdrFromOpenApiWorkspace } from "@fern-api/docs-resolver";
 
 export async function generateOpenApiToFdrApiDefinitionForWorkspaces({
     project,
@@ -23,49 +17,11 @@ export async function generateOpenApiToFdrApiDefinitionForWorkspaces({
     await Promise.all(
         project.apiWorkspaces.map(async (workspace) => {
             await cliContext.runTaskForWorkspace(workspace, async (context) => {
-                await cliContext.runTaskForWorkspace(workspace, async (context) => {
-                    if (workspace instanceof LazyFernWorkspace) {
-                        context.logger.info("Skipping, API is specified as a Fern Definition.");
-                        return;
-                    } else if (!(workspace instanceof OSSWorkspace)) {
-                        return;
-                    }
+                const fdrApiDefinition = await generateFdrFromOpenApiWorkspace(workspace, context);
 
-                    const openApiLoader = new OpenAPILoader(workspace.absoluteFilePath);
-                    const openApiSpecs = await getAllOpenAPISpecs({ context, specs: workspace.specs });
-
-                    const openApiDocuments = await openApiLoader.loadDocuments({ context, specs: openApiSpecs });
-
-                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
-                    let fdrApiDefinition: any;
-                    for (const openApi of openApiDocuments) {
-                        if (openApi.type !== "openapi") {
-                            continue;
-                        }
-
-                        const oasContext: BaseOpenApiV3_1ConverterNodeContext = {
-                            document: openApi.value as OpenAPIV3_1.Document,
-                            logger: context.logger,
-                            errors: new ErrorCollector()
-                        };
-
-                        const openApiFdrJson = new OpenApiDocumentConverterNode({
-                            input: openApi.value as OpenAPIV3_1.Document,
-                            context: oasContext,
-                            accessPath: [],
-                            pathId: workspace.workspaceName ?? "openapi parser"
-                        });
-
-                        fdrApiDefinition = merge(fdrApiDefinition, openApiFdrJson.convert());
-                    }
-
-                    const resolvedOutputFilePath = path.resolve(outputFilepath);
-                    await writeFile(
-                        resolvedOutputFilePath,
-                        await stringifyLargeObject(fdrApiDefinition, { pretty: true })
-                    );
-                    context.logger.info(`Wrote FDR API definition to ${resolvedOutputFilePath}`);
-                });
+                const resolvedOutputFilePath = path.resolve(outputFilepath);
+                await writeFile(resolvedOutputFilePath, await stringifyLargeObject(fdrApiDefinition, { pretty: true }));
+                context.logger.info(`Wrote FDR API definition to ${resolvedOutputFilePath}`);
             });
         })
     );
diff --git a/packages/cli/configuration-loader/package.json b/packages/cli/configuration-loader/package.json
index cd34c514fd6..f17c15b5027 100644
--- a/packages/cli/configuration-loader/package.json
+++ b/packages/cli/configuration-loader/package.json
@@ -33,7 +33,7 @@
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/task-context": "workspace:*",
     "@fern-api/fern-definition-schema": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.126.1-444264056",
+    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
     "@fern-fern/fiddle-sdk": "0.0.584",
     "@fern-fern/generators-sdk": "0.114.0-5745f9e74",
     "find-up": "^6.3.0",
diff --git a/packages/cli/configuration/package.json b/packages/cli/configuration/package.json
index 470e518a3b4..a974fa02743 100644
--- a/packages/cli/configuration/package.json
+++ b/packages/cli/configuration/package.json
@@ -31,7 +31,7 @@
     "@fern-api/core-utils": "workspace:*",
     "@fern-api/path-utils": "workspace:*",
     "@fern-api/fern-definition-schema": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.126.1-444264056",
+    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
     "@fern-fern/fiddle-sdk": "0.0.584",
     "zod": "^3.22.3"
   },
diff --git a/packages/cli/docs-importers/commons/package.json b/packages/cli/docs-importers/commons/package.json
index c35763532bb..5586b6810d0 100644
--- a/packages/cli/docs-importers/commons/package.json
+++ b/packages/cli/docs-importers/commons/package.json
@@ -31,7 +31,7 @@
     "@fern-api/configuration": "workspace:*",
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/task-context": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.126.1-444264056",
+    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
     "js-yaml": "^4.1.0"
   },
   "devDependencies": {
diff --git a/packages/cli/docs-importers/mintlify/package.json b/packages/cli/docs-importers/mintlify/package.json
index a77bd52b3c4..1a6663ad16c 100644
--- a/packages/cli/docs-importers/mintlify/package.json
+++ b/packages/cli/docs-importers/mintlify/package.json
@@ -34,7 +34,7 @@
     "@fern-api/task-context": "workspace:*",
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/logger": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.126.1-444264056",
+    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
     "gray-matter": "^4.0.3"
   },
   "devDependencies": {
diff --git a/packages/cli/docs-markdown-utils/package.json b/packages/cli/docs-markdown-utils/package.json
index 3e157089867..b59d51c478f 100644
--- a/packages/cli/docs-markdown-utils/package.json
+++ b/packages/cli/docs-markdown-utils/package.json
@@ -30,7 +30,7 @@
   "dependencies": {
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/task-context": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.126.1-444264056",
+    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
     "gray-matter": "^4.0.3",
     "mdast-util-from-markdown": "^2.0.1",
     "mdast-util-mdx": "^3.0.0",
diff --git a/packages/cli/docs-preview/package.json b/packages/cli/docs-preview/package.json
index 9342d7e2369..f24e91e0df7 100644
--- a/packages/cli/docs-preview/package.json
+++ b/packages/cli/docs-preview/package.json
@@ -29,7 +29,7 @@
   },
   "dependencies": {
     "@fern-api/docs-resolver": "workspace:*",
-    "@fern-api/fdr-sdk": "0.126.1-444264056",
+    "@fern-api/fdr-sdk": "0.127.3-6479103bd",
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/ir-sdk": "workspace:*",
     "@fern-api/logger": "workspace:*",
diff --git a/packages/cli/docs-preview/src/previewDocs.ts b/packages/cli/docs-preview/src/previewDocs.ts
index 26fb2132da9..f738fc46b35 100644
--- a/packages/cli/docs-preview/src/previewDocs.ts
+++ b/packages/cli/docs-preview/src/previewDocs.ts
@@ -18,15 +18,19 @@ import { Project } from "@fern-api/project-loader";
 import { convertIrToFdrApi } from "@fern-api/register";
 import { TaskContext } from "@fern-api/task-context";
 import { v4 as uuidv4 } from "uuid";
+import { generateFdrFromOpenApiWorkspace } from "@fern-api/docs-resolver";
+import { isNonNullish } from "../../../commons/core-utils/src";
 
 export async function getPreviewDocsDefinition({
     domain,
     project,
-    context
+    context,
+    v2
 }: {
     domain: string;
     project: Project;
     context: TaskContext;
+    v2?: boolean;
 }): Promise<DocsV1Read.DocsDefinition> {
     const docsWorkspace = project.docsWorkspaces;
     const apiWorkspaces = project.apiWorkspaces;
@@ -80,7 +84,19 @@ export async function getPreviewDocsDefinition({
     });
 
     return {
-        apis: apiCollector.getAPIsForDefinition(),
+        apis: v2 ? {} : apiCollector.getAPIsForDefinition(),
+        apisV2: v2
+            ? Object.fromEntries(
+                  (
+                      await Promise.all(
+                          fernWorkspaces.map((workspace) => [
+                              uuidv4(),
+                              generateFdrFromOpenApiWorkspace(workspace, context)
+                          ])
+                      )
+                  ).filter(isNonNullish)
+              )
+            : {},
         config: readDocsConfig,
         files: {},
         filesV2,
diff --git a/packages/cli/docs-preview/src/runPreviewServer.ts b/packages/cli/docs-preview/src/runPreviewServer.ts
index 3c9433fcafb..7ec931e916c 100644
--- a/packages/cli/docs-preview/src/runPreviewServer.ts
+++ b/packages/cli/docs-preview/src/runPreviewServer.ts
@@ -16,6 +16,7 @@ import { getPreviewDocsDefinition } from "./previewDocs";
 const EMPTY_DOCS_DEFINITION: DocsV1Read.DocsDefinition = {
     pages: {},
     apis: {},
+    apisV2: {},
     files: {},
     filesV2: {},
     config: {
@@ -54,7 +55,8 @@ export async function runPreviewServer({
     validateProject,
     context,
     port,
-    bundlePath
+    bundlePath,
+    v2
 }: {
     initialProject: Project;
     reloadProject: () => Promise<Project>;
@@ -62,6 +64,7 @@ export async function runPreviewServer({
     context: TaskContext;
     port: number;
     bundlePath?: string;
+    v2?: boolean;
 }): Promise<void> {
     if (bundlePath != null) {
         context.logger.info(`Using bundle from path: ${bundlePath}`);
@@ -128,7 +131,8 @@ export async function runPreviewServer({
             const newDocsDefinition = await getPreviewDocsDefinition({
                 domain: `${instance.host}${instance.pathname}`,
                 project,
-                context
+                context,
+                v2
             });
             context.logger.info(`Reload completed in ${Date.now() - startTime}ms`);
             return newDocsDefinition;
diff --git a/packages/cli/docs-resolver/package.json b/packages/cli/docs-resolver/package.json
index 0e874efb46a..d879ff37de4 100644
--- a/packages/cli/docs-resolver/package.json
+++ b/packages/cli/docs-resolver/package.json
@@ -27,12 +27,15 @@
     "depcheck": "depcheck"
   },
   "dependencies": {
+    "@fern-api/api-workspace-commons": "workspace:*",
     "@fern-api/cli-source-resolver": "workspace:*",
     "@fern-api/configuration-loader": "workspace:*",
     "@fern-api/core-utils": "workspace:*",
     "@fern-api/docs-markdown-utils": "workspace:*",
-    "@fern-api/fdr-sdk": "0.126.1-444264056",
-    "@fern-api/ui-core-utils": "0.126.1-444264056",
+    "@fern-api/docs-parsers": "^0.0.13",
+    "@fern-api/fdr-sdk": "0.127.3-6479103bd",
+    "@fern-api/lazy-fern-workspace": "workspace:*",
+    "@fern-api/ui-core-utils": "0.127.3-6479103bd",
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/ir-generator": "workspace:*",
     "@fern-api/ir-sdk": "workspace:*",
@@ -49,6 +52,7 @@
     "@types/node": "18.7.18",
     "depcheck": "^1.4.6",
     "eslint": "^8.56.0",
+    "openapi-types": "^10.0.0",
     "organize-imports-cli": "^0.10.0",
     "prettier": "^2.7.1",
     "typescript": "4.6.4",
diff --git a/packages/cli/docs-resolver/src/index.ts b/packages/cli/docs-resolver/src/index.ts
index a6692d7a13e..cc615757fb1 100644
--- a/packages/cli/docs-resolver/src/index.ts
+++ b/packages/cli/docs-resolver/src/index.ts
@@ -1,2 +1,3 @@
 export { DocsDefinitionResolver, type UploadedFile } from "./DocsDefinitionResolver";
 export { wrapWithHttps } from "./wrapWithHttps";
+export { generateFdrFromOpenApiWorkspace } from "./utils/generateFdrFromOpenApiWorkspace";
diff --git a/packages/cli/docs-resolver/src/utils/generateFdrFromOpenApiWorkspace.ts b/packages/cli/docs-resolver/src/utils/generateFdrFromOpenApiWorkspace.ts
new file mode 100644
index 00000000000..d67cb531b35
--- /dev/null
+++ b/packages/cli/docs-resolver/src/utils/generateFdrFromOpenApiWorkspace.ts
@@ -0,0 +1,52 @@
+import { getAllOpenAPISpecs, LazyFernWorkspace, OSSWorkspace, OpenAPILoader } from "@fern-api/lazy-fern-workspace";
+import {
+    ErrorCollector,
+    OpenApiDocumentConverterNode,
+    BaseOpenApiV3_1ConverterNodeContext
+} from "@fern-api/docs-parsers";
+import { OpenAPIV3_1 } from "openapi-types";
+import { merge } from "lodash-es";
+import { AbstractAPIWorkspace } from "@fern-api/api-workspace-commons";
+import { TaskContext } from "@fern-api/task-context";
+
+export async function generateFdrFromOpenApiWorkspace(
+    workspace: AbstractAPIWorkspace<unknown>,
+    context: TaskContext
+): Promise<ReturnType<OpenApiDocumentConverterNode["convert"]>> {
+    if (workspace instanceof LazyFernWorkspace) {
+        context.logger.info("Skipping, API is specified as a Fern Definition.");
+        return;
+    } else if (!(workspace instanceof OSSWorkspace)) {
+        return;
+    }
+
+    const openApiLoader = new OpenAPILoader(workspace.absoluteFilePath);
+    const openApiSpecs = await getAllOpenAPISpecs({ context, specs: workspace.specs });
+
+    const openApiDocuments = await openApiLoader.loadDocuments({ context, specs: openApiSpecs });
+
+    // // eslint-disable-next-line @typescript-eslint/no-explicit-any
+    let fdrApiDefinition: ReturnType<OpenApiDocumentConverterNode["convert"]>;
+    for (const openApi of openApiDocuments) {
+        if (openApi.type !== "openapi") {
+            continue;
+        }
+
+        const oasContext: BaseOpenApiV3_1ConverterNodeContext = {
+            document: openApi.value as OpenAPIV3_1.Document,
+            logger: context.logger,
+            errors: new ErrorCollector()
+        };
+
+        const openApiFdrJson = new OpenApiDocumentConverterNode({
+            input: openApi.value as OpenAPIV3_1.Document,
+            context: oasContext,
+            accessPath: [],
+            pathId: workspace.workspaceName ?? "openapi parser"
+        });
+
+        fdrApiDefinition = merge(fdrApiDefinition, openApiFdrJson.convert());
+    }
+
+    return fdrApiDefinition;
+}
diff --git a/packages/cli/ete-tests/package.json b/packages/cli/ete-tests/package.json
index a67311c1f82..59a36fa6329 100644
--- a/packages/cli/ete-tests/package.json
+++ b/packages/cli/ete-tests/package.json
@@ -29,7 +29,7 @@
   },
   "dependencies": {
     "@fern-api/configuration": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.126.1-444264056",
+    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/logging-execa": "workspace:*",
     "@fern-typescript/fetcher": "workspace:*",
diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/package.json b/packages/cli/generation/remote-generation/remote-workspace-runner/package.json
index 042dbc724a6..5d3c27eb9ae 100644
--- a/packages/cli/generation/remote-generation/remote-workspace-runner/package.json
+++ b/packages/cli/generation/remote-generation/remote-workspace-runner/package.json
@@ -35,7 +35,7 @@
     "@fern-api/core-utils": "workspace:*",
     "@fern-api/docs-resolver": "workspace:*",
     "@fern-api/logging-execa": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.126.1-444264056",
+    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/ir-generator": "workspace:*",
     "@fern-api/ir-migrations": "workspace:*",
diff --git a/packages/cli/register/package.json b/packages/cli/register/package.json
index 8daa14d587d..ec70d43f350 100644
--- a/packages/cli/register/package.json
+++ b/packages/cli/register/package.json
@@ -33,7 +33,7 @@
     "@fern-api/configuration": "workspace:*",
     "@fern-api/core": "workspace:*",
     "@fern-api/core-utils": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.126.1-444264056",
+    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/ir-generator": "workspace:*",
     "@fern-api/ir-sdk": "workspace:*",
diff --git a/packages/core/package.json b/packages/core/package.json
index 6a52b4380fa..cc5200e19ee 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -28,7 +28,7 @@
     "depcheck": "depcheck"
   },
   "dependencies": {
-    "@fern-fern/fdr-cjs-sdk": "0.126.1-444264056",
+    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd", 
     "@fern-fern/generators-sdk": "0.114.0-5745f9e74",
     "@fern-api/venus-api-sdk": "0.10.2",
     "@fern-fern/fdr-test-sdk": "^0.0.5297",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1cb3f71d27e..e42e9112998 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -3856,8 +3856,8 @@ importers:
         specifier: workspace:*
         version: link:../../commons/core-utils
       '@fern-api/docs-parsers':
-        specifier: ^0.0.12
-        version: 0.0.12(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)
+        specifier: ^0.0.13
+        version: 0.0.13(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)
       '@fern-api/docs-preview':
         specifier: workspace:*
         version: link:../docs-preview
@@ -4225,6 +4225,8 @@ importers:
         specifier: ^2.1.4
         version: 2.1.4(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)
 
+  packages/cli/cli/dist/local: {}
+
   packages/cli/configuration:
     dependencies:
       '@fern-api/core-utils':
@@ -4237,8 +4239,8 @@ importers:
         specifier: workspace:*
         version: link:../../commons/path-utils
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.126.1-444264056
-        version: 0.126.1-444264056
+        specifier: 0.127.3-6479103bd
+        version: 0.127.3-6479103bd
       '@fern-fern/fiddle-sdk':
         specifier: 0.0.584
         version: 0.0.584
@@ -4286,8 +4288,8 @@ importers:
         specifier: workspace:*
         version: link:../task-context
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.126.1-444264056
-        version: 0.126.1-444264056
+        specifier: 0.127.3-6479103bd
+        version: 0.127.3-6479103bd
       '@fern-fern/fiddle-sdk':
         specifier: 0.0.584
         version: 0.0.584
@@ -4362,8 +4364,8 @@ importers:
         specifier: workspace:*
         version: link:../../task-context
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.126.1-444264056
-        version: 0.126.1-444264056
+        specifier: 0.127.3-6479103bd
+        version: 0.127.3-6479103bd
       js-yaml:
         specifier: ^4.1.0
         version: 4.1.0
@@ -4414,8 +4416,8 @@ importers:
         specifier: workspace:*
         version: link:../../task-context
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.126.1-444264056
-        version: 0.126.1-444264056
+        specifier: 0.127.3-6479103bd
+        version: 0.127.3-6479103bd
       gray-matter:
         specifier: ^4.0.3
         version: 4.0.3
@@ -4451,8 +4453,8 @@ importers:
         specifier: workspace:*
         version: link:../task-context
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.126.1-444264056
-        version: 0.126.1-444264056
+        specifier: 0.127.3-6479103bd
+        version: 0.127.3-6479103bd
       gray-matter:
         specifier: ^4.0.3
         version: 4.0.3
@@ -4506,8 +4508,8 @@ importers:
         specifier: workspace:*
         version: link:../docs-resolver
       '@fern-api/fdr-sdk':
-        specifier: 0.126.1-444264056
-        version: 0.126.1-444264056(typescript@4.6.4)
+        specifier: 0.127.3-6479103bd
+        version: 0.127.3-6479103bd(typescript@4.6.4)
       '@fern-api/fs-utils':
         specifier: workspace:*
         version: link:../../commons/fs-utils
@@ -4605,6 +4607,9 @@ importers:
 
   packages/cli/docs-resolver:
     dependencies:
+      '@fern-api/api-workspace-commons':
+        specifier: workspace:*
+        version: link:../workspace/commons
       '@fern-api/cli-source-resolver':
         specifier: workspace:*
         version: link:../cli-source-resolver
@@ -4617,9 +4622,12 @@ importers:
       '@fern-api/docs-markdown-utils':
         specifier: workspace:*
         version: link:../docs-markdown-utils
+      '@fern-api/docs-parsers':
+        specifier: ^0.0.13
+        version: 0.0.13(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)
       '@fern-api/fdr-sdk':
-        specifier: 0.126.1-444264056
-        version: 0.126.1-444264056(typescript@4.6.4)
+        specifier: 0.127.3-6479103bd
+        version: 0.127.3-6479103bd(typescript@4.6.4)
       '@fern-api/fs-utils':
         specifier: workspace:*
         version: link:../../commons/fs-utils
@@ -4629,6 +4637,9 @@ importers:
       '@fern-api/ir-sdk':
         specifier: workspace:*
         version: link:../../ir-sdk
+      '@fern-api/lazy-fern-workspace':
+        specifier: workspace:*
+        version: link:../workspace/lazy-fern-workspace
       '@fern-api/register':
         specifier: workspace:*
         version: link:../register
@@ -4636,8 +4647,8 @@ importers:
         specifier: workspace:*
         version: link:../task-context
       '@fern-api/ui-core-utils':
-        specifier: 0.126.1-444264056
-        version: 0.126.1-444264056
+        specifier: 0.127.3-6479103bd
+        version: 0.127.3-6479103bd
       dayjs:
         specifier: ^1.11.11
         version: 1.11.11
@@ -4666,6 +4677,9 @@ importers:
       eslint:
         specifier: ^8.56.0
         version: 8.56.0
+      openapi-types:
+        specifier: ^10.0.0
+        version: 10.0.0
       organize-imports-cli:
         specifier: ^0.10.0
         version: 0.10.0
@@ -4691,8 +4705,8 @@ importers:
         specifier: workspace:*
         version: link:../../commons/logging-execa
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.126.1-444264056
-        version: 0.126.1-444264056
+        specifier: 0.127.3-6479103bd
+        version: 0.127.3-6479103bd
       '@fern-typescript/fetcher':
         specifier: workspace:*
         version: link:../../../generators/typescript/utils/core-utilities/fetcher
@@ -5495,8 +5509,8 @@ importers:
         specifier: workspace:*
         version: link:../../../workspace/loader
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.126.1-444264056
-        version: 0.126.1-444264056
+        specifier: 0.127.3-6479103bd
+        version: 0.127.3-6479103bd
       '@fern-fern/fiddle-sdk':
         specifier: 0.0.584
         version: 0.0.584
@@ -5965,8 +5979,8 @@ importers:
         specifier: workspace:*
         version: link:../task-context
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.126.1-444264056
-        version: 0.126.1-444264056
+        specifier: 0.127.3-6479103bd
+        version: 0.127.3-6479103bd
       lodash-es:
         specifier: ^4.17.21
         version: 4.17.21
@@ -6743,8 +6757,8 @@ importers:
         specifier: 0.10.2
         version: 0.10.2
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.126.1-444264056
-        version: 0.126.1-444264056
+        specifier: 0.127.3-6479103bd
+        version: 0.127.3-6479103bd
       '@fern-fern/fdr-test-sdk':
         specifier: ^0.0.5297
         version: 0.0.5297
@@ -8080,8 +8094,8 @@ packages:
   '@fern-api/core-utils@0.4.24-rc1':
     resolution: {integrity: sha512-aYu4lQK2qZIKzTF9TeFrICTPJ/zGEZUEWQmZt6pJeHu+R6afrcCBNkUleWU1OpHlDbe+xXUUBOktRg0PM9Hywg==}
 
-  '@fern-api/docs-parsers@0.0.12':
-    resolution: {integrity: sha512-bTnhztE8xZlnyzm3lvnvv+DGGup81qD/A8k2f9OP4I9kxzGsR7p/U/OnEDD+ztXWvlemdH7QxKLjzVmZBLLeJg==}
+  '@fern-api/docs-parsers@0.0.13':
+    resolution: {integrity: sha512-pmMUD28tWPGutTGDR2Q8vx/3v9YHlYMCUP2uVsI94Qam51Pm/uPVFikYoPrSxDYfG1NNcxGVddC7FKW18S99Xw==}
 
   '@fern-api/dynamic-ir-sdk@53.24.0':
     resolution: {integrity: sha512-4XvzvSsh7lNZz5oYN0LH+FRpFGxg9TjfdipSJMpgHvPShe85m/tcfbOzbS0DHBpQGlKb/gHQtQRPAoBR1wdDAw==}
@@ -8089,8 +8103,8 @@ packages:
   '@fern-api/dynamic-ir-sdk@54.0.0':
     resolution: {integrity: sha512-5ewX7042AGuw697jA6ubulCIQbfTM2HC8UbHxTakE0px871HJTRwHNT2Y9o2kjMbsRXTzyYdb5lOVr+85sc/KQ==}
 
-  '@fern-api/fdr-sdk@0.126.1-444264056':
-    resolution: {integrity: sha512-Xl1Ctteav1GOulX40756FLEoJAI7VCn6zgkdDb6RRSZhm9Z8fjaBRv/cdMo1saupqHNd62Hm5b8FdmGjwWFAPw==}
+  '@fern-api/fdr-sdk@0.127.3-6479103bd':
+    resolution: {integrity: sha512-9WPubeQHSQJ2ece9lG2TY4Rc879e7AhvDYOamlYqsD5gy16eATRUkOvj7d6pWch5JwYJaMM8jcdZrQ9dltf/qQ==}
 
   '@fern-api/logger@0.4.24-rc1':
     resolution: {integrity: sha512-yh0E2F3K3IPnJZcE4dv+u8I51iKgTgv/reinKo4K5YmYEG1iLtw5vBEYMOPkQmsYFPAKIh++OMB/6TrsahMWew==}
@@ -8104,8 +8118,8 @@ packages:
   '@fern-api/ui-core-utils@0.0.0':
     resolution: {integrity: sha512-8T3YLd+n8z5Vs+WNRIwH6PUW31ZC4/lkRD5G2+qyBcdePfOVYV3CHp3eiUrSSArOr0SJmzN/mQwPm3iAaey7nw==}
 
-  '@fern-api/ui-core-utils@0.126.1-444264056':
-    resolution: {integrity: sha512-9L3Tgl83nGaw9Jug17ZXSkPL7ZTeOP3SukG/Fz2Y2Aa/GqEToCrexuGkTO090nwuv2zO9gi7CYDHvQOEl5IIMQ==}
+  '@fern-api/ui-core-utils@0.127.3-6479103bd':
+    resolution: {integrity: sha512-WLrD3Ad2zzPGfVickTiJ1JoKN97Px9Dzu+Zl8oHcreIdf3Ngmf5LH/jCcwRx7LenRKdRj6+UMFBxA1ZdVDg3ng==}
 
   '@fern-api/venus-api-sdk@0.10.2':
     resolution: {integrity: sha512-BD18ZNJeWYvztRXSUWY2lfZ8jFUbNAfHWctvIsWyXgI7C8EL3N0+CWUGD5cZ1QqRnq42nm6XJdWRKhny3yrz4g==}
@@ -8113,8 +8127,8 @@ packages:
   '@fern-fern/docs-config@0.0.80':
     resolution: {integrity: sha512-wAZCNxwM4qIPn3idoIihPP65KWPjNuoTSfdP4+5f8K2jJLgs5cdkY0pm4cQlGWvi5K6b+lfbUWDaslnXscJ2gQ==}
 
-  '@fern-fern/fdr-cjs-sdk@0.126.1-444264056':
-    resolution: {integrity: sha512-APStUB4pA/H620WMm/K6uyCtk7hxXB4ZuroY+VIfLexpieC39ZSHeN6DlpbuG/vPkF6LUtnpYlfWxGpEVCmhrw==}
+  '@fern-fern/fdr-cjs-sdk@0.127.3-6479103bd':
+    resolution: {integrity: sha512-nYpgLaorgK0s+6P6iKC8TYa4QF4RjZxr4y5/jogpkQc74sm2fmZq7vpRiCTmr9wt+Ei6EZqbemqvULh6G8y25g==}
 
   '@fern-fern/fdr-test-sdk@0.0.5297':
     resolution: {integrity: sha512-jrZUZ6oIA64LHtrv77xEq0X7qJhT9xRMGWhKcLjIUArMsD7h6KMWUHVdoB/1MP0Mz/uL/E2xmM31SOgJicpIcA==}
@@ -9921,6 +9935,14 @@ packages:
     resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==}
     engines: {node: '>= 0.4'}
 
+  date-fns-tz@3.2.0:
+    resolution: {integrity: sha512-sg8HqoTEulcbbbVXeg84u5UnlsQa8GS5QXMqjjYIhS4abEVVKIUwe0/l/UhrZdKaL/W5eWZNlbTeEIiOXTcsBQ==}
+    peerDependencies:
+      date-fns: ^3.0.0 || ^4.0.0
+
+  date-fns@4.1.0:
+    resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
+
   dayjs@1.11.11:
     resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==}
 
@@ -10230,6 +10252,9 @@ packages:
   es-toolkit@1.26.0:
     resolution: {integrity: sha512-gg6ZaI4eTwzkQGkdEG+t4b4VH2mTxodBQ2KvyTKAQFIag3Vvxoq3XZ1ie4ijIQmVxiipL2+dZLDMkh1VIvAFyg==}
 
+  es-toolkit@1.30.1:
+    resolution: {integrity: sha512-ZXflqanzH8BpHkDhFa10bBf6ONDCe84EPUm7SSICGzuuROSluT2ynTPtwn9PcRelMtorCRozSknI/U0MNYp0Uw==}
+
   es6-promise@3.3.1:
     resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
 
@@ -12159,6 +12184,9 @@ packages:
     resolution: {integrity: sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==}
     engines: {node: '>=12'}
 
+  openapi-types@10.0.0:
+    resolution: {integrity: sha512-Y8xOCT2eiKGYDzMW9R4x5cmfc3vGaaI4EL2pwhDmodWw1HlK18YcZ4uJxc7Rdp7/gGzAygzH9SXr6GKYIXbRcQ==}
+
   openapi-types@12.1.3:
     resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==}
 
@@ -15208,11 +15236,10 @@ snapshots:
       lodash-es: 4.17.21
       strip-ansi: 7.1.0
 
-  '@fern-api/docs-parsers@0.0.12(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)':
+  '@fern-api/docs-parsers@0.0.13(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)':
     dependencies:
       '@fern-api/logger': 0.4.24-rc1
       '@fern-api/ui-core-utils': 0.0.0
-      ajv: 8.17.1
       es-toolkit: 1.26.0
       openapi-types: 12.1.3
       ts-essentials: 10.0.1(typescript@4.6.4)
@@ -15241,12 +15268,12 @@ snapshots:
 
   '@fern-api/dynamic-ir-sdk@54.0.0': {}
 
-  '@fern-api/fdr-sdk@0.126.1-444264056(typescript@4.6.4)':
+  '@fern-api/fdr-sdk@0.127.3-6479103bd(typescript@4.6.4)':
     dependencies:
-      '@fern-api/ui-core-utils': 0.126.1-444264056
+      '@fern-api/ui-core-utils': 0.127.3-6479103bd
       '@ungap/structured-clone': 1.2.0
       dayjs: 1.11.11
-      es-toolkit: 1.26.0
+      es-toolkit: 1.30.1
       fast-deep-equal: 3.1.3
       form-data: 4.0.0
       formdata-node: 6.0.3
@@ -15288,8 +15315,10 @@ snapshots:
       title: 3.5.3
       ua-parser-js: 1.0.37
 
-  '@fern-api/ui-core-utils@0.126.1-444264056':
+  '@fern-api/ui-core-utils@0.127.3-6479103bd':
     dependencies:
+      date-fns: 4.1.0
+      date-fns-tz: 3.2.0(date-fns@4.1.0)
       strip-ansi: 7.1.0
       title: 3.5.3
       ua-parser-js: 1.0.37
@@ -15308,7 +15337,7 @@ snapshots:
 
   '@fern-fern/docs-config@0.0.80': {}
 
-  '@fern-fern/fdr-cjs-sdk@0.126.1-444264056':
+  '@fern-fern/fdr-cjs-sdk@0.127.3-6479103bd':
     dependencies:
       form-data: 4.0.0
       formdata-node: 6.0.3
@@ -17470,6 +17499,12 @@ snapshots:
       es-errors: 1.3.0
       is-data-view: 1.0.1
 
+  date-fns-tz@3.2.0(date-fns@4.1.0):
+    dependencies:
+      date-fns: 4.1.0
+
+  date-fns@4.1.0: {}
+
   dayjs@1.11.11: {}
 
   debug@2.6.9:
@@ -17812,6 +17847,8 @@ snapshots:
 
   es-toolkit@1.26.0: {}
 
+  es-toolkit@1.30.1: {}
+
   es6-promise@3.3.1: {}
 
   esbuild@0.21.5:
@@ -20433,6 +20470,8 @@ snapshots:
       is-docker: 2.2.1
       is-wsl: 2.2.0
 
+  openapi-types@10.0.0: {}
+
   openapi-types@12.1.3: {}
 
   optionator@0.9.3:

From 1607ad2835ac0c8b32c215af294711e7e391bab4 Mon Sep 17 00:00:00 2001
From: Rohin Bhargava <rohin@buildwithfern.com>
Date: Fri, 20 Dec 2024 02:33:35 +0000
Subject: [PATCH 02/11] correlate IDs properly, docs dev working

---
 packages/cli/cli/package.json                |  2 +-
 packages/cli/docs-preview/src/previewDocs.ts | 15 ++++++++++----
 packages/cli/docs-resolver/package.json      |  2 +-
 pnpm-lock.yaml                               | 21 ++++++++------------
 4 files changed, 21 insertions(+), 19 deletions(-)

diff --git a/packages/cli/cli/package.json b/packages/cli/cli/package.json
index b06f1763b27..bf5b094e129 100644
--- a/packages/cli/cli/package.json
+++ b/packages/cli/cli/package.json
@@ -46,7 +46,7 @@
     "@fern-api/configuration-loader": "workspace:*",
     "@fern-api/core": "workspace:*",
     "@fern-api/core-utils": "workspace:*",
-    "@fern-api/docs-parsers": "^0.0.13",  
+    "@fern-api/docs-parsers": "^0.0.14",  
     "@fern-api/docs-preview": "workspace:*",
     "@fern-api/docs-resolver": "workspace:*",
     "@fern-api/docs-validator": "workspace:*", 
diff --git a/packages/cli/docs-preview/src/previewDocs.ts b/packages/cli/docs-preview/src/previewDocs.ts
index f738fc46b35..8a14568abba 100644
--- a/packages/cli/docs-preview/src/previewDocs.ts
+++ b/packages/cli/docs-preview/src/previewDocs.ts
@@ -48,6 +48,9 @@ export async function getPreviewDocsDefinition({
         )
     );
 
+    // TODO: remove this once we remove V1 API generation
+    const apiDefinitionIds: FdrAPI.ApiDefinitionId[] = [];
+
     const apiCollector = new ReferencedAPICollector(context);
 
     const filesV2: Record<string, DocsV1Read.File_> = {};
@@ -71,7 +74,11 @@ export async function getPreviewDocsDefinition({
                     fileId
                 };
             }),
-        async (opts) => apiCollector.addReferencedAPI(opts)
+        async (opts) => {
+            const id = apiCollector.addReferencedAPI(opts);
+            apiDefinitionIds.push(FdrAPI.ApiDefinitionId(id));
+            return id;
+        }
     );
 
     const writeDocsDefinition = await resolver.resolve();
@@ -89,9 +96,9 @@ export async function getPreviewDocsDefinition({
             ? Object.fromEntries(
                   (
                       await Promise.all(
-                          fernWorkspaces.map((workspace) => [
-                              uuidv4(),
-                              generateFdrFromOpenApiWorkspace(workspace, context)
+                          project.apiWorkspaces.map(async (workspace, i) => [
+                              apiDefinitionIds[i],
+                              await generateFdrFromOpenApiWorkspace(workspace, context)
                           ])
                       )
                   ).filter(isNonNullish)
diff --git a/packages/cli/docs-resolver/package.json b/packages/cli/docs-resolver/package.json
index d879ff37de4..0c1544ed3e0 100644
--- a/packages/cli/docs-resolver/package.json
+++ b/packages/cli/docs-resolver/package.json
@@ -32,7 +32,7 @@
     "@fern-api/configuration-loader": "workspace:*",
     "@fern-api/core-utils": "workspace:*",
     "@fern-api/docs-markdown-utils": "workspace:*",
-    "@fern-api/docs-parsers": "^0.0.13",
+    "@fern-api/docs-parsers": "^0.0.14",
     "@fern-api/fdr-sdk": "0.127.3-6479103bd",
     "@fern-api/lazy-fern-workspace": "workspace:*",
     "@fern-api/ui-core-utils": "0.127.3-6479103bd",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e42e9112998..bf8dd41766a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -3856,8 +3856,8 @@ importers:
         specifier: workspace:*
         version: link:../../commons/core-utils
       '@fern-api/docs-parsers':
-        specifier: ^0.0.13
-        version: 0.0.13(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)
+        specifier: ^0.0.14
+        version: 0.0.14(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)
       '@fern-api/docs-preview':
         specifier: workspace:*
         version: link:../docs-preview
@@ -4623,8 +4623,8 @@ importers:
         specifier: workspace:*
         version: link:../docs-markdown-utils
       '@fern-api/docs-parsers':
-        specifier: ^0.0.13
-        version: 0.0.13(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)
+        specifier: ^0.0.14
+        version: 0.0.14(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)
       '@fern-api/fdr-sdk':
         specifier: 0.127.3-6479103bd
         version: 0.127.3-6479103bd(typescript@4.6.4)
@@ -8094,8 +8094,8 @@ packages:
   '@fern-api/core-utils@0.4.24-rc1':
     resolution: {integrity: sha512-aYu4lQK2qZIKzTF9TeFrICTPJ/zGEZUEWQmZt6pJeHu+R6afrcCBNkUleWU1OpHlDbe+xXUUBOktRg0PM9Hywg==}
 
-  '@fern-api/docs-parsers@0.0.13':
-    resolution: {integrity: sha512-pmMUD28tWPGutTGDR2Q8vx/3v9YHlYMCUP2uVsI94Qam51Pm/uPVFikYoPrSxDYfG1NNcxGVddC7FKW18S99Xw==}
+  '@fern-api/docs-parsers@0.0.14':
+    resolution: {integrity: sha512-82MLnKAATRiCjD3Xcf60Mw9vGSZ2yj7iy8xaRGWBGudDjZBb2p4kcj95musonaF2f/IFNkq4iX3AONgB7FNhYA==}
 
   '@fern-api/dynamic-ir-sdk@53.24.0':
     resolution: {integrity: sha512-4XvzvSsh7lNZz5oYN0LH+FRpFGxg9TjfdipSJMpgHvPShe85m/tcfbOzbS0DHBpQGlKb/gHQtQRPAoBR1wdDAw==}
@@ -10249,9 +10249,6 @@ packages:
     resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
     engines: {node: '>= 0.4'}
 
-  es-toolkit@1.26.0:
-    resolution: {integrity: sha512-gg6ZaI4eTwzkQGkdEG+t4b4VH2mTxodBQ2KvyTKAQFIag3Vvxoq3XZ1ie4ijIQmVxiipL2+dZLDMkh1VIvAFyg==}
-
   es-toolkit@1.30.1:
     resolution: {integrity: sha512-ZXflqanzH8BpHkDhFa10bBf6ONDCe84EPUm7SSICGzuuROSluT2ynTPtwn9PcRelMtorCRozSknI/U0MNYp0Uw==}
 
@@ -15236,11 +15233,11 @@ snapshots:
       lodash-es: 4.17.21
       strip-ansi: 7.1.0
 
-  '@fern-api/docs-parsers@0.0.13(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)':
+  '@fern-api/docs-parsers@0.0.14(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)':
     dependencies:
       '@fern-api/logger': 0.4.24-rc1
       '@fern-api/ui-core-utils': 0.0.0
-      es-toolkit: 1.26.0
+      es-toolkit: 1.30.1
       openapi-types: 12.1.3
       ts-essentials: 10.0.1(typescript@4.6.4)
       uuid: 9.0.1
@@ -17845,8 +17842,6 @@ snapshots:
       is-date-object: 1.0.5
       is-symbol: 1.0.4
 
-  es-toolkit@1.26.0: {}
-
   es-toolkit@1.30.1: {}
 
   es6-promise@3.3.1: {}

From 73a5ea24a2a8cc13cde4b65f404a9b3713ad0b13 Mon Sep 17 00:00:00 2001
From: Rohin Bhargava <rohin@buildwithfern.com>
Date: Tue, 7 Jan 2025 17:56:21 -0500
Subject: [PATCH 03/11] docs dev working for design customer

---
 fern/apis/docs-yml/definition/docs.yml        |    4 +
 packages/cli/cli/package.json                 |    2 +-
 packages/cli/cli/src/cli.ts                   |    8 +-
 .../src/commands/docs-dev/devDocsWorkspace.ts |    7 +-
 .../generate/generateDocsWorkspace.ts         |   14 +
 .../writeDocsDefinitionForProject.ts          |   14 +
 .../cli/configuration-loader/package.json     |    2 +-
 packages/cli/configuration/package.json       |    2 +-
 .../docs/types/ExperimentalConfig.ts          |    2 +
 .../docs/types/ExperimentalConfig.ts          |    2 +
 .../cli/docs-importers/commons/package.json   |    2 +-
 .../cli/docs-importers/mintlify/package.json  |    2 +-
 packages/cli/docs-markdown-utils/package.json |    2 +-
 packages/cli/docs-preview/package.json        |    4 +-
 packages/cli/docs-preview/src/previewDocs.ts  |   77 +-
 .../cli/docs-preview/src/runPreviewServer.ts  |    7 +-
 packages/cli/docs-resolver/package.json       |    6 +-
 .../src/ApiReferenceNodeConverter.ts          |    2 +-
 .../src/ApiReferenceNodeConverterLatest.ts    | 1000 +++++++++++++++++
 .../src/DocsDefinitionResolver.ts             |   50 +-
 .../docs-resolver/src/__test__/dry.test.ts    |    2 +
 packages/cli/ete-tests/package.json           |    2 +-
 .../remote-workspace-runner/package.json      |    2 +-
 .../src/publishDocs.ts                        |    7 +-
 .../runRemoteGenerationForDocsWorkspace.ts    |    4 +
 packages/cli/register/package.json            |    2 +-
 packages/core/package.json                    |    2 +-
 pnpm-lock.yaml                                |   88 +-
 28 files changed, 1217 insertions(+), 101 deletions(-)
 create mode 100644 packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts

diff --git a/fern/apis/docs-yml/definition/docs.yml b/fern/apis/docs-yml/definition/docs.yml
index 86e48294f70..e0556d34b18 100644
--- a/fern/apis/docs-yml/definition/docs.yml
+++ b/fern/apis/docs-yml/definition/docs.yml
@@ -974,6 +974,10 @@ types:
           If `disable-stream-toggle` is set to true, the stream toggle will be disabled.
 
           This behavior is unstable and may change in the future.
+      direct-openapi-parser:
+        type: optional<boolean>
+        docs: |
+          If `direct-openapi-parser` is set to true, the OpenAPI parser will be used directly, without Fern.
 
   PlaygroundSettings:
     properties:
diff --git a/packages/cli/cli/package.json b/packages/cli/cli/package.json
index bf5b094e129..12893a93d9b 100644
--- a/packages/cli/cli/package.json
+++ b/packages/cli/cli/package.json
@@ -46,7 +46,7 @@
     "@fern-api/configuration-loader": "workspace:*",
     "@fern-api/core": "workspace:*",
     "@fern-api/core-utils": "workspace:*",
-    "@fern-api/docs-parsers": "^0.0.14",  
+    "@fern-api/docs-parsers": "^0.0.19",  
     "@fern-api/docs-preview": "workspace:*",
     "@fern-api/docs-resolver": "workspace:*",
     "@fern-api/docs-validator": "workspace:*", 
diff --git a/packages/cli/cli/src/cli.ts b/packages/cli/cli/src/cli.ts
index 94d9c60d9b3..a015859b267 100644
--- a/packages/cli/cli/src/cli.ts
+++ b/packages/cli/cli/src/cli.ts
@@ -992,10 +992,6 @@ function addDocsPreviewCommand(cli: Argv<GlobalCliOptions>, cliContext: CliConte
                     string: true,
                     hidden: true,
                     description: "Path of the local docs bundle to use"
-                })
-                .option("v2", {
-                    boolean: true,
-                    description: "Use openapi parser v2"
                 }),
         async (argv) => {
             let port: number;
@@ -1005,7 +1001,6 @@ function addDocsPreviewCommand(cli: Argv<GlobalCliOptions>, cliContext: CliConte
                 port = await getPort({ port: [3000, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010] });
             }
             const bundlePath: string | undefined = argv.bundlePath;
-            const v2 = argv.v2;
             await previewDocsWorkspace({
                 loadProject: () =>
                     loadProjectAndRegisterWorkspacesWithContext(cliContext, {
@@ -1014,8 +1009,7 @@ function addDocsPreviewCommand(cli: Argv<GlobalCliOptions>, cliContext: CliConte
                     }),
                 cliContext,
                 port,
-                bundlePath,
-                v2
+                bundlePath
             });
         }
     );
diff --git a/packages/cli/cli/src/commands/docs-dev/devDocsWorkspace.ts b/packages/cli/cli/src/commands/docs-dev/devDocsWorkspace.ts
index 18660ebc2f8..244231a0ac1 100644
--- a/packages/cli/cli/src/commands/docs-dev/devDocsWorkspace.ts
+++ b/packages/cli/cli/src/commands/docs-dev/devDocsWorkspace.ts
@@ -8,14 +8,12 @@ export async function previewDocsWorkspace({
     loadProject,
     cliContext,
     port,
-    bundlePath,
-    v2
+    bundlePath
 }: {
     loadProject: () => Promise<Project>;
     cliContext: CliContext;
     port: number;
     bundlePath?: string;
-    v2?: boolean;
 }): Promise<void> {
     const project = await loadProject();
     const docsWorkspace = project.docsWorkspaces;
@@ -60,8 +58,7 @@ export async function previewDocsWorkspace({
             },
             context,
             port,
-            bundlePath,
-            v2
+            bundlePath
         });
     });
 }
diff --git a/packages/cli/cli/src/commands/generate/generateDocsWorkspace.ts b/packages/cli/cli/src/commands/generate/generateDocsWorkspace.ts
index 1bc187b20e8..558bd9e2097 100644
--- a/packages/cli/cli/src/commands/generate/generateDocsWorkspace.ts
+++ b/packages/cli/cli/src/commands/generate/generateDocsWorkspace.ts
@@ -4,6 +4,8 @@ import { Project } from "@fern-api/project-loader";
 import { runRemoteGenerationForDocsWorkspace } from "@fern-api/remote-workspace-runner";
 import { CliContext } from "../../cli-context/CliContext";
 import { validateDocsWorkspaceAndLogIssues } from "../validate/validateDocsWorkspaceAndLogIssues";
+import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
+import { isNonNullish } from "@fern-api/core-utils";
 
 export async function generateDocsWorkspace({
     project,
@@ -57,9 +59,21 @@ export async function generateDocsWorkspace({
             })
         );
 
+        const ossWorkspaces = (
+            await Promise.all(
+                project.apiWorkspaces.map(async (workspace) => {
+                    if (workspace instanceof OSSWorkspace) {
+                        return workspace as OSSWorkspace;
+                    }
+                    return null;
+                })
+            )
+        ).filter(isNonNullish);
+
         await runRemoteGenerationForDocsWorkspace({
             organization: project.config.organization,
             fernWorkspaces,
+            ossWorkspaces,
             docsWorkspace,
             context,
             token,
diff --git a/packages/cli/cli/src/commands/write-docs-definition/writeDocsDefinitionForProject.ts b/packages/cli/cli/src/commands/write-docs-definition/writeDocsDefinitionForProject.ts
index 3381c3d9722..fe7b737612b 100644
--- a/packages/cli/cli/src/commands/write-docs-definition/writeDocsDefinitionForProject.ts
+++ b/packages/cli/cli/src/commands/write-docs-definition/writeDocsDefinitionForProject.ts
@@ -4,6 +4,8 @@ import { AbsoluteFilePath } from "@fern-api/fs-utils";
 import { writeFile } from "fs/promises";
 import chalk from "chalk";
 import { DocsDefinitionResolver } from "@fern-api/docs-resolver";
+import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
+import { isNonNullish } from "@fern-api/core-utils";
 
 export async function writeDocsDefinitionForProject({
     project,
@@ -20,6 +22,17 @@ export async function writeDocsDefinitionForProject({
     }
 
     await cliContext.runTaskForWorkspace(docsWorkspace, async (context) => {
+        const ossWorkspaces = (
+            await Promise.all(
+                project.apiWorkspaces.map(async (workspace) => {
+                    if (workspace instanceof OSSWorkspace) {
+                        return workspace as OSSWorkspace;
+                    }
+                    return null;
+                })
+            )
+        ).filter(isNonNullish);
+
         const fernWorkspaces = await Promise.all(
             project.apiWorkspaces.map(async (workspace) => {
                 return workspace.toFernWorkspace(
@@ -32,6 +45,7 @@ export async function writeDocsDefinitionForProject({
         const docsResolver = new DocsDefinitionResolver(
             docsWorkspace.config.instances[0]?.url ?? "http://localhost:8080",
             docsWorkspace,
+            ossWorkspaces,
             fernWorkspaces,
             context
         );
diff --git a/packages/cli/configuration-loader/package.json b/packages/cli/configuration-loader/package.json
index f17c15b5027..13583d0379d 100644
--- a/packages/cli/configuration-loader/package.json
+++ b/packages/cli/configuration-loader/package.json
@@ -33,7 +33,7 @@
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/task-context": "workspace:*",
     "@fern-api/fern-definition-schema": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
+    "@fern-fern/fdr-cjs-sdk": "0.127.4-331678a74",
     "@fern-fern/fiddle-sdk": "0.0.584",
     "@fern-fern/generators-sdk": "0.114.0-5745f9e74",
     "find-up": "^6.3.0",
diff --git a/packages/cli/configuration/package.json b/packages/cli/configuration/package.json
index a974fa02743..1bd393dd2b2 100644
--- a/packages/cli/configuration/package.json
+++ b/packages/cli/configuration/package.json
@@ -31,7 +31,7 @@
     "@fern-api/core-utils": "workspace:*",
     "@fern-api/path-utils": "workspace:*",
     "@fern-api/fern-definition-schema": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
+    "@fern-fern/fdr-cjs-sdk": "0.127.4-331678a74",
     "@fern-fern/fiddle-sdk": "0.0.584",
     "zod": "^3.22.3"
   },
diff --git a/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/ExperimentalConfig.ts b/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/ExperimentalConfig.ts
index 414ee0c3393..2be87a68ee0 100644
--- a/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/ExperimentalConfig.ts
+++ b/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/ExperimentalConfig.ts
@@ -14,4 +14,6 @@ export interface ExperimentalConfig {
      * This behavior is unstable and may change in the future.
      */
     disableStreamToggle?: boolean;
+    /** If `direct-openapi-parser` is set to true, the OpenAPI parser will be used directly, without Fern. */
+    directOpenapiParser?: boolean;
 }
diff --git a/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/ExperimentalConfig.ts b/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/ExperimentalConfig.ts
index 95cf8362dee..3cef35969be 100644
--- a/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/ExperimentalConfig.ts
+++ b/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/ExperimentalConfig.ts
@@ -15,11 +15,13 @@ export const ExperimentalConfig: core.serialization.ObjectSchema<
         core.serialization.list(core.serialization.string()).optional()
     ),
     disableStreamToggle: core.serialization.property("disable-stream-toggle", core.serialization.boolean().optional()),
+    directOpenapiParser: core.serialization.property("direct-openapi-parser", core.serialization.boolean().optional()),
 });
 
 export declare namespace ExperimentalConfig {
     interface Raw {
         "mdx-components"?: string[] | null;
         "disable-stream-toggle"?: boolean | null;
+        "direct-openapi-parser"?: boolean | null;
     }
 }
diff --git a/packages/cli/docs-importers/commons/package.json b/packages/cli/docs-importers/commons/package.json
index 5586b6810d0..aa6ebe3f18e 100644
--- a/packages/cli/docs-importers/commons/package.json
+++ b/packages/cli/docs-importers/commons/package.json
@@ -31,7 +31,7 @@
     "@fern-api/configuration": "workspace:*",
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/task-context": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
+    "@fern-fern/fdr-cjs-sdk": "0.127.4-331678a74",
     "js-yaml": "^4.1.0"
   },
   "devDependencies": {
diff --git a/packages/cli/docs-importers/mintlify/package.json b/packages/cli/docs-importers/mintlify/package.json
index 1a6663ad16c..d2b91b955cc 100644
--- a/packages/cli/docs-importers/mintlify/package.json
+++ b/packages/cli/docs-importers/mintlify/package.json
@@ -34,7 +34,7 @@
     "@fern-api/task-context": "workspace:*",
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/logger": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
+    "@fern-fern/fdr-cjs-sdk": "0.127.4-331678a74",
     "gray-matter": "^4.0.3"
   },
   "devDependencies": {
diff --git a/packages/cli/docs-markdown-utils/package.json b/packages/cli/docs-markdown-utils/package.json
index b59d51c478f..c6f903135f6 100644
--- a/packages/cli/docs-markdown-utils/package.json
+++ b/packages/cli/docs-markdown-utils/package.json
@@ -30,7 +30,7 @@
   "dependencies": {
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/task-context": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
+    "@fern-fern/fdr-cjs-sdk": "0.127.4-331678a74",
     "gray-matter": "^4.0.3",
     "mdast-util-from-markdown": "^2.0.1",
     "mdast-util-mdx": "^3.0.0",
diff --git a/packages/cli/docs-preview/package.json b/packages/cli/docs-preview/package.json
index f24e91e0df7..d1780560886 100644
--- a/packages/cli/docs-preview/package.json
+++ b/packages/cli/docs-preview/package.json
@@ -28,10 +28,12 @@
     "depcheck": "depcheck"
   },
   "dependencies": {
+    "@fern-api/core-utils": "workspace:*",
     "@fern-api/docs-resolver": "workspace:*",
-    "@fern-api/fdr-sdk": "0.127.3-6479103bd",
+    "@fern-api/fdr-sdk": "0.127.4-331678a74",
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/ir-sdk": "workspace:*",
+    "@fern-api/lazy-fern-workspace": "workspace:*",
     "@fern-api/logger": "workspace:*",
     "@fern-api/project-loader": "workspace:*",
     "@fern-api/register": "workspace:*",
diff --git a/packages/cli/docs-preview/src/previewDocs.ts b/packages/cli/docs-preview/src/previewDocs.ts
index 8a14568abba..38fce8e199b 100644
--- a/packages/cli/docs-preview/src/previewDocs.ts
+++ b/packages/cli/docs-preview/src/previewDocs.ts
@@ -18,19 +18,18 @@ import { Project } from "@fern-api/project-loader";
 import { convertIrToFdrApi } from "@fern-api/register";
 import { TaskContext } from "@fern-api/task-context";
 import { v4 as uuidv4 } from "uuid";
-import { generateFdrFromOpenApiWorkspace } from "@fern-api/docs-resolver";
-import { isNonNullish } from "../../../commons/core-utils/src";
+import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
+import { isNonNullish } from "@fern-api/core-utils";
+import { parseDocsConfiguration } from "../../configuration-loader/src/docs-yml/parseDocsConfiguration";
 
 export async function getPreviewDocsDefinition({
     domain,
     project,
-    context,
-    v2
+    context
 }: {
     domain: string;
     project: Project;
     context: TaskContext;
-    v2?: boolean;
 }): Promise<DocsV1Read.DocsDefinition> {
     const docsWorkspace = project.docsWorkspaces;
     const apiWorkspaces = project.apiWorkspaces;
@@ -48,16 +47,33 @@ export async function getPreviewDocsDefinition({
         )
     );
 
-    // TODO: remove this once we remove V1 API generation
-    const apiDefinitionIds: FdrAPI.ApiDefinitionId[] = [];
+    const ossWorkspaces = (
+        await Promise.all(
+            apiWorkspaces.map(async (workspace) => {
+                if (workspace instanceof OSSWorkspace) {
+                    return workspace as OSSWorkspace;
+                }
+                return null;
+            })
+        )
+    ).filter(isNonNullish);
 
     const apiCollector = new ReferencedAPICollector(context);
+    const apiCollectorV2 = new ReferencedAPICollectorV2(context);
 
     const filesV2: Record<string, DocsV1Read.File_> = {};
 
+    const parsedDocsConfig = await parseDocsConfiguration({
+        rawDocsConfiguration: docsWorkspace.config,
+        context,
+        absolutePathToFernFolder: docsWorkspace.absoluteFilePath,
+        absoluteFilepathToDocsConfig: docsWorkspace.absoluteFilepathToDocsConfig
+    });
+
     const resolver = new DocsDefinitionResolver(
         domain,
         docsWorkspace,
+        ossWorkspaces,
         fernWorkspaces,
         context,
         undefined,
@@ -74,11 +90,8 @@ export async function getPreviewDocsDefinition({
                     fileId
                 };
             }),
-        async (opts) => {
-            const id = apiCollector.addReferencedAPI(opts);
-            apiDefinitionIds.push(FdrAPI.ApiDefinitionId(id));
-            return id;
-        }
+        async (opts) => apiCollector.addReferencedAPI(opts),
+        async (opts) => apiCollectorV2.addReferencedAPI(opts)
     );
 
     const writeDocsDefinition = await resolver.resolve();
@@ -91,19 +104,8 @@ export async function getPreviewDocsDefinition({
     });
 
     return {
-        apis: v2 ? {} : apiCollector.getAPIsForDefinition(),
-        apisV2: v2
-            ? Object.fromEntries(
-                  (
-                      await Promise.all(
-                          project.apiWorkspaces.map(async (workspace, i) => [
-                              apiDefinitionIds[i],
-                              await generateFdrFromOpenApiWorkspace(workspace, context)
-                          ])
-                      )
-                  ).filter(isNonNullish)
-              )
-            : {},
+        apis: parsedDocsConfig.experimental?.directOpenapiParser ? {} : apiCollector.getAPIsForDefinition(),
+        apisV2: parsedDocsConfig.experimental?.directOpenapiParser ? apiCollectorV2.getAPIsForDefinition() : {},
         config: readDocsConfig,
         files: {},
         filesV2,
@@ -165,3 +167,28 @@ class ReferencedAPICollector {
         return this.apis;
     }
 }
+
+class ReferencedAPICollectorV2 {
+    private readonly apis: Record<APIDefinitionID, FdrAPI.api.latest.ApiDefinition> = {};
+
+    constructor(private readonly context: TaskContext) {}
+
+    public addReferencedAPI({ api }: { api: FdrAPI.api.latest.ApiDefinition }): APIDefinitionID {
+        try {
+            this.apis[api.id] = api;
+            return api.id;
+        } catch (e) {
+            // Print Error
+            const err = e as Error;
+            this.context.logger.error(`Failed to read referenced API: ${err?.message} ${err?.stack}`);
+            if (err.stack != null) {
+                this.context.logger.error(err?.stack);
+            }
+            throw e;
+        }
+    }
+
+    public getAPIsForDefinition(): Record<FdrAPI.ApiDefinitionId, FdrAPI.api.latest.ApiDefinition> {
+        return this.apis;
+    }
+}
diff --git a/packages/cli/docs-preview/src/runPreviewServer.ts b/packages/cli/docs-preview/src/runPreviewServer.ts
index 7ec931e916c..d78753c868b 100644
--- a/packages/cli/docs-preview/src/runPreviewServer.ts
+++ b/packages/cli/docs-preview/src/runPreviewServer.ts
@@ -55,8 +55,7 @@ export async function runPreviewServer({
     validateProject,
     context,
     port,
-    bundlePath,
-    v2
+    bundlePath
 }: {
     initialProject: Project;
     reloadProject: () => Promise<Project>;
@@ -64,7 +63,6 @@ export async function runPreviewServer({
     context: TaskContext;
     port: number;
     bundlePath?: string;
-    v2?: boolean;
 }): Promise<void> {
     if (bundlePath != null) {
         context.logger.info(`Using bundle from path: ${bundlePath}`);
@@ -131,8 +129,7 @@ export async function runPreviewServer({
             const newDocsDefinition = await getPreviewDocsDefinition({
                 domain: `${instance.host}${instance.pathname}`,
                 project,
-                context,
-                v2
+                context
             });
             context.logger.info(`Reload completed in ${Date.now() - startTime}ms`);
             return newDocsDefinition;
diff --git a/packages/cli/docs-resolver/package.json b/packages/cli/docs-resolver/package.json
index 0c1544ed3e0..5c77f9a5a59 100644
--- a/packages/cli/docs-resolver/package.json
+++ b/packages/cli/docs-resolver/package.json
@@ -32,10 +32,10 @@
     "@fern-api/configuration-loader": "workspace:*",
     "@fern-api/core-utils": "workspace:*",
     "@fern-api/docs-markdown-utils": "workspace:*",
-    "@fern-api/docs-parsers": "^0.0.14",
-    "@fern-api/fdr-sdk": "0.127.3-6479103bd",
+    "@fern-api/docs-parsers": "^0.0.19",
+    "@fern-api/fdr-sdk": "0.127.4-331678a74",
     "@fern-api/lazy-fern-workspace": "workspace:*",
-    "@fern-api/ui-core-utils": "0.127.3-6479103bd",
+    "@fern-api/ui-core-utils": "0.127.4-331678a74",
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/ir-generator": "workspace:*",
     "@fern-api/ir-sdk": "workspace:*",
diff --git a/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts b/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts
index aa2d13f6aaa..77ae404959b 100644
--- a/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts
+++ b/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts
@@ -1,6 +1,6 @@
 import { docsYml } from "@fern-api/configuration-loader";
 import { isNonNullish } from "@fern-api/core-utils";
-import { APIV1Read, FernNavigation } from "@fern-api/fdr-sdk";
+import { APIV1Read, FdrAPI, FernNavigation } from "@fern-api/fdr-sdk";
 import { AbsoluteFilePath, relative, RelativeFilePath } from "@fern-api/fs-utils";
 import { TaskContext } from "@fern-api/task-context";
 import { DocsWorkspace, FernWorkspace } from "@fern-api/workspace-loader";
diff --git a/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts b/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts
new file mode 100644
index 00000000000..ede0ae31e0c
--- /dev/null
+++ b/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts
@@ -0,0 +1,1000 @@
+import { docsYml } from "@fern-api/configuration-loader";
+import { isNonNullish } from "@fern-api/core-utils";
+import { FdrAPI, FernNavigation } from "@fern-api/fdr-sdk";
+import { AbsoluteFilePath, relative, RelativeFilePath } from "@fern-api/fs-utils";
+import { TaskContext } from "@fern-api/task-context";
+import { DocsWorkspace, FernWorkspace } from "@fern-api/workspace-loader";
+import { camelCase, kebabCase } from "lodash-es";
+import urlJoin from "url-join";
+import { ChangelogNodeConverter } from "./ChangelogNodeConverter";
+import { NodeIdGenerator } from "./NodeIdGenerator";
+import { stringifyEndpointPathParts } from "./utils/stringifyEndpointPathParts";
+import { titleCase, visitDiscriminatedUnion } from "@fern-api/ui-core-utils";
+import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
+import { threadId } from "worker_threads";
+
+// TODO: these functions need an extra piece of information from the fdr latest shape, to see if the operation id takes precedence over slug generation
+function getLatestEndpointUrlSlug(endpoint: FdrAPI.api.latest.endpoint.EndpointDefinition) {
+    const slugParts = endpoint.namespace?.map((subpackageId) => subpackageId.toString()) ?? [];
+    slugParts.push(kebabCase(endpoint.id.split(".").pop() ?? ""));
+    return endpoint.operationId != null ? kebabCase(endpoint.operationId) : urlJoin(slugParts);
+}
+
+function getLatestWebSocketUrlSlug(webSocket: FdrAPI.api.latest.websocket.WebSocketChannel) {
+    const slugParts = webSocket.namespace?.map((subpackageId) => subpackageId.toString()) ?? [];
+    slugParts.push(kebabCase(webSocket.id.split(".").pop() ?? ""));
+    return webSocket.operationId != null ? kebabCase(webSocket.operationId) : urlJoin(slugParts);
+}
+
+function getLatestWebhookUrlSlug(webhook: FdrAPI.api.latest.webhook.WebhookDefinition) {
+    const slugParts = webhook.namespace?.map((subpackageId) => subpackageId.toString()) ?? [];
+    slugParts.push(kebabCase(webhook.id.split(".").pop() ?? ""));
+    return webhook.operationId != null ? kebabCase(webhook.operationId) : urlJoin(slugParts);
+}
+// END TODO
+
+export class ApiReferenceNodeConverterLatest {
+    apiDefinitionId: FernNavigation.V1.ApiDefinitionId;
+    #api: FdrAPI.api.latest.ApiDefinition;
+    #visitedEndpoints = new Set<FernNavigation.V1.EndpointId>();
+    #visitedWebSockets = new Set<FernNavigation.V1.WebSocketId>();
+    #visitedWebhooks = new Set<FernNavigation.V1.WebhookId>();
+    #visitedSubpackages = new Set<string>();
+    #nodeIdToSubpackageId = new Map<string, string[]>();
+    #children: FernNavigation.V1.ApiPackageChild[] = [];
+    #overviewPageId: FernNavigation.V1.PageId | undefined;
+    #slug: FernNavigation.V1.SlugGenerator;
+    #idgen: NodeIdGenerator;
+    #topLevelSubpackages: Map<string, FdrAPI.navigation.v1.ApiPackageNode> = new Map();
+    private disableEndpointPairs;
+    constructor(
+        private apiSection: docsYml.DocsNavigationItem.ApiSection,
+        api: FdrAPI.api.latest.ApiDefinition,
+        parentSlug: FernNavigation.V1.SlugGenerator,
+        private workspace: OSSWorkspace,
+        private docsWorkspace: DocsWorkspace,
+        private taskContext: TaskContext,
+        private markdownFilesToFullSlugs: Map<AbsoluteFilePath, string>,
+        idgen: NodeIdGenerator
+    ) {
+        this.#api = api;
+        this.disableEndpointPairs = docsWorkspace.config.experimental?.disableStreamToggle ?? false;
+        this.apiDefinitionId = FernNavigation.V1.ApiDefinitionId(api.id);
+
+        // we are assuming that the apiDefinitionId is unique.
+        this.#idgen = idgen;
+
+        this.#overviewPageId =
+            this.apiSection.overviewAbsolutePath != null
+                ? FernNavigation.V1.PageId(this.toRelativeFilepath(this.apiSection.overviewAbsolutePath))
+                : undefined;
+
+        // the overview page markdown could contain a full slug, which would be used as the base slug for the API section.
+        const maybeFullSlug =
+            this.apiSection.overviewAbsolutePath != null
+                ? this.markdownFilesToFullSlugs.get(this.apiSection.overviewAbsolutePath)
+                : undefined;
+
+        this.#slug = parentSlug.apply({
+            fullSlug: maybeFullSlug?.split("/"),
+            skipUrlSlug: this.apiSection.skipUrlSlug,
+            urlSlug: this.apiSection.slug ?? kebabCase(this.apiSection.title)
+        });
+
+        // Step 1. Convert the navigation items that are manually defined in the API section.
+        if (this.apiSection.navigation != null) {
+            this.#children = this.#convertApiReferenceLayoutItems(this.apiSection.navigation, this.#slug);
+        }
+
+        // Step 2. Fill in the any missing navigation items from the API definition
+        this.#children = this.#mergeAndFilterChildren(
+            this.#children.map((child) => this.#enrichApiPackageChild(child)),
+            this.#convertApiDefinitionPackage(this.#api, this.#slug)
+        );
+    }
+
+    public get(): FernNavigation.V1.ApiReferenceNode {
+        const pointsTo = FernNavigation.V1.followRedirects(this.#children);
+        const changelogNodeConverter = new ChangelogNodeConverter(
+            this.markdownFilesToFullSlugs,
+            this.workspace.changelog?.files.map((file) => file.absoluteFilepath),
+            this.docsWorkspace,
+            this.#idgen
+        ).orUndefined();
+        return {
+            id: this.#idgen.get(this.apiDefinitionId),
+            type: "apiReference",
+            title: this.apiSection.title,
+            apiDefinitionId: this.apiDefinitionId,
+            overviewPageId: this.#overviewPageId,
+            paginated: this.apiSection.paginated,
+            slug: this.#slug.get(),
+            icon: this.apiSection.icon,
+            hidden: this.apiSection.hidden,
+            hideTitle: this.apiSection.flattened,
+            showErrors: this.apiSection.showErrors,
+            changelog: changelogNodeConverter?.toChangelogNode({
+                parentSlug: this.#slug,
+                viewers: undefined
+            }),
+            children: this.#children,
+            availability: undefined,
+            pointsTo,
+            noindex: undefined,
+            playground: this.#convertPlaygroundSettings(this.apiSection.playground),
+            authed: undefined,
+            viewers: this.apiSection.viewers,
+            orphaned: this.apiSection.orphaned
+        };
+    }
+
+    #findEndpointByLocator(locator: string): FdrAPI.api.latest.endpoint.EndpointDefinition | undefined {
+        return (
+            this.#api?.endpoints[FdrAPI.EndpointId(locator)] ??
+            this.#api?.endpoints[FdrAPI.EndpointId(locator.split(".").pop() ?? "")] ??
+            this.#api?.endpoints[FdrAPI.EndpointId(locator.split("/").pop() ?? "")] ??
+            Object.values(this.#api?.endpoints ?? {}).find((endpoint) => endpoint.id.includes(locator)) ??
+            Object.values(this.#api?.endpoints ?? {}).find(
+                (endpoint) => `${endpoint.method} ${stringifyEndpointPathParts(endpoint.path)}` === locator
+            ) ??
+            Object.values(this.#api?.endpoints ?? {}).find(
+                (endpoint) => `STREAM ${stringifyEndpointPathParts(endpoint.path)}` === locator
+            )
+        );
+    }
+
+    #findWebSocketByLocator(locator: string): FdrAPI.api.latest.websocket.WebSocketChannel | undefined {
+        return (
+            this.#api?.websockets[FdrAPI.WebSocketId(locator)] ??
+            this.#api?.websockets[FdrAPI.WebSocketId(locator.split(".").pop() ?? "")] ??
+            this.#api?.websockets[FdrAPI.WebSocketId(locator.split("/").pop() ?? "")] ??
+            Object.values(this.#api?.websockets ?? {}).find((endpoint) => endpoint.id.includes(locator))
+        );
+    }
+
+    #findWebhookByLocator(locator: string): FdrAPI.api.latest.webhook.WebhookDefinition | undefined {
+        return (
+            this.#api?.webhooks[FdrAPI.WebhookId(locator)] ??
+            this.#api?.webhooks[FdrAPI.WebhookId(locator.split(".").pop() ?? "")] ??
+            this.#api?.webhooks[FdrAPI.WebhookId(locator.split("/").pop() ?? "")] ??
+            Object.values(this.#api?.webhooks ?? {}).find((endpoint) => endpoint.id.includes(locator))
+        );
+    }
+
+    // Step 1
+
+    #convertApiReferenceLayoutItems(
+        navigation: docsYml.ParsedApiReferenceLayoutItem[],
+        parentSlug: FernNavigation.V1.SlugGenerator
+    ): FernNavigation.V1.ApiPackageChild[] {
+        return navigation
+            .map((item) =>
+                visitDiscriminatedUnion(item)._visit<FernNavigation.V1.ApiPackageChild | undefined>({
+                    link: (link) => ({
+                        id: this.#idgen.get(link.url),
+                        type: "link",
+                        title: link.text,
+                        icon: link.icon,
+                        url: FernNavigation.Url(link.url)
+                    }),
+                    page: (page) => this.#toPageNode(page, parentSlug),
+                    package: (pkg) => this.#convertPackage(pkg, parentSlug),
+                    section: (section) => this.#convertSection(section, parentSlug),
+                    item: ({ value: unknownIdentifier }): FernNavigation.V1.ApiPackageChild | undefined =>
+                        this.#convertUnknownIdentifier(unknownIdentifier, parentSlug),
+                    endpoint: (endpoint) => this.#convertEndpoint(endpoint, parentSlug)
+                })
+            )
+            .filter(isNonNullish);
+    }
+
+    #toPageNode(
+        page: docsYml.DocsNavigationItem.Page,
+        parentSlug: FernNavigation.V1.SlugGenerator
+    ): FernNavigation.V1.PageNode {
+        const pageId = FernNavigation.V1.PageId(this.toRelativeFilepath(page.absolutePath));
+        const pageSlug = parentSlug.apply({
+            fullSlug: this.markdownFilesToFullSlugs.get(page.absolutePath)?.split("/"),
+            urlSlug: page.slug ?? kebabCase(page.title)
+        });
+        return {
+            id: this.#idgen.get(pageId),
+            type: "page",
+            pageId,
+            title: page.title,
+            slug: pageSlug.get(),
+            icon: page.icon,
+            hidden: page.hidden,
+            noindex: page.noindex,
+            authed: undefined,
+            viewers: page.viewers,
+            orphaned: page.orphaned
+        };
+    }
+
+    #convertPackage(
+        pkg: docsYml.ParsedApiReferenceLayoutItem.Package,
+        parentSlug: FernNavigation.V1.SlugGenerator
+    ): FernNavigation.V1.ApiPackageNode {
+        const overviewPageId =
+            pkg.overviewAbsolutePath != null
+                ? FernNavigation.V1.PageId(this.toRelativeFilepath(pkg.overviewAbsolutePath))
+                : undefined;
+
+        const maybeFullSlug =
+            pkg.overviewAbsolutePath != null ? this.markdownFilesToFullSlugs.get(pkg.overviewAbsolutePath) : undefined;
+
+        const subpackage =
+            this.#api.subpackages[FdrAPI.api.v1.SubpackageId(pkg.package)] ??
+            this.#api.subpackages[
+                FdrAPI.api.v1.SubpackageId(pkg.package.replace(".yml", "").replace(".yaml", "").split(".").pop() ?? "")
+            ] ??
+            this.#api.subpackages[FdrAPI.api.v1.SubpackageId(pkg.package.split("/").pop() ?? "")];
+
+        if (subpackage != null) {
+            const subpackageNodeId = this.#idgen.get(overviewPageId ?? `${this.apiDefinitionId}:${subpackage.id}`);
+
+            if (this.#visitedSubpackages.has(subpackage.id)) {
+                this.taskContext.logger.error(
+                    `Duplicate subpackage found in the API Reference layout: ${subpackage.id}`
+                );
+            }
+
+            this.#visitedSubpackages.add(subpackage.id);
+            this.#nodeIdToSubpackageId.set(subpackageNodeId, [subpackage.id]);
+            const urlSlug = pkg.slug ?? subpackage.name;
+            const slug = parentSlug.apply({
+                fullSlug: maybeFullSlug?.split("/"),
+                skipUrlSlug: pkg.skipUrlSlug,
+                urlSlug
+            });
+            const convertedItems = this.#convertApiReferenceLayoutItems(pkg.contents, slug);
+            const subpackageNode: FernNavigation.V1.ApiPackageNode = {
+                id: subpackageNodeId,
+                type: "apiPackage",
+                children: convertedItems,
+                title: pkg.title ?? subpackage.displayName ?? titleCase(subpackage.name),
+                slug: slug.get(),
+                icon: pkg.icon,
+                hidden: pkg.hidden,
+                overviewPageId,
+                availability: undefined,
+                apiDefinitionId: this.apiDefinitionId,
+                pointsTo: undefined,
+                noindex: undefined,
+                playground: this.#convertPlaygroundSettings(pkg.playground),
+                authed: undefined,
+                viewers: pkg.viewers,
+                orphaned: pkg.orphaned
+            };
+
+            this.#topLevelSubpackages.set(subpackage.id, subpackageNode);
+            return subpackageNode;
+        } else {
+            this.taskContext.logger.warn(
+                `Subpackage ${pkg.package} not found in ${this.apiDefinitionId}, treating it as a section`
+            );
+            const urlSlug = pkg.slug ?? kebabCase(pkg.package);
+            const slug = parentSlug.apply({
+                fullSlug: maybeFullSlug?.split("/"),
+                skipUrlSlug: pkg.skipUrlSlug,
+                urlSlug
+            });
+            const convertedItems = this.#convertApiReferenceLayoutItems(pkg.contents, slug);
+            const sectionNode: FernNavigation.V1.ApiPackageNode = {
+                id: this.#idgen.get(overviewPageId ?? `${this.apiDefinitionId}:${kebabCase(pkg.package)}`),
+                type: "apiPackage",
+                children: convertedItems,
+                title: pkg.title ?? pkg.package,
+                slug: slug.get(),
+                icon: pkg.icon,
+                hidden: pkg.hidden,
+                overviewPageId,
+                availability: undefined,
+                apiDefinitionId: this.apiDefinitionId,
+                pointsTo: undefined,
+                noindex: undefined,
+                playground: this.#convertPlaygroundSettings(pkg.playground),
+                authed: undefined,
+                viewers: pkg.viewers,
+                orphaned: pkg.orphaned
+            };
+
+            this.#topLevelSubpackages.set(pkg.package, sectionNode);
+            return sectionNode;
+        }
+    }
+
+    #convertSection(
+        section: docsYml.ParsedApiReferenceLayoutItem.Section,
+        parentSlug: FernNavigation.V1.SlugGenerator
+    ): FernNavigation.V1.ApiPackageNode {
+        const overviewPageId =
+            section.overviewAbsolutePath != null
+                ? FernNavigation.V1.PageId(this.toRelativeFilepath(section.overviewAbsolutePath))
+                : undefined;
+
+        const maybeFullSlug =
+            section.overviewAbsolutePath != null
+                ? this.markdownFilesToFullSlugs.get(section.overviewAbsolutePath)
+                : undefined;
+
+        const nodeId = this.#idgen.get(overviewPageId ?? maybeFullSlug ?? parentSlug.get());
+
+        const subpackageIds = section.referencedSubpackages
+            .map((locator) => {
+                const subpackage =
+                    this.#api?.subpackages[FdrAPI.api.v1.SubpackageId(locator)] ??
+                    this.#api?.subpackages[
+                        FdrAPI.api.v1.SubpackageId(
+                            locator.replace(".yml", "").replace(".yaml", "").split(".").pop() ?? ""
+                        )
+                    ] ??
+                    this.#api?.subpackages[FdrAPI.api.v1.SubpackageId(locator.split("/").pop() ?? "")];
+
+                return subpackage != null ? subpackage.id : undefined;
+            })
+            .filter((subpackageId) => {
+                if (subpackageId == null) {
+                    this.taskContext.logger.error(`Subpackage ${subpackageId} not found in ${this.apiDefinitionId}`);
+                }
+                return subpackageId != null;
+            })
+            .filter(isNonNullish);
+
+        this.#nodeIdToSubpackageId.set(nodeId, subpackageIds);
+        subpackageIds.forEach((subpackageId) => {
+            if (this.#visitedSubpackages.has(subpackageId)) {
+                this.taskContext.logger.error(
+                    `Duplicate subpackage found in the API Reference layout: ${subpackageId}`
+                );
+            }
+            this.#visitedSubpackages.add(subpackageId);
+        });
+
+        const urlSlug = section.slug ?? kebabCase(section.title);
+        const slug = parentSlug.apply({
+            fullSlug: maybeFullSlug?.split("/"),
+            skipUrlSlug: section.skipUrlSlug,
+            urlSlug
+        });
+        const convertedItems = this.#convertApiReferenceLayoutItems(section.contents, slug);
+        return {
+            id: nodeId,
+            type: "apiPackage",
+            children: convertedItems,
+            title: section.title,
+            slug: slug.get(),
+            icon: section.icon,
+            hidden: section.hidden,
+            overviewPageId,
+            availability: undefined,
+            apiDefinitionId: this.apiDefinitionId,
+            pointsTo: undefined,
+            noindex: undefined,
+            playground: this.#convertPlaygroundSettings(section.playground),
+            authed: undefined,
+            viewers: section.viewers,
+            orphaned: section.orphaned
+        };
+    }
+
+    #convertUnknownIdentifier(
+        unknownIdentifier: string,
+        parentSlug: FernNavigation.V1.SlugGenerator
+    ): FernNavigation.V1.ApiPackageChild | undefined {
+        unknownIdentifier = unknownIdentifier.trim();
+        // unknownIdentifier could either be a package, endpoint, websocket, or webhook.
+        // We need to determine which one it is.
+
+        // if the unknownIdentifier is a subpackage, we need to check subpackage metadata, and any locators (strip .yml)
+
+        const subpackage =
+            this.#api?.subpackages[FdrAPI.api.v1.SubpackageId(unknownIdentifier)] ??
+            this.#api?.subpackages[
+                FdrAPI.api.v1.SubpackageId(
+                    unknownIdentifier.replace(".yml", "").replace(".yaml", "").split(".").pop() ?? ""
+                )
+            ] ??
+            this.#api?.subpackages[FdrAPI.api.v1.SubpackageId(unknownIdentifier.split("/").pop() ?? "")];
+
+        if (subpackage != null) {
+            const subpackageNodeId = this.#idgen.get(`${this.apiDefinitionId}:${subpackage.id}`);
+
+            if (this.#visitedSubpackages.has(subpackage.id)) {
+                this.taskContext.logger.error(
+                    `Duplicate subpackage found in the API Reference layout: ${subpackage.id}`
+                );
+            }
+
+            this.#visitedSubpackages.add(subpackage.id);
+            this.#nodeIdToSubpackageId.set(subpackageNodeId, [subpackage.id]);
+            const urlSlug = subpackage.name;
+            const slug = parentSlug.apply({ urlSlug });
+            const subpackageNode: FernNavigation.V1.ApiPackageNode = {
+                id: subpackageNodeId,
+                type: "apiPackage",
+                children: [],
+                title: subpackage.displayName ?? titleCase(subpackage.name),
+                slug: slug.get(),
+                icon: undefined,
+                hidden: undefined,
+                overviewPageId: undefined,
+                availability: undefined,
+                apiDefinitionId: this.apiDefinitionId,
+                pointsTo: undefined,
+                noindex: undefined,
+                playground: undefined,
+                authed: undefined,
+                viewers: undefined,
+                orphaned: undefined
+            };
+
+            this.#topLevelSubpackages.set(subpackage.id, subpackageNode);
+            return subpackageNode;
+        }
+
+        // if the unknownIdentifier is not a subpackage, it could be an http endpoint, websocket, or webhook.
+        return this.#convertEndpoint(
+            {
+                type: "endpoint",
+                endpoint: unknownIdentifier,
+                title: undefined,
+                icon: undefined,
+                slug: undefined,
+                hidden: undefined,
+                playground: undefined,
+                viewers: undefined,
+                orphaned: undefined
+            },
+            parentSlug
+        );
+    }
+
+    #convertEndpoint(
+        endpointItem: docsYml.ParsedApiReferenceLayoutItem.Endpoint,
+        parentSlug: FernNavigation.V1.SlugGenerator
+    ): FernNavigation.V1.ApiPackageChild | undefined {
+        const endpoint = this.#findEndpointByLocator(endpointItem.endpoint);
+
+        if (endpoint != null) {
+            if (endpoint.id == null) {
+                throw new Error(`Expected Endpoint ID for ${endpoint.id}. Got undefined.`);
+            }
+            if (this.#visitedEndpoints.has(endpoint.id)) {
+                this.taskContext.logger.error(`Duplicate endpoint found in the API Reference layout: ${endpoint.id}`);
+            }
+            this.#visitedEndpoints.add(endpoint.id);
+            const endpointSlug =
+                endpointItem.slug != null
+                    ? parentSlug.append(endpointItem.slug)
+                    : parentSlug.apply({ urlSlug: getLatestEndpointUrlSlug(endpoint) });
+            return {
+                id: this.#idgen.get(`${this.apiDefinitionId}:${endpoint.id}`),
+                type: "endpoint",
+                method: endpoint.method,
+                endpointId: endpoint.id,
+                apiDefinitionId: this.apiDefinitionId,
+                availability: FernNavigation.V1.convertAvailability(endpoint.availability),
+                isResponseStream: endpoint.responses?.[0]?.body.type === "stream",
+                title: endpointItem.title ?? endpoint.displayName ?? stringifyEndpointPathParts(endpoint.path),
+                slug: endpointSlug.get(),
+                icon: endpointItem.icon,
+                hidden: endpointItem.hidden,
+                playground: this.#convertPlaygroundSettings(endpointItem.playground),
+                authed: undefined,
+                viewers: endpointItem.viewers,
+                orphaned: endpointItem.orphaned
+            };
+        }
+
+        const webSocket = this.#findWebSocketByLocator(endpointItem.endpoint);
+
+        if (webSocket != null) {
+            if (webSocket.id == null) {
+                throw new Error(`Expected WebSocket ID for ${webSocket.id}. Got undefined.`);
+            }
+            if (this.#visitedWebSockets.has(webSocket.id)) {
+                this.taskContext.logger.error(
+                    `Duplicate web socket found in the API Reference layout: ${webSocket.id}`
+                );
+            }
+            this.#visitedWebSockets.add(webSocket.id);
+            return {
+                id: this.#idgen.get(`${this.apiDefinitionId}:${webSocket.id}`),
+                type: "webSocket",
+                webSocketId: webSocket.id,
+                title: endpointItem.title ?? webSocket.displayName ?? stringifyEndpointPathParts(webSocket.path),
+                slug: (endpointItem.slug != null
+                    ? parentSlug.append(endpointItem.slug)
+                    : parentSlug.apply({ urlSlug: getLatestWebSocketUrlSlug(webSocket) })
+                ).get(),
+                icon: endpointItem.icon,
+                hidden: endpointItem.hidden,
+                apiDefinitionId: this.apiDefinitionId,
+                availability: FernNavigation.V1.convertAvailability(webSocket.availability),
+                playground: this.#convertPlaygroundSettings(endpointItem.playground),
+                authed: undefined,
+                viewers: endpointItem.viewers,
+                orphaned: endpointItem.orphaned
+            };
+        }
+
+        const webhook = this.#findWebhookByLocator(endpointItem.endpoint);
+
+        if (webhook != null) {
+            if (webhook.id == null) {
+                throw new Error(`Expected Webhook ID for ${webhook.id}. Got undefined.`);
+            }
+            if (this.#visitedWebhooks.has(webhook.id)) {
+                this.taskContext.logger.error(`Duplicate webhook found in the API Reference layout: ${webhook.id}`);
+            }
+            this.#visitedWebhooks.add(webhook.id);
+            return {
+                id: this.#idgen.get(`${this.apiDefinitionId}:${webhook.id}`),
+                type: "webhook",
+                webhookId: webhook.id,
+                method: webhook.method,
+                title: endpointItem.title ?? webhook.displayName ?? urlJoin("/", ...webhook.path),
+                slug: (endpointItem.slug != null
+                    ? parentSlug.append(endpointItem.slug)
+                    : parentSlug.apply({ urlSlug: getLatestWebhookUrlSlug(webhook) })
+                ).get(),
+                icon: endpointItem.icon,
+                hidden: endpointItem.hidden,
+                apiDefinitionId: this.apiDefinitionId,
+                availability: undefined,
+                authed: undefined,
+                viewers: endpointItem.viewers,
+                orphaned: endpointItem.orphaned
+            };
+        }
+
+        this.taskContext.logger.error("Unknown identifier in the API Reference layout: ", endpointItem.endpoint);
+
+        return;
+    }
+
+    // Step 2
+
+    #mergeAndFilterChildren(
+        left: FernNavigation.V1.ApiPackageChild[],
+        right: FernNavigation.V1.ApiPackageChild[]
+    ): FernNavigation.V1.ApiPackageChild[] {
+        return this.mergeEndpointPairs([...left, ...right]).filter((child) =>
+            child.type === "apiPackage" ? child.children.length > 0 : true
+        );
+    }
+
+    #enrichApiPackageChild(child: FernNavigation.V1.ApiPackageChild): FernNavigation.V1.ApiPackageChild {
+        if (child.type === "apiPackage") {
+            // expand the subpackage to include children that haven't been visited yet
+            const slug = FernNavigation.V1.SlugGenerator.init(child.slug);
+            const subpackageIds = this.#nodeIdToSubpackageId.get(child.id) ?? [];
+            const subpackageChildren = subpackageIds.flatMap((subpackageId) =>
+                this.#convertApiDefinitionPackageId(subpackageId, slug)
+            );
+
+            // recursively apply enrichment to children
+            const enrichedChildren = child.children.map((innerChild) => this.#enrichApiPackageChild(innerChild));
+
+            // combine children with subpackage (tacked on at the end to preserve order)
+            const children = this.#mergeAndFilterChildren(enrichedChildren, subpackageChildren);
+
+            return {
+                ...child,
+                children,
+                pointsTo: undefined
+            };
+        }
+        return child;
+    }
+
+    #convertApiDefinitionPackage(
+        pkg: FdrAPI.api.latest.ApiDefinition,
+        parentSlug: FernNavigation.V1.SlugGenerator
+    ): FernNavigation.V1.ApiPackageChild[] {
+        // if an endpoint, websocket, webhook, or subpackage is not visited, add it to the additional children list
+        let additionalChildren: FernNavigation.V1.ApiPackageChild[] = [];
+
+        Object.entries(pkg.subpackages).forEach(([subpackageId, subpackageMetadata]) => {
+            if (this.#visitedSubpackages.has(subpackageId)) {
+                return;
+            }
+
+            const slug = parentSlug.apply({
+                urlSlug: subpackageMetadata.name
+            });
+            const subpackageNode: FernNavigation.V1.ApiPackageNode = {
+                id: FernNavigation.V1.NodeId(`${this.apiDefinitionId}:${subpackageId}`),
+                type: "apiPackage",
+                children: [],
+                title: subpackageMetadata.displayName ?? titleCase(subpackageMetadata.name),
+                slug: slug.get(),
+                icon: undefined,
+                hidden: undefined,
+                overviewPageId: undefined,
+                availability: undefined,
+                apiDefinitionId: this.apiDefinitionId,
+                pointsTo: undefined,
+                noindex: undefined,
+                playground: undefined,
+                authed: undefined,
+                viewers: undefined,
+                orphaned: undefined
+            };
+            this.#topLevelSubpackages.set(subpackageId, subpackageNode);
+            additionalChildren.push(subpackageNode);
+        });
+
+        Object.entries(pkg.endpoints).forEach(([endpointId, endpoint]) => {
+            if (endpointId == null) {
+                throw new Error(`Expected Endpoint ID for ${endpoint.id}. Got undefined.`);
+            }
+            if (this.#visitedEndpoints.has(FdrAPI.EndpointId(endpointId))) {
+                return;
+            }
+
+            const endpointSlug = parentSlug.apply({
+                urlSlug: getLatestEndpointUrlSlug(endpoint)
+            });
+
+            const endpointNode: FernNavigation.V1.EndpointNode = {
+                id: FernNavigation.V1.NodeId(`${this.apiDefinitionId}:${endpointId}`),
+                type: "endpoint",
+                method: endpoint.method,
+                endpointId: FdrAPI.EndpointId(endpointId),
+                apiDefinitionId: this.apiDefinitionId,
+                availability: FernNavigation.V1.convertAvailability(endpoint.availability),
+                isResponseStream: endpoint.responses?.[0]?.body.type === "stream",
+                title: endpoint.displayName ?? stringifyEndpointPathParts(endpoint.path),
+                slug: endpointSlug.get(),
+                icon: undefined,
+                hidden: undefined,
+                playground: undefined,
+                authed: undefined,
+                viewers: undefined,
+                orphaned: undefined
+            };
+
+            if (endpoint.namespace != null && endpoint.namespace.length > 0) {
+                const firstNamespacePart = camelCase(endpoint.namespace[0]);
+                if (firstNamespacePart != null) {
+                    let subpackageCursor = this.#topLevelSubpackages.get(firstNamespacePart);
+                    if (subpackageCursor == null) {
+                        this.taskContext.logger.error(
+                            `Subpackage ${firstNamespacePart} not found in ${this.apiDefinitionId}`
+                        );
+                        return;
+                    }
+                    let slugGenerator = parentSlug.apply({ urlSlug: subpackageCursor.slug });
+
+                    for (const namespacePart of endpoint.namespace.slice(1)) {
+                        let newSubpackageCursor: FdrAPI.navigation.v1.ApiPackageChild | undefined =
+                            subpackageCursor.children.find(
+                                (child) =>
+                                    child.type === "apiPackage" && child.id === camelCase(namespacePart.toString())
+                            );
+                        slugGenerator = slugGenerator.append(kebabCase(namespacePart));
+                        if (newSubpackageCursor == null) {
+                            newSubpackageCursor = {
+                                id: FernNavigation.V1.NodeId(`${this.apiDefinitionId}:${namespacePart}`),
+                                type: "apiPackage",
+                                children: [],
+                                title: titleCase(namespacePart),
+                                slug: slugGenerator.get(),
+                                icon: undefined,
+                                hidden: undefined,
+                                overviewPageId: undefined,
+                                availability: undefined,
+                                apiDefinitionId: this.apiDefinitionId,
+                                pointsTo: undefined,
+                                noindex: undefined,
+                                playground: undefined,
+                                authed: undefined,
+                                viewers: undefined,
+                                orphaned: undefined
+                            };
+                        }
+                        if (newSubpackageCursor != null && newSubpackageCursor.type === "apiPackage") {
+                            subpackageCursor = newSubpackageCursor;
+                        }
+                    }
+
+                    subpackageCursor.children.push(endpointNode);
+                }
+            } else {
+                additionalChildren.push(endpointNode);
+            }
+        });
+
+        Object.entries(pkg.websockets).forEach(([webSocketId, webSocket]) => {
+            if (webSocketId == null) {
+                throw new Error(`Expected WebSocket ID for ${webSocket.id}. Got undefined.`);
+            }
+            if (this.#visitedWebSockets.has(FdrAPI.WebSocketId(webSocketId))) {
+                return;
+            }
+            const webSocketNode: FernNavigation.V1.WebSocketNode = {
+                id: FernNavigation.V1.NodeId(`${this.apiDefinitionId}:${webSocketId}`),
+                type: "webSocket",
+                webSocketId: FdrAPI.WebSocketId(webSocketId),
+                title: webSocket.displayName ?? stringifyEndpointPathParts(webSocket.path),
+                slug: parentSlug
+                    .apply({
+                        urlSlug: getLatestWebSocketUrlSlug(webSocket)
+                    })
+                    .get(),
+                icon: undefined,
+                hidden: undefined,
+                apiDefinitionId: this.apiDefinitionId,
+                availability: FernNavigation.V1.convertAvailability(webSocket.availability),
+                playground: undefined,
+                authed: undefined,
+                viewers: undefined,
+                orphaned: undefined
+            };
+            if (webSocket.namespace != null && webSocket.namespace.length > 0) {
+                const firstNamespacePart = webSocket.namespace[0];
+                if (firstNamespacePart != null) {
+                    let subpackageCursor = this.#topLevelSubpackages.get(firstNamespacePart);
+                    if (subpackageCursor == null) {
+                        throw new Error(`Subpackage ${firstNamespacePart} not found in ${this.apiDefinitionId}`);
+                    }
+                    let slugGenerator = parentSlug.apply({ urlSlug: subpackageCursor.slug });
+
+                    for (const namespacePart of webSocket.namespace.slice(1)) {
+                        let newSubpackageCursor: FdrAPI.navigation.v1.ApiPackageChild | undefined =
+                            subpackageCursor.children.find(
+                                (child) => child.type === "apiPackage" && child.id === namespacePart.toString()
+                            );
+                        slugGenerator = slugGenerator.append(namespacePart);
+                        if (newSubpackageCursor == null) {
+                            newSubpackageCursor = {
+                                id: FernNavigation.V1.NodeId(`${this.apiDefinitionId}:${namespacePart}`),
+                                type: "apiPackage",
+                                children: [],
+                                title: titleCase(namespacePart),
+                                slug: slugGenerator.get(),
+                                icon: undefined,
+                                hidden: undefined,
+                                overviewPageId: undefined,
+                                availability: undefined,
+                                apiDefinitionId: this.apiDefinitionId,
+                                pointsTo: undefined,
+                                noindex: undefined,
+                                playground: undefined,
+                                authed: undefined,
+                                viewers: undefined,
+                                orphaned: undefined
+                            };
+                        }
+                        if (newSubpackageCursor != null && newSubpackageCursor.type === "apiPackage") {
+                            subpackageCursor = newSubpackageCursor;
+                        }
+                    }
+                    subpackageCursor.children.push(webSocketNode);
+                }
+            } else {
+                additionalChildren.push(webSocketNode);
+            }
+        });
+
+        Object.entries(pkg.webhooks).forEach(([webhookId, webhook]) => {
+            if (webhookId == null) {
+                throw new Error(`Expected Webhook ID for ${webhook.id}. Got undefined.`);
+            }
+            if (this.#visitedWebhooks.has(FdrAPI.WebhookId(webhookId))) {
+                return;
+            }
+            const webhookNode: FernNavigation.V1.WebhookNode = {
+                id: FernNavigation.V1.NodeId(`${this.apiDefinitionId}:${webhookId}`),
+                type: "webhook",
+                webhookId: FdrAPI.WebhookId(webhookId),
+                method: webhook.method,
+                title: webhook.displayName ?? titleCase(webhook.id),
+                slug: parentSlug
+                    .apply({
+                        urlSlug: getLatestWebhookUrlSlug(webhook)
+                    })
+                    .get(),
+                icon: undefined,
+                hidden: undefined,
+                apiDefinitionId: this.apiDefinitionId,
+                availability: undefined,
+                authed: undefined,
+                viewers: undefined,
+                orphaned: undefined
+            };
+
+            if (webhook.namespace != null && webhook.namespace.length > 0) {
+                const firstNamespacePart = webhook.namespace[0];
+                if (firstNamespacePart != null) {
+                    let subpackageCursor = this.#topLevelSubpackages.get(firstNamespacePart);
+                    if (subpackageCursor == null) {
+                        throw new Error(`Subpackage ${firstNamespacePart} not found in ${this.apiDefinitionId}`);
+                    }
+                    let slugGenerator = parentSlug.apply({ urlSlug: subpackageCursor.slug });
+
+                    for (const namespacePart of webhook.namespace.slice(1)) {
+                        let newSubpackageCursor: FdrAPI.navigation.v1.ApiPackageChild | undefined =
+                            subpackageCursor.children.find(
+                                (child) => child.type === "apiPackage" && child.id === namespacePart.toString()
+                            );
+                        slugGenerator = slugGenerator.append(namespacePart);
+                        if (newSubpackageCursor == null) {
+                            newSubpackageCursor = {
+                                id: FernNavigation.V1.NodeId(`${this.apiDefinitionId}:${namespacePart}`),
+                                type: "apiPackage",
+                                children: [],
+                                title: namespacePart,
+                                slug: slugGenerator.get(),
+                                icon: undefined,
+                                hidden: undefined,
+                                overviewPageId: undefined,
+                                availability: undefined,
+                                apiDefinitionId: this.apiDefinitionId,
+                                pointsTo: undefined,
+                                noindex: undefined,
+                                playground: undefined,
+                                authed: undefined,
+                                viewers: undefined,
+                                orphaned: undefined
+                            };
+                        }
+                        if (newSubpackageCursor != null && newSubpackageCursor.type === "apiPackage") {
+                            subpackageCursor = newSubpackageCursor;
+                        }
+                    }
+                    subpackageCursor.children.push(webhookNode);
+                }
+            } else {
+                additionalChildren.push(webhookNode);
+            }
+        });
+
+        additionalChildren = this.mergeEndpointPairs(additionalChildren);
+
+        if (this.apiSection.alphabetized) {
+            additionalChildren = additionalChildren.sort((a, b) => {
+                const aTitle = a.type === "endpointPair" ? a.nonStream.title : a.title;
+                const bTitle = b.type === "endpointPair" ? b.nonStream.title : b.title;
+                return aTitle.localeCompare(bTitle);
+            });
+        }
+
+        return additionalChildren;
+    }
+
+    // TODO: optimize this with some DP, where we store incrementally found endpoints (constructing an indexed tree of subpackages)
+    #resolveSubpackage(subpackageId: string): FdrAPI.api.latest.ApiDefinition {
+        const endpoints = Object.fromEntries(
+            Object.entries(this.#api?.endpoints ?? {}).filter(
+                ([_, endpoint]) =>
+                    endpoint.namespace != null &&
+                    camelCase(endpoint.namespace[endpoint.namespace.length - 1]) ===
+                        FdrAPI.api.v1.SubpackageId(subpackageId)
+            )
+        );
+        const websockets = Object.fromEntries(
+            Object.entries(this.#api?.websockets ?? {}).filter(
+                ([_, webSocket]) =>
+                    webSocket.namespace != null &&
+                    camelCase(webSocket.namespace[webSocket.namespace.length - 1]) ===
+                        FdrAPI.api.v1.SubpackageId(subpackageId)
+            )
+        );
+        const webhooks = Object.fromEntries(
+            Object.entries(this.#api?.webhooks ?? {}).filter(
+                ([_, webhook]) =>
+                    webhook.namespace != null &&
+                    camelCase(webhook.namespace[webhook.namespace.length - 1]) ===
+                        FdrAPI.api.v1.SubpackageId(subpackageId)
+            )
+        );
+        return {
+            id: FdrAPI.ApiDefinitionId(subpackageId),
+            endpoints,
+            websockets,
+            webhooks,
+            types: {},
+            subpackages: {},
+            auths: {},
+            globalHeaders: undefined
+        };
+    }
+
+    #convertApiDefinitionPackageId(
+        packageId: string | undefined,
+        parentSlug: FernNavigation.V1.SlugGenerator
+    ): FernNavigation.V1.ApiPackageChild[] {
+        const pkg = packageId != null ? this.#resolveSubpackage(packageId) : undefined;
+
+        if (pkg == null) {
+            this.taskContext.logger.error(`Subpackage ${packageId} not found in ${this.apiDefinitionId}`);
+            return [];
+        }
+
+        // if an endpoint, websocket, webhook, or subpackage is not visited, add it to the additional children list
+        return this.#convertApiDefinitionPackage(pkg, parentSlug);
+    }
+
+    #convertPlaygroundSettings(
+        playgroundSettings?: docsYml.RawSchemas.PlaygroundSettings
+    ): FernNavigation.V1.PlaygroundSettings | undefined {
+        if (playgroundSettings) {
+            return {
+                environments:
+                    playgroundSettings.environments != null && playgroundSettings.environments.length > 0
+                        ? playgroundSettings.environments.map((environmentId) =>
+                              FernNavigation.V1.EnvironmentId(environmentId)
+                          )
+                        : undefined,
+                button:
+                    playgroundSettings.button != null && playgroundSettings.button.href
+                        ? { href: FernNavigation.V1.Url(playgroundSettings.button.href) }
+                        : undefined,
+                "limit-websocket-messages-per-connection":
+                    playgroundSettings.limitWebsocketMessagesPerConnection != null
+                        ? playgroundSettings.limitWebsocketMessagesPerConnection
+                        : undefined
+            };
+        }
+
+        return;
+    }
+
+    private mergeEndpointPairs(children: FernNavigation.V1.ApiPackageChild[]): FernNavigation.V1.ApiPackageChild[] {
+        if (this.disableEndpointPairs) {
+            return children;
+        }
+
+        const toRet: FernNavigation.V1.ApiPackageChild[] = [];
+
+        const methodAndPathToEndpointNode = new Map<string, FernNavigation.V1.EndpointNode>();
+        children.forEach((child) => {
+            if (child.type !== "endpoint") {
+                toRet.push(child);
+                return;
+            }
+
+            const endpoint = this.#api?.endpoints[child.endpointId];
+            if (endpoint == null) {
+                throw new Error(`Endpoint ${child.endpointId} not found`);
+            }
+
+            const methodAndPath = `${endpoint.method} ${stringifyEndpointPathParts(endpoint.path)}`;
+
+            const existing = methodAndPathToEndpointNode.get(methodAndPath);
+            methodAndPathToEndpointNode.set(methodAndPath, child);
+
+            if (existing == null || existing.isResponseStream === child.isResponseStream) {
+                toRet.push(child);
+                return;
+            }
+
+            const idx = toRet.indexOf(existing);
+            const stream = child.isResponseStream ? child : existing;
+            const nonStream = child.isResponseStream ? existing : child;
+            const pairNode: FernNavigation.V1.EndpointPairNode = {
+                id: FernNavigation.V1.NodeId(`${this.apiDefinitionId}:${nonStream.endpointId}+${stream.endpointId}`),
+                type: "endpointPair",
+                stream,
+                nonStream
+            };
+
+            toRet[idx] = pairNode;
+        });
+
+        return toRet;
+    }
+
+    private toRelativeFilepath(filepath: AbsoluteFilePath): RelativeFilePath;
+    private toRelativeFilepath(filepath: AbsoluteFilePath | undefined): RelativeFilePath | undefined;
+    private toRelativeFilepath(filepath: AbsoluteFilePath | undefined): RelativeFilePath | undefined {
+        if (filepath == null) {
+            return undefined;
+        }
+        return relative(this.docsWorkspace.absoluteFilePath, filepath);
+    }
+}
diff --git a/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts b/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts
index 011c62af493..9fdac46d3f4 100644
--- a/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts
+++ b/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts
@@ -6,7 +6,7 @@ import {
     replaceReferencedCode,
     replaceReferencedMarkdown
 } from "@fern-api/docs-markdown-utils";
-import { APIV1Write, DocsV1Write, FernNavigation } from "@fern-api/fdr-sdk";
+import { APIV1Write, DocsV1Write, FdrAPI, FernNavigation } from "@fern-api/fdr-sdk";
 import { AbsoluteFilePath, listFiles, relative, RelativeFilePath, relativize, resolve } from "@fern-api/fs-utils";
 import { generateIntermediateRepresentation } from "@fern-api/ir-generator";
 import { IntermediateRepresentation } from "@fern-api/ir-sdk";
@@ -26,6 +26,9 @@ import { convertIrToApiDefinition } from "./utils/convertIrToApiDefinition";
 import { collectFilesFromDocsConfig } from "./utils/getImageFilepathsToUpload";
 import { wrapWithHttps } from "./wrapWithHttps";
 import { SourceResolverImpl } from "@fern-api/cli-source-resolver";
+import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
+import { generateFdrFromOpenApiWorkspace } from "./utils/generateFdrFromOpenApiWorkspace";
+import { ApiReferenceNodeConverterLatest } from "./ApiReferenceNodeConverterLatest";
 
 dayjs.extend(utc);
 
@@ -51,6 +54,8 @@ type RegisterApiFn = (opts: {
     apiName?: string;
 }) => AsyncOrSync<string>;
 
+type RegisterApiV2Fn = (opts: { api: FdrAPI.api.latest.ApiDefinition; apiName?: string }) => AsyncOrSync<string>;
+
 const defaultUploadFiles: UploadFilesFn = (files) => {
     return files.map((file) => ({ ...file, fileId: String(file.relativeFilePath) }));
 };
@@ -61,16 +66,23 @@ const defaultRegisterApi: RegisterApiFn = async ({ ir }) => {
     return `${ir.apiName.snakeCase.unsafeName}-${apiCounter}`;
 };
 
+const defaultRegisterApiV2: RegisterApiV2Fn = async ({ api }) => {
+    apiCounter++;
+    return `${api.id}-${apiCounter}`;
+};
+
 export class DocsDefinitionResolver {
     constructor(
         private domain: string,
         private docsWorkspace: DocsWorkspace,
+        private ossWorkspaces: OSSWorkspace[],
         private fernWorkspaces: FernWorkspace[],
         private taskContext: TaskContext,
         // Optional
         private editThisPage?: docsYml.RawSchemas.EditThisPageConfig,
         private uploadFiles: UploadFilesFn = defaultUploadFiles,
-        private registerApi: RegisterApiFn = defaultRegisterApi
+        private registerApi: RegisterApiFn = defaultRegisterApi,
+        private registerApiV2: RegisterApiV2Fn = defaultRegisterApiV2
     ) {}
 
     #idgen = NodeIdGenerator.init();
@@ -346,6 +358,18 @@ export class DocsDefinitionResolver {
         throw new Error("Failed to load API Definition referenced in docs");
     }
 
+    private getOpenApiWorkspaceForApiSection(apiSection: docsYml.DocsNavigationItem.ApiSection): OSSWorkspace {
+        if (this.ossWorkspaces.length === 1 && this.ossWorkspaces[0] != null) {
+            return this.ossWorkspaces[0];
+        } else if (apiSection.apiName != null) {
+            const ossWorkspace = this.ossWorkspaces.find((workspace) => workspace.workspaceName === apiSection.apiName);
+            if (ossWorkspace != null) {
+                return ossWorkspace;
+            }
+        }
+        throw new Error("Failed to load API Definition referenced in docs");
+    }
+
     private async toRootNode(): Promise<FernNavigation.V1.RootNode> {
         const slug = FernNavigation.V1.SlugGenerator.init(FernNavigation.slugjoin(this.getDocsBasePath()));
         const id = this.#idgen.get("root");
@@ -542,6 +566,28 @@ export class DocsDefinitionResolver {
         item: docsYml.DocsNavigationItem.ApiSection,
         parentSlug: FernNavigation.V1.SlugGenerator
     ): Promise<FernNavigation.V1.ApiReferenceNode> {
+        if (this.parsedDocsConfig.experimental?.directOpenapiParser) {
+            const workspace = this.getOpenApiWorkspaceForApiSection(item);
+            const api = await generateFdrFromOpenApiWorkspace(workspace, this.taskContext);
+            if (api == null) {
+                throw new Error("Failed to generate API Definition from OpenAPI workspace");
+            }
+            await this.registerApiV2({
+                api,
+                apiName: item.apiName
+            });
+            const node = new ApiReferenceNodeConverterLatest(
+                item,
+                api,
+                parentSlug,
+                workspace,
+                this.docsWorkspace,
+                this.taskContext,
+                this.markdownFilesToFullSlugs,
+                this.#idgen
+            );
+            return node.get();
+        }
         const workspace = this.getFernWorkspaceForApiSection(item);
         const snippetsConfig = convertDocsSnippetsConfigToFdr(item.snippetsConfiguration);
         const ir = generateIntermediateRepresentation({
diff --git a/packages/cli/docs-resolver/src/__test__/dry.test.ts b/packages/cli/docs-resolver/src/__test__/dry.test.ts
index afa718448b1..a88497675dc 100644
--- a/packages/cli/docs-resolver/src/__test__/dry.test.ts
+++ b/packages/cli/docs-resolver/src/__test__/dry.test.ts
@@ -22,9 +22,11 @@ it.skip("converts to api reference node", async () => {
         "domain",
         docsWorkspace,
         [],
+        [],
         context,
         undefined,
         async (_files) => [],
+        async (_opts) => "",
         async (_opts) => ""
     );
 
diff --git a/packages/cli/ete-tests/package.json b/packages/cli/ete-tests/package.json
index 59a36fa6329..541d2a5e7e1 100644
--- a/packages/cli/ete-tests/package.json
+++ b/packages/cli/ete-tests/package.json
@@ -29,7 +29,7 @@
   },
   "dependencies": {
     "@fern-api/configuration": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
+    "@fern-fern/fdr-cjs-sdk": "0.127.4-331678a74",
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/logging-execa": "workspace:*",
     "@fern-typescript/fetcher": "workspace:*",
diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/package.json b/packages/cli/generation/remote-generation/remote-workspace-runner/package.json
index 5d3c27eb9ae..6b771eeb3dd 100644
--- a/packages/cli/generation/remote-generation/remote-workspace-runner/package.json
+++ b/packages/cli/generation/remote-generation/remote-workspace-runner/package.json
@@ -35,7 +35,7 @@
     "@fern-api/core-utils": "workspace:*",
     "@fern-api/docs-resolver": "workspace:*",
     "@fern-api/logging-execa": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
+    "@fern-fern/fdr-cjs-sdk": "0.127.4-331678a74",
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/ir-generator": "workspace:*",
     "@fern-api/ir-migrations": "workspace:*",
diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts
index 5f1684edaa3..5fff325b6bb 100644
--- a/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts
+++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts
@@ -16,6 +16,7 @@ import { chunk } from "lodash-es";
 import * as mime from "mime-types";
 import terminalLink from "terminal-link";
 import { measureImageSizes } from "./measureImageSizes";
+import { OSSWorkspace } from "../../../../workspace/lazy-fern-workspace/src";
 
 const MEASURE_IMAGE_BATCH_SIZE = 10;
 const UPLOAD_FILE_BATCH_SIZE = 10;
@@ -33,6 +34,7 @@ export async function publishDocs({
     domain,
     customDomains,
     fernWorkspaces,
+    ossWorkspaces,
     context,
     preview,
     editThisPage,
@@ -44,6 +46,7 @@ export async function publishDocs({
     domain: string;
     customDomains: string[];
     fernWorkspaces: FernWorkspace[];
+    ossWorkspaces: OSSWorkspace[];
     context: TaskContext;
     preview: boolean;
     editThisPage: docsYml.RawSchemas.FernDocsConfig.EditThisPageConfig | undefined;
@@ -60,6 +63,7 @@ export async function publishDocs({
     const resolver = new DocsDefinitionResolver(
         domain,
         docsWorkspace,
+        ossWorkspaces,
         fernWorkspaces,
         context,
         editThisPage,
@@ -158,7 +162,8 @@ export async function publishDocs({
             const response = await fdr.api.v1.register.registerApiDefinition({
                 orgId: CjsFdrSdk.OrgId(organization),
                 apiId: CjsFdrSdk.ApiId(ir.apiName.originalName),
-                definition: apiDefinition
+                definition: apiDefinition,
+                definitionV2: undefined
             });
 
             if (response.ok) {
diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForDocsWorkspace.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForDocsWorkspace.ts
index d21227958df..32faf84c7d8 100644
--- a/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForDocsWorkspace.ts
+++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForDocsWorkspace.ts
@@ -3,10 +3,12 @@ import { replaceEnvVariables } from "@fern-api/core-utils";
 import { TaskContext } from "@fern-api/task-context";
 import { DocsWorkspace, FernWorkspace } from "@fern-api/workspace-loader";
 import { publishDocs } from "./publishDocs";
+import { OSSWorkspace } from "../../../../workspace/lazy-fern-workspace/src";
 
 export async function runRemoteGenerationForDocsWorkspace({
     organization,
     fernWorkspaces,
+    ossWorkspaces,
     docsWorkspace,
     context,
     token,
@@ -15,6 +17,7 @@ export async function runRemoteGenerationForDocsWorkspace({
 }: {
     organization: string;
     fernWorkspaces: FernWorkspace[];
+    ossWorkspaces: OSSWorkspace[];
     docsWorkspace: DocsWorkspace;
     context: TaskContext;
     token: FernToken;
@@ -76,6 +79,7 @@ export async function runRemoteGenerationForDocsWorkspace({
             organization,
             context,
             fernWorkspaces,
+            ossWorkspaces,
             preview,
             editThisPage: maybeInstance.editThisPage,
             isPrivate: maybeInstance.private
diff --git a/packages/cli/register/package.json b/packages/cli/register/package.json
index ec70d43f350..31904aad626 100644
--- a/packages/cli/register/package.json
+++ b/packages/cli/register/package.json
@@ -33,7 +33,7 @@
     "@fern-api/configuration": "workspace:*",
     "@fern-api/core": "workspace:*",
     "@fern-api/core-utils": "workspace:*",
-    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd",
+    "@fern-fern/fdr-cjs-sdk": "0.127.4-331678a74",
     "@fern-api/fs-utils": "workspace:*",
     "@fern-api/ir-generator": "workspace:*",
     "@fern-api/ir-sdk": "workspace:*",
diff --git a/packages/core/package.json b/packages/core/package.json
index cc5200e19ee..b8c710ddcf5 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -28,7 +28,7 @@
     "depcheck": "depcheck"
   },
   "dependencies": {
-    "@fern-fern/fdr-cjs-sdk": "0.127.3-6479103bd", 
+    "@fern-fern/fdr-cjs-sdk": "0.127.4-331678a74", 
     "@fern-fern/generators-sdk": "0.114.0-5745f9e74",
     "@fern-api/venus-api-sdk": "0.10.2",
     "@fern-fern/fdr-test-sdk": "^0.0.5297",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index bf8dd41766a..6ef20670a0a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -3856,8 +3856,8 @@ importers:
         specifier: workspace:*
         version: link:../../commons/core-utils
       '@fern-api/docs-parsers':
-        specifier: ^0.0.14
-        version: 0.0.14(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)
+        specifier: ^0.0.19
+        version: 0.0.19(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)
       '@fern-api/docs-preview':
         specifier: workspace:*
         version: link:../docs-preview
@@ -4239,8 +4239,8 @@ importers:
         specifier: workspace:*
         version: link:../../commons/path-utils
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.127.3-6479103bd
-        version: 0.127.3-6479103bd
+        specifier: 0.127.4-331678a74
+        version: 0.127.4-331678a74
       '@fern-fern/fiddle-sdk':
         specifier: 0.0.584
         version: 0.0.584
@@ -4288,8 +4288,8 @@ importers:
         specifier: workspace:*
         version: link:../task-context
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.127.3-6479103bd
-        version: 0.127.3-6479103bd
+        specifier: 0.127.4-331678a74
+        version: 0.127.4-331678a74
       '@fern-fern/fiddle-sdk':
         specifier: 0.0.584
         version: 0.0.584
@@ -4364,8 +4364,8 @@ importers:
         specifier: workspace:*
         version: link:../../task-context
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.127.3-6479103bd
-        version: 0.127.3-6479103bd
+        specifier: 0.127.4-331678a74
+        version: 0.127.4-331678a74
       js-yaml:
         specifier: ^4.1.0
         version: 4.1.0
@@ -4416,8 +4416,8 @@ importers:
         specifier: workspace:*
         version: link:../../task-context
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.127.3-6479103bd
-        version: 0.127.3-6479103bd
+        specifier: 0.127.4-331678a74
+        version: 0.127.4-331678a74
       gray-matter:
         specifier: ^4.0.3
         version: 4.0.3
@@ -4453,8 +4453,8 @@ importers:
         specifier: workspace:*
         version: link:../task-context
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.127.3-6479103bd
-        version: 0.127.3-6479103bd
+        specifier: 0.127.4-331678a74
+        version: 0.127.4-331678a74
       gray-matter:
         specifier: ^4.0.3
         version: 4.0.3
@@ -4504,18 +4504,24 @@ importers:
 
   packages/cli/docs-preview:
     dependencies:
+      '@fern-api/core-utils':
+        specifier: workspace:*
+        version: link:../../commons/core-utils
       '@fern-api/docs-resolver':
         specifier: workspace:*
         version: link:../docs-resolver
       '@fern-api/fdr-sdk':
-        specifier: 0.127.3-6479103bd
-        version: 0.127.3-6479103bd(typescript@4.6.4)
+        specifier: 0.127.4-331678a74
+        version: 0.127.4-331678a74(typescript@4.6.4)
       '@fern-api/fs-utils':
         specifier: workspace:*
         version: link:../../commons/fs-utils
       '@fern-api/ir-sdk':
         specifier: workspace:*
         version: link:../../ir-sdk
+      '@fern-api/lazy-fern-workspace':
+        specifier: workspace:*
+        version: link:../workspace/lazy-fern-workspace
       '@fern-api/logger':
         specifier: workspace:*
         version: link:../logger
@@ -4623,11 +4629,11 @@ importers:
         specifier: workspace:*
         version: link:../docs-markdown-utils
       '@fern-api/docs-parsers':
-        specifier: ^0.0.14
-        version: 0.0.14(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)
+        specifier: ^0.0.19
+        version: 0.0.19(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)
       '@fern-api/fdr-sdk':
-        specifier: 0.127.3-6479103bd
-        version: 0.127.3-6479103bd(typescript@4.6.4)
+        specifier: 0.127.4-331678a74
+        version: 0.127.4-331678a74(typescript@4.6.4)
       '@fern-api/fs-utils':
         specifier: workspace:*
         version: link:../../commons/fs-utils
@@ -4647,8 +4653,8 @@ importers:
         specifier: workspace:*
         version: link:../task-context
       '@fern-api/ui-core-utils':
-        specifier: 0.127.3-6479103bd
-        version: 0.127.3-6479103bd
+        specifier: 0.127.4-331678a74
+        version: 0.127.4-331678a74
       dayjs:
         specifier: ^1.11.11
         version: 1.11.11
@@ -4705,8 +4711,8 @@ importers:
         specifier: workspace:*
         version: link:../../commons/logging-execa
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.127.3-6479103bd
-        version: 0.127.3-6479103bd
+        specifier: 0.127.4-331678a74
+        version: 0.127.4-331678a74
       '@fern-typescript/fetcher':
         specifier: workspace:*
         version: link:../../../generators/typescript/utils/core-utilities/fetcher
@@ -5509,8 +5515,8 @@ importers:
         specifier: workspace:*
         version: link:../../../workspace/loader
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.127.3-6479103bd
-        version: 0.127.3-6479103bd
+        specifier: 0.127.4-331678a74
+        version: 0.127.4-331678a74
       '@fern-fern/fiddle-sdk':
         specifier: 0.0.584
         version: 0.0.584
@@ -5979,8 +5985,8 @@ importers:
         specifier: workspace:*
         version: link:../task-context
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.127.3-6479103bd
-        version: 0.127.3-6479103bd
+        specifier: 0.127.4-331678a74
+        version: 0.127.4-331678a74
       lodash-es:
         specifier: ^4.17.21
         version: 4.17.21
@@ -6757,8 +6763,8 @@ importers:
         specifier: 0.10.2
         version: 0.10.2
       '@fern-fern/fdr-cjs-sdk':
-        specifier: 0.127.3-6479103bd
-        version: 0.127.3-6479103bd
+        specifier: 0.127.4-331678a74
+        version: 0.127.4-331678a74
       '@fern-fern/fdr-test-sdk':
         specifier: ^0.0.5297
         version: 0.0.5297
@@ -8094,8 +8100,8 @@ packages:
   '@fern-api/core-utils@0.4.24-rc1':
     resolution: {integrity: sha512-aYu4lQK2qZIKzTF9TeFrICTPJ/zGEZUEWQmZt6pJeHu+R6afrcCBNkUleWU1OpHlDbe+xXUUBOktRg0PM9Hywg==}
 
-  '@fern-api/docs-parsers@0.0.14':
-    resolution: {integrity: sha512-82MLnKAATRiCjD3Xcf60Mw9vGSZ2yj7iy8xaRGWBGudDjZBb2p4kcj95musonaF2f/IFNkq4iX3AONgB7FNhYA==}
+  '@fern-api/docs-parsers@0.0.19':
+    resolution: {integrity: sha512-DWXyxW25dG/lCwAilvHcd394vHpSAF8wF1Q8P/PFxKBATHkVZxXHfmNeRC+soS4rn4E0vPOZJO3QR8d+ULZZkg==}
 
   '@fern-api/dynamic-ir-sdk@53.24.0':
     resolution: {integrity: sha512-4XvzvSsh7lNZz5oYN0LH+FRpFGxg9TjfdipSJMpgHvPShe85m/tcfbOzbS0DHBpQGlKb/gHQtQRPAoBR1wdDAw==}
@@ -8103,8 +8109,8 @@ packages:
   '@fern-api/dynamic-ir-sdk@54.0.0':
     resolution: {integrity: sha512-5ewX7042AGuw697jA6ubulCIQbfTM2HC8UbHxTakE0px871HJTRwHNT2Y9o2kjMbsRXTzyYdb5lOVr+85sc/KQ==}
 
-  '@fern-api/fdr-sdk@0.127.3-6479103bd':
-    resolution: {integrity: sha512-9WPubeQHSQJ2ece9lG2TY4Rc879e7AhvDYOamlYqsD5gy16eATRUkOvj7d6pWch5JwYJaMM8jcdZrQ9dltf/qQ==}
+  '@fern-api/fdr-sdk@0.127.4-331678a74':
+    resolution: {integrity: sha512-uat4R+gWFoe8UT67q0Yhc6dDwHUn84Jb6do7r5tDk4fUWcy4oPaCMQxutvyclNj6M3AUtFY8uEy/8dCNgk3ADA==}
 
   '@fern-api/logger@0.4.24-rc1':
     resolution: {integrity: sha512-yh0E2F3K3IPnJZcE4dv+u8I51iKgTgv/reinKo4K5YmYEG1iLtw5vBEYMOPkQmsYFPAKIh++OMB/6TrsahMWew==}
@@ -8118,8 +8124,8 @@ packages:
   '@fern-api/ui-core-utils@0.0.0':
     resolution: {integrity: sha512-8T3YLd+n8z5Vs+WNRIwH6PUW31ZC4/lkRD5G2+qyBcdePfOVYV3CHp3eiUrSSArOr0SJmzN/mQwPm3iAaey7nw==}
 
-  '@fern-api/ui-core-utils@0.127.3-6479103bd':
-    resolution: {integrity: sha512-WLrD3Ad2zzPGfVickTiJ1JoKN97Px9Dzu+Zl8oHcreIdf3Ngmf5LH/jCcwRx7LenRKdRj6+UMFBxA1ZdVDg3ng==}
+  '@fern-api/ui-core-utils@0.127.4-331678a74':
+    resolution: {integrity: sha512-hBUEOTKVbGqfKQ+cA8MR1jvn4XYVqTBkW3I0G1LF0NSgzRr8dvpL+BYGmhLQkXweOjTfYsVNIvqzX80oUU2Urw==}
 
   '@fern-api/venus-api-sdk@0.10.2':
     resolution: {integrity: sha512-BD18ZNJeWYvztRXSUWY2lfZ8jFUbNAfHWctvIsWyXgI7C8EL3N0+CWUGD5cZ1QqRnq42nm6XJdWRKhny3yrz4g==}
@@ -8127,8 +8133,8 @@ packages:
   '@fern-fern/docs-config@0.0.80':
     resolution: {integrity: sha512-wAZCNxwM4qIPn3idoIihPP65KWPjNuoTSfdP4+5f8K2jJLgs5cdkY0pm4cQlGWvi5K6b+lfbUWDaslnXscJ2gQ==}
 
-  '@fern-fern/fdr-cjs-sdk@0.127.3-6479103bd':
-    resolution: {integrity: sha512-nYpgLaorgK0s+6P6iKC8TYa4QF4RjZxr4y5/jogpkQc74sm2fmZq7vpRiCTmr9wt+Ei6EZqbemqvULh6G8y25g==}
+  '@fern-fern/fdr-cjs-sdk@0.127.4-331678a74':
+    resolution: {integrity: sha512-ZWWiN71iD/xK9zZPBac5dL2UU3iJPOmK9SazVwPkTxcAMRgVX+Pu/hNKz07NEvQD79l4otCmK5PB8IYMyqlncw==}
 
   '@fern-fern/fdr-test-sdk@0.0.5297':
     resolution: {integrity: sha512-jrZUZ6oIA64LHtrv77xEq0X7qJhT9xRMGWhKcLjIUArMsD7h6KMWUHVdoB/1MP0Mz/uL/E2xmM31SOgJicpIcA==}
@@ -15233,7 +15239,7 @@ snapshots:
       lodash-es: 4.17.21
       strip-ansi: 7.1.0
 
-  '@fern-api/docs-parsers@0.0.14(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)':
+  '@fern-api/docs-parsers@0.0.19(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)':
     dependencies:
       '@fern-api/logger': 0.4.24-rc1
       '@fern-api/ui-core-utils': 0.0.0
@@ -15265,9 +15271,9 @@ snapshots:
 
   '@fern-api/dynamic-ir-sdk@54.0.0': {}
 
-  '@fern-api/fdr-sdk@0.127.3-6479103bd(typescript@4.6.4)':
+  '@fern-api/fdr-sdk@0.127.4-331678a74(typescript@4.6.4)':
     dependencies:
-      '@fern-api/ui-core-utils': 0.127.3-6479103bd
+      '@fern-api/ui-core-utils': 0.127.4-331678a74
       '@ungap/structured-clone': 1.2.0
       dayjs: 1.11.11
       es-toolkit: 1.30.1
@@ -15312,7 +15318,7 @@ snapshots:
       title: 3.5.3
       ua-parser-js: 1.0.37
 
-  '@fern-api/ui-core-utils@0.127.3-6479103bd':
+  '@fern-api/ui-core-utils@0.127.4-331678a74':
     dependencies:
       date-fns: 4.1.0
       date-fns-tz: 3.2.0(date-fns@4.1.0)
@@ -15334,7 +15340,7 @@ snapshots:
 
   '@fern-fern/docs-config@0.0.80': {}
 
-  '@fern-fern/fdr-cjs-sdk@0.127.3-6479103bd':
+  '@fern-fern/fdr-cjs-sdk@0.127.4-331678a74':
     dependencies:
       form-data: 4.0.0
       formdata-node: 6.0.3

From cdc8d6831c73d2b73415f60674ad8b17453c26cf Mon Sep 17 00:00:00 2001
From: Rohin Bhargava <rohin@buildwithfern.com>
Date: Tue, 7 Jan 2025 18:00:10 -0500
Subject: [PATCH 04/11] json schema

---
 docs-yml.schema.json | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/docs-yml.schema.json b/docs-yml.schema.json
index e0df9708bf3..86d1d728042 100644
--- a/docs-yml.schema.json
+++ b/docs-yml.schema.json
@@ -2214,6 +2214,16 @@
               "type": "null"
             }
           ]
+        },
+        "direct-openapi-parser": {
+          "oneOf": [
+            {
+              "type": "boolean"
+            },
+            {
+              "type": "null"
+            }
+          ]
         }
       },
       "additionalProperties": false

From 0c89750ef95e6eb17f8b43d4f628096fb588ad7f Mon Sep 17 00:00:00 2001
From: Rohin Bhargava <rohin@buildwithfern.com>
Date: Tue, 7 Jan 2025 19:16:36 -0500
Subject: [PATCH 05/11] remove unused deps

---
 packages/cli/cli/package.json |  2 --
 pnpm-lock.yaml                | 34 ----------------------------------
 2 files changed, 36 deletions(-)

diff --git a/packages/cli/cli/package.json b/packages/cli/cli/package.json
index 9942ff1caad..c04bc4833de 100644
--- a/packages/cli/cli/package.json
+++ b/packages/cli/cli/package.json
@@ -45,7 +45,6 @@
     "@fern-api/configuration-loader": "workspace:*",
     "@fern-api/core": "workspace:*",
     "@fern-api/core-utils": "workspace:*",
-    "@fern-api/docs-parsers": "^0.0.19",  
     "@fern-api/docs-preview": "workspace:*",
     "@fern-api/docs-resolver": "workspace:*",
     "@fern-api/docs-validator": "workspace:*",
@@ -105,7 +104,6 @@
     "js-yaml": "^4.1.0",
     "latest-version": "^9.0.0",
     "lodash-es": "^4.17.21",
-    "openapi-types": "^12.1.3",
     "ora": "^7.0.1",
     "@trivago/prettier-plugin-sort-imports": "^5.2.1",
     "prettier": "^3.4.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 77af3d10e13..fd6232aaa36 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -3941,9 +3941,6 @@ importers:
       '@fern-api/core-utils':
         specifier: workspace:*
         version: link:../../commons/core-utils
-      '@fern-api/docs-parsers':
-        specifier: ^0.0.19
-        version: 0.0.19(@types/node@18.15.3)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@5.7.2)
       '@fern-api/docs-preview':
         specifier: workspace:*
         version: link:../docs-preview
@@ -4124,9 +4121,6 @@ importers:
       lodash-es:
         specifier: ^4.17.21
         version: 4.17.21
-      openapi-types:
-        specifier: ^12.1.3
-        version: 12.1.3
       ora:
         specifier: ^7.0.1
         version: 7.0.1
@@ -15676,34 +15670,6 @@ snapshots:
       lodash-es: 4.17.21
       strip-ansi: 7.1.0
 
-  '@fern-api/docs-parsers@0.0.19(@types/node@18.15.3)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@5.7.2)':
-    dependencies:
-      '@fern-api/logger': 0.4.24-rc1
-      '@fern-api/ui-core-utils': 0.0.0
-      es-toolkit: 1.30.1
-      openapi-types: 12.1.3
-      ts-essentials: 10.0.1(typescript@5.7.2)
-      uuid: 9.0.1
-      vitest: 2.1.8(@types/node@18.15.3)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)
-      whatwg-mimetype: 4.0.0
-    transitivePeerDependencies:
-      - '@edge-runtime/vm'
-      - '@types/node'
-      - '@vitest/browser'
-      - '@vitest/ui'
-      - happy-dom
-      - jsdom
-      - less
-      - lightningcss
-      - msw
-      - sass
-      - sass-embedded
-      - stylus
-      - sugarss
-      - supports-color
-      - terser
-      - typescript
-
   '@fern-api/docs-parsers@0.0.19(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)':
     dependencies:
       '@fern-api/logger': 0.4.24-rc1

From 530977e7bc1d809f6c5eff1c4c0e9da4147c9985 Mon Sep 17 00:00:00 2001
From: Rohin Bhargava <rohin@buildwithfern.com>
Date: Tue, 7 Jan 2025 19:18:31 -0500
Subject: [PATCH 06/11] fix issues with newer fdr version

---
 packages/cli/docs-importers/mintlify/src/convertMarkdown.ts | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/packages/cli/docs-importers/mintlify/src/convertMarkdown.ts b/packages/cli/docs-importers/mintlify/src/convertMarkdown.ts
index b6c5ec18610..8e0d39d5989 100644
--- a/packages/cli/docs-importers/mintlify/src/convertMarkdown.ts
+++ b/packages/cli/docs-importers/mintlify/src/convertMarkdown.ts
@@ -2,7 +2,7 @@ import { readFile } from "fs/promises";
 import grayMatter from "gray-matter";
 
 import { FernDocsBuilder } from "@fern-api/docs-importer-commons";
-import { AbsoluteFilePath, RelativeFilePath, dirname, join, relativize } from "@fern-api/fs-utils";
+import { AbsoluteFilePath, RelativeFilePath, dirname, join } from "@fern-api/fs-utils";
 
 import { FernRegistry as CjsFdrSdk, FernRegistry } from "@fern-fern/fdr-cjs-sdk";
 
@@ -84,7 +84,9 @@ export async function convertMarkdown({
             "twitter:card": undefined,
             noindex: undefined,
             nofollow: undefined,
-            "jsonld:breadcrumb": undefined
+            "jsonld:breadcrumb": undefined,
+            logo: undefined,
+            keywords: undefined
         },
         content: transformedContent
     };

From d02c88a4822136f94b211202af5d94bd6a1e3e00 Mon Sep 17 00:00:00 2001
From: Rohin Bhargava <rohin@buildwithfern.com>
Date: Tue, 7 Jan 2025 19:25:53 -0500
Subject: [PATCH 07/11] linter

---
 packages/cli/docs-resolver/package.json |  1 -
 pnpm-lock.yaml                          | 68 -------------------------
 2 files changed, 69 deletions(-)

diff --git a/packages/cli/docs-resolver/package.json b/packages/cli/docs-resolver/package.json
index 342a46e2a60..fcb25ce6e9c 100644
--- a/packages/cli/docs-resolver/package.json
+++ b/packages/cli/docs-resolver/package.json
@@ -52,7 +52,6 @@
     "depcheck": "^1.4.6",
     "eslint": "^8.56.0",
     "openapi-types": "^10.0.0",
-    "organize-imports-cli": "^0.10.0",
     "prettier": "^2.7.1",
     "typescript": "4.6.4",
     "vitest": "^2.0.5"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index fd6232aaa36..d31e87d907e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -4767,9 +4767,6 @@ importers:
       openapi-types:
         specifier: ^10.0.0
         version: 10.0.0
-      organize-imports-cli:
-        specifier: ^0.10.0
-        version: 0.10.0
       prettier:
         specifier: ^2.7.1
         version: 2.8.8
@@ -9145,12 +9142,6 @@ packages:
   '@types/stream-json@1.7.7':
     resolution: {integrity: sha512-hHG7cLQ09H/m9i0jzL6UJAeLLxIWej90ECn0svO4T8J0nGcl89xZDQ2ujT4WKlvg0GWkcxJbjIDzW/v7BYUM6Q==}
 
-  '@types/strip-bom@3.0.0':
-    resolution: {integrity: sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==}
-
-  '@types/strip-json-comments@0.0.30':
-    resolution: {integrity: sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==}
-
   '@types/swagger2openapi@7.0.4':
     resolution: {integrity: sha512-ffMqzciTDihOKH4Q//9Ond1yb5JP1P5FC/aFPsLK4blea1Fwk2aYctiNCkAh5etDYFswFXS+5LV/vuGkf+PU6A==}
 
@@ -10394,10 +10385,6 @@ packages:
   ecdsa-sig-formatter@1.0.11:
     resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
 
-  editorconfig@0.15.3:
-    resolution: {integrity: sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==}
-    hasBin: true
-
   ee-first@1.1.1:
     resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
 
@@ -11947,9 +11934,6 @@ packages:
     resolution: {integrity: sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==}
     engines: {node: 20 || >=22}
 
-  lru-cache@4.1.5:
-    resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
-
   lru-cache@5.1.1:
     resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
 
@@ -12479,10 +12463,6 @@ packages:
     resolution: {integrity: sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==}
     engines: {node: '>=16'}
 
-  organize-imports-cli@0.10.0:
-    resolution: {integrity: sha512-cVyNEeiDxX/zA6gdK1QS2rr3TK1VymIkT0LagnAk4f6eE0IC0bo3BeUkMzm3q3GnCJzYC+6lfuMpBE0Cequ7Vg==}
-    hasBin: true
-
   os-tmpdir@1.0.2:
     resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
     engines: {node: '>=0.10.0'}
@@ -12822,9 +12802,6 @@ packages:
   proxy-from-env@1.1.0:
     resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
 
-  pseudomap@1.0.2:
-    resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
-
   psl@1.9.0:
     resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
 
@@ -13231,9 +13208,6 @@ packages:
   siginfo@2.0.0:
     resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
 
-  sigmund@1.0.1:
-    resolution: {integrity: sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==}
-
   signal-exit@3.0.7:
     resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
 
@@ -13789,9 +13763,6 @@ packages:
   tsconfig-paths@3.15.0:
     resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
 
-  tsconfig@7.0.0:
-    resolution: {integrity: sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==}
-
   tslib@1.14.1:
     resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
 
@@ -14399,9 +14370,6 @@ packages:
     resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
     engines: {node: '>=10'}
 
-  yallist@2.1.2:
-    resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
-
   yallist@3.1.1:
     resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
 
@@ -16779,10 +16747,6 @@ snapshots:
       '@types/node': 18.15.3
       '@types/stream-chain': 2.1.0
 
-  '@types/strip-bom@3.0.0': {}
-
-  '@types/strip-json-comments@0.0.30': {}
-
   '@types/swagger2openapi@7.0.4':
     dependencies:
       '@types/node': 18.15.3
@@ -18201,13 +18165,6 @@ snapshots:
     dependencies:
       safe-buffer: 5.2.1
 
-  editorconfig@0.15.3:
-    dependencies:
-      commander: 2.20.3
-      lru-cache: 4.1.5
-      semver: 5.7.2
-      sigmund: 1.0.1
-
   ee-first@1.1.1: {}
 
   ejs@3.1.10:
@@ -20306,11 +20263,6 @@ snapshots:
 
   lru-cache@11.0.1: {}
 
-  lru-cache@4.1.5:
-    dependencies:
-      pseudomap: 1.0.2
-      yallist: 2.1.2
-
   lru-cache@5.1.1:
     dependencies:
       yallist: 3.1.1
@@ -21161,13 +21113,6 @@ snapshots:
       string-width: 6.1.0
       strip-ansi: 7.1.0
 
-  organize-imports-cli@0.10.0:
-    dependencies:
-      chalk: 4.1.2
-      editorconfig: 0.15.3
-      ts-morph: 15.1.0
-      tsconfig: 7.0.0
-
   os-tmpdir@1.0.2: {}
 
   p-finally@1.0.0: {}
@@ -21448,8 +21393,6 @@ snapshots:
 
   proxy-from-env@1.1.0: {}
 
-  pseudomap@1.0.2: {}
-
   psl@1.9.0: {}
 
   punycode@2.3.1: {}
@@ -21967,8 +21910,6 @@ snapshots:
 
   siginfo@2.0.0: {}
 
-  sigmund@1.0.1: {}
-
   signal-exit@3.0.7: {}
 
   signal-exit@4.1.0: {}
@@ -22672,13 +22613,6 @@ snapshots:
       minimist: 1.2.6
       strip-bom: 3.0.0
 
-  tsconfig@7.0.0:
-    dependencies:
-      '@types/strip-bom': 3.0.0
-      '@types/strip-json-comments': 0.0.30
-      strip-bom: 3.0.0
-      strip-json-comments: 2.0.1
-
   tslib@1.14.1: {}
 
   tslib@2.6.2: {}
@@ -23552,8 +23486,6 @@ snapshots:
 
   y18n@5.0.8: {}
 
-  yallist@2.1.2: {}
-
   yallist@3.1.1: {}
 
   yallist@4.0.0: {}

From bb2acdb070ed702163c61871bc4877e047885b0e Mon Sep 17 00:00:00 2001
From: Rohin Bhargava <rohin@buildwithfern.com>
Date: Tue, 7 Jan 2025 19:38:12 -0500
Subject: [PATCH 08/11] format

---
 ...nerateOpenApiToFdrApiDefinitionForWorkspaces.ts |  6 ++++--
 .../src/commands/generate/generateDocsWorkspace.ts |  4 ++--
 .../writeDocsDefinitionForProject.ts               |  6 +++---
 packages/cli/docs-preview/src/previewDocs.ts       |  5 +++--
 .../docs-resolver/src/ApiReferenceNodeConverter.ts |  2 +-
 .../src/ApiReferenceNodeConverterLatest.ts         | 14 ++++++++------
 .../docs-resolver/src/DocsDefinitionResolver.ts    |  8 ++++----
 .../src/utils/generateFdrFromOpenApiWorkspace.ts   | 13 +++++++------
 .../remote-workspace-runner/src/publishDocs.ts     |  2 +-
 .../src/runRemoteGenerationForDocsWorkspace.ts     |  2 +-
 10 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/packages/cli/cli/src/commands/generate-openapi-fdr/generateOpenApiToFdrApiDefinitionForWorkspaces.ts b/packages/cli/cli/src/commands/generate-openapi-fdr/generateOpenApiToFdrApiDefinitionForWorkspaces.ts
index 01111d8101f..720a6f3f7a1 100644
--- a/packages/cli/cli/src/commands/generate-openapi-fdr/generateOpenApiToFdrApiDefinitionForWorkspaces.ts
+++ b/packages/cli/cli/src/commands/generate-openapi-fdr/generateOpenApiToFdrApiDefinitionForWorkspaces.ts
@@ -1,9 +1,11 @@
 import { writeFile } from "fs/promises";
 import path from "path";
-import { CliContext } from "../../cli-context/CliContext";
+
 import { generateFdrFromOpenApiWorkspace } from "@fern-api/docs-resolver";
-import { Project } from "@fern-api/project-loader";
 import { AbsoluteFilePath, stringifyLargeObject } from "@fern-api/fs-utils";
+import { Project } from "@fern-api/project-loader";
+
+import { CliContext } from "../../cli-context/CliContext";
 
 export async function generateOpenApiToFdrApiDefinitionForWorkspaces({
     project,
diff --git a/packages/cli/cli/src/commands/generate/generateDocsWorkspace.ts b/packages/cli/cli/src/commands/generate/generateDocsWorkspace.ts
index 13017c14214..389500144c3 100644
--- a/packages/cli/cli/src/commands/generate/generateDocsWorkspace.ts
+++ b/packages/cli/cli/src/commands/generate/generateDocsWorkspace.ts
@@ -1,12 +1,12 @@
 import { createOrganizationIfDoesNotExist } from "@fern-api/auth";
+import { isNonNullish } from "@fern-api/core-utils";
+import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
 import { askToLogin } from "@fern-api/login";
 import { Project } from "@fern-api/project-loader";
 import { runRemoteGenerationForDocsWorkspace } from "@fern-api/remote-workspace-runner";
 
 import { CliContext } from "../../cli-context/CliContext";
 import { validateDocsWorkspaceAndLogIssues } from "../validate/validateDocsWorkspaceAndLogIssues";
-import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
-import { isNonNullish } from "@fern-api/core-utils";
 
 export async function generateDocsWorkspace({
     project,
diff --git a/packages/cli/cli/src/commands/write-docs-definition/writeDocsDefinitionForProject.ts b/packages/cli/cli/src/commands/write-docs-definition/writeDocsDefinitionForProject.ts
index 19e1fbbe053..92b9aa4ce02 100644
--- a/packages/cli/cli/src/commands/write-docs-definition/writeDocsDefinitionForProject.ts
+++ b/packages/cli/cli/src/commands/write-docs-definition/writeDocsDefinitionForProject.ts
@@ -1,13 +1,13 @@
 import chalk from "chalk";
 import { writeFile } from "fs/promises";
 
+import { isNonNullish } from "@fern-api/core-utils";
 import { DocsDefinitionResolver } from "@fern-api/docs-resolver";
+import { AbsoluteFilePath } from "@fern-api/fs-utils";
 import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
-import { isNonNullish } from "@fern-api/core-utils";
-
 import { Project } from "@fern-api/project-loader";
+
 import { CliContext } from "../../cli-context/CliContext";
-import { AbsoluteFilePath } from "@fern-api/fs-utils";
 
 export async function writeDocsDefinitionForProject({
     project,
diff --git a/packages/cli/docs-preview/src/previewDocs.ts b/packages/cli/docs-preview/src/previewDocs.ts
index f860dfab4b2..1ec1f6abb51 100644
--- a/packages/cli/docs-preview/src/previewDocs.ts
+++ b/packages/cli/docs-preview/src/previewDocs.ts
@@ -1,5 +1,6 @@
 import { v4 as uuidv4 } from "uuid";
 
+import { isNonNullish } from "@fern-api/core-utils";
 import { DocsDefinitionResolver } from "@fern-api/docs-resolver";
 import {
     APIV1Read,
@@ -15,11 +16,11 @@ import {
 } from "@fern-api/fdr-sdk";
 import { convertToFernHostAbsoluteFilePath } from "@fern-api/fs-utils";
 import { IntermediateRepresentation } from "@fern-api/ir-sdk";
+import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
 import { Project } from "@fern-api/project-loader";
 import { convertIrToFdrApi } from "@fern-api/register";
 import { TaskContext } from "@fern-api/task-context";
-import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
-import { isNonNullish } from "@fern-api/core-utils";
+
 import { parseDocsConfiguration } from "../../configuration-loader/src/docs-yml/parseDocsConfiguration";
 
 export async function getPreviewDocsDefinition({
diff --git a/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts b/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts
index 437f385feb2..c1d2092462b 100644
--- a/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts
+++ b/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts
@@ -4,7 +4,7 @@ import urlJoin from "url-join";
 import { docsYml } from "@fern-api/configuration-loader";
 import { isNonNullish } from "@fern-api/core-utils";
 import { APIV1Read, FernNavigation } from "@fern-api/fdr-sdk";
-import { AbsoluteFilePath, relative, RelativeFilePath } from "@fern-api/fs-utils";
+import { AbsoluteFilePath, RelativeFilePath, relative } from "@fern-api/fs-utils";
 import { TaskContext } from "@fern-api/task-context";
 import { titleCase, visitDiscriminatedUnion } from "@fern-api/ui-core-utils";
 import { DocsWorkspace, FernWorkspace } from "@fern-api/workspace-loader";
diff --git a/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts b/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts
index ede0ae31e0c..0bb81339273 100644
--- a/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts
+++ b/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts
@@ -1,17 +1,19 @@
+import { camelCase, kebabCase } from "lodash-es";
+import urlJoin from "url-join";
+import { threadId } from "worker_threads";
+
 import { docsYml } from "@fern-api/configuration-loader";
 import { isNonNullish } from "@fern-api/core-utils";
 import { FdrAPI, FernNavigation } from "@fern-api/fdr-sdk";
-import { AbsoluteFilePath, relative, RelativeFilePath } from "@fern-api/fs-utils";
+import { AbsoluteFilePath, RelativeFilePath, relative } from "@fern-api/fs-utils";
+import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
 import { TaskContext } from "@fern-api/task-context";
+import { titleCase, visitDiscriminatedUnion } from "@fern-api/ui-core-utils";
 import { DocsWorkspace, FernWorkspace } from "@fern-api/workspace-loader";
-import { camelCase, kebabCase } from "lodash-es";
-import urlJoin from "url-join";
+
 import { ChangelogNodeConverter } from "./ChangelogNodeConverter";
 import { NodeIdGenerator } from "./NodeIdGenerator";
 import { stringifyEndpointPathParts } from "./utils/stringifyEndpointPathParts";
-import { titleCase, visitDiscriminatedUnion } from "@fern-api/ui-core-utils";
-import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
-import { threadId } from "worker_threads";
 
 // TODO: these functions need an extra piece of information from the fdr latest shape, to see if the operation id takes precedence over slug generation
 function getLatestEndpointUrlSlug(endpoint: FdrAPI.api.latest.endpoint.EndpointDefinition) {
diff --git a/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts b/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts
index 6ae8feeb41f..15db2285e27 100644
--- a/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts
+++ b/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts
@@ -15,22 +15,22 @@ import {
     replaceReferencedMarkdown
 } from "@fern-api/docs-markdown-utils";
 import { APIV1Write, DocsV1Write, FdrAPI, FernNavigation } from "@fern-api/fdr-sdk";
-import { AbsoluteFilePath, listFiles, relative, RelativeFilePath, resolve } from "@fern-api/fs-utils";
+import { AbsoluteFilePath, RelativeFilePath, listFiles, relative, resolve } from "@fern-api/fs-utils";
 import { generateIntermediateRepresentation } from "@fern-api/ir-generator";
 import { IntermediateRepresentation } from "@fern-api/ir-sdk";
+import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
 import { TaskContext } from "@fern-api/task-context";
 import { DocsWorkspace, FernWorkspace } from "@fern-api/workspace-loader";
 
 import { ApiReferenceNodeConverter } from "./ApiReferenceNodeConverter";
+import { ApiReferenceNodeConverterLatest } from "./ApiReferenceNodeConverterLatest";
 import { ChangelogNodeConverter } from "./ChangelogNodeConverter";
 import { NodeIdGenerator } from "./NodeIdGenerator";
 import { convertDocsSnippetsConfigToFdr } from "./utils/convertDocsSnippetsConfigToFdr";
 import { convertIrToApiDefinition } from "./utils/convertIrToApiDefinition";
+import { generateFdrFromOpenApiWorkspace } from "./utils/generateFdrFromOpenApiWorkspace";
 import { collectFilesFromDocsConfig } from "./utils/getImageFilepathsToUpload";
 import { wrapWithHttps } from "./wrapWithHttps";
-import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
-import { generateFdrFromOpenApiWorkspace } from "./utils/generateFdrFromOpenApiWorkspace";
-import { ApiReferenceNodeConverterLatest } from "./ApiReferenceNodeConverterLatest";
 
 dayjs.extend(utc);
 
diff --git a/packages/cli/docs-resolver/src/utils/generateFdrFromOpenApiWorkspace.ts b/packages/cli/docs-resolver/src/utils/generateFdrFromOpenApiWorkspace.ts
index d67cb531b35..ba186b30b4a 100644
--- a/packages/cli/docs-resolver/src/utils/generateFdrFromOpenApiWorkspace.ts
+++ b/packages/cli/docs-resolver/src/utils/generateFdrFromOpenApiWorkspace.ts
@@ -1,12 +1,13 @@
-import { getAllOpenAPISpecs, LazyFernWorkspace, OSSWorkspace, OpenAPILoader } from "@fern-api/lazy-fern-workspace";
+import { merge } from "lodash-es";
+import { OpenAPIV3_1 } from "openapi-types";
+
+import { AbstractAPIWorkspace } from "@fern-api/api-workspace-commons";
 import {
+    BaseOpenApiV3_1ConverterNodeContext,
     ErrorCollector,
-    OpenApiDocumentConverterNode,
-    BaseOpenApiV3_1ConverterNodeContext
+    OpenApiDocumentConverterNode
 } from "@fern-api/docs-parsers";
-import { OpenAPIV3_1 } from "openapi-types";
-import { merge } from "lodash-es";
-import { AbstractAPIWorkspace } from "@fern-api/api-workspace-commons";
+import { LazyFernWorkspace, OSSWorkspace, OpenAPILoader, getAllOpenAPISpecs } from "@fern-api/lazy-fern-workspace";
 import { TaskContext } from "@fern-api/task-context";
 
 export async function generateFdrFromOpenApiWorkspace(
diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts
index d5be4e30270..d0941a96b7b 100644
--- a/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts
+++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts
@@ -18,8 +18,8 @@ import { DocsWorkspace, FernWorkspace } from "@fern-api/workspace-loader";
 
 import { FernRegistry as CjsFdrSdk } from "@fern-fern/fdr-cjs-sdk";
 
-import { measureImageSizes } from "./measureImageSizes";
 import { OSSWorkspace } from "../../../../workspace/lazy-fern-workspace/src";
+import { measureImageSizes } from "./measureImageSizes";
 
 const MEASURE_IMAGE_BATCH_SIZE = 10;
 const UPLOAD_FILE_BATCH_SIZE = 10;
diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForDocsWorkspace.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForDocsWorkspace.ts
index 67959fed421..1e409d22867 100644
--- a/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForDocsWorkspace.ts
+++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/runRemoteGenerationForDocsWorkspace.ts
@@ -3,8 +3,8 @@ import { replaceEnvVariables } from "@fern-api/core-utils";
 import { TaskContext } from "@fern-api/task-context";
 import { DocsWorkspace, FernWorkspace } from "@fern-api/workspace-loader";
 
-import { publishDocs } from "./publishDocs";
 import { OSSWorkspace } from "../../../../workspace/lazy-fern-workspace/src";
+import { publishDocs } from "./publishDocs";
 
 export async function runRemoteGenerationForDocsWorkspace({
     organization,

From f598160259412d55b33af0bcb350a7d7a8f3675b Mon Sep 17 00:00:00 2001
From: Rohin Bhargava <rohin@buildwithfern.com>
Date: Wed, 8 Jan 2025 16:39:04 -0500
Subject: [PATCH 09/11] added fixture test for when fdr-sdk supports directory
 imports

---
 packages/cli/docs-resolver/package.json       |   2 +-
 .../src/ApiReferenceNodeConverter.ts          | 154 ++------
 .../src/ApiReferenceNodeConverterLatest.ts    | 205 ++++-------
 .../fixtures/openapi-latest/fern/docs.yml     |   9 +
 .../openapi-latest/fern/fern.config.json      |   4 +
 .../openapi-latest/fern/generators.yml        |   1 +
 .../fixtures/openapi-latest/fern/openapi.yml  | 332 ++++++++++++++++++
 .../src/__test__/openapi-latest.test.ts       |  79 +++++
 .../src/utils/convertIrToApiDefinition.ts     |   8 +-
 .../src/utils/convertPlaygroundSettings.ts    |  27 ++
 .../src/utils/enrichApiPackageChild.ts        |  48 +++
 .../src/utils/mergeAndFilterChildren.ts       |  27 ++
 .../src/utils/mergeEndpointPairs.ts           |  58 +++
 .../cli/docs-resolver/src/utils/toPageNode.ts |  42 +++
 .../src/utils/toRelativeFilepath.ts           |  17 +
 pnpm-lock.yaml                                |  10 +-
 16 files changed, 750 insertions(+), 273 deletions(-)
 create mode 100644 packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/docs.yml
 create mode 100644 packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/fern.config.json
 create mode 100644 packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/generators.yml
 create mode 100644 packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/openapi.yml
 create mode 100644 packages/cli/docs-resolver/src/__test__/openapi-latest.test.ts
 create mode 100644 packages/cli/docs-resolver/src/utils/convertPlaygroundSettings.ts
 create mode 100644 packages/cli/docs-resolver/src/utils/enrichApiPackageChild.ts
 create mode 100644 packages/cli/docs-resolver/src/utils/mergeAndFilterChildren.ts
 create mode 100644 packages/cli/docs-resolver/src/utils/mergeEndpointPairs.ts
 create mode 100644 packages/cli/docs-resolver/src/utils/toPageNode.ts
 create mode 100644 packages/cli/docs-resolver/src/utils/toRelativeFilepath.ts

diff --git a/packages/cli/docs-resolver/package.json b/packages/cli/docs-resolver/package.json
index fcb25ce6e9c..d5669729c38 100644
--- a/packages/cli/docs-resolver/package.json
+++ b/packages/cli/docs-resolver/package.json
@@ -31,7 +31,7 @@
     "@fern-api/configuration-loader": "workspace:*",
     "@fern-api/core-utils": "workspace:*",
     "@fern-api/docs-markdown-utils": "workspace:*",
-    "@fern-api/docs-parsers": "^0.0.19",
+    "@fern-api/docs-parsers": "^0.0.20",
     "@fern-api/fdr-sdk": "0.127.4-331678a74",
     "@fern-api/lazy-fern-workspace": "workspace:*",
     "@fern-api/ui-core-utils": "0.127.4-331678a74",
diff --git a/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts b/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts
index c1d2092462b..5c222480b4a 100644
--- a/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts
+++ b/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts
@@ -4,7 +4,7 @@ import urlJoin from "url-join";
 import { docsYml } from "@fern-api/configuration-loader";
 import { isNonNullish } from "@fern-api/core-utils";
 import { APIV1Read, FernNavigation } from "@fern-api/fdr-sdk";
-import { AbsoluteFilePath, RelativeFilePath, relative } from "@fern-api/fs-utils";
+import { AbsoluteFilePath } from "@fern-api/fs-utils";
 import { TaskContext } from "@fern-api/task-context";
 import { titleCase, visitDiscriminatedUnion } from "@fern-api/ui-core-utils";
 import { DocsWorkspace, FernWorkspace } from "@fern-api/workspace-loader";
@@ -12,8 +12,14 @@ import { DocsWorkspace, FernWorkspace } from "@fern-api/workspace-loader";
 import { ApiDefinitionHolder } from "./ApiDefinitionHolder";
 import { ChangelogNodeConverter } from "./ChangelogNodeConverter";
 import { NodeIdGenerator } from "./NodeIdGenerator";
+import { convertPlaygroundSettings } from "./utils/convertPlaygroundSettings";
+import { enrichApiPackageChild } from "./utils/enrichApiPackageChild";
 import { isSubpackage } from "./utils/isSubpackage";
+import { mergeAndFilterChildren } from "./utils/mergeAndFilterChildren";
+import { mergeEndpointPairs } from "./utils/mergeEndpointPairs";
 import { stringifyEndpointPathParts } from "./utils/stringifyEndpointPathParts";
+import { toPageNode } from "./utils/toPageNode";
+import { toRelativeFilepath } from "./utils/toRelativeFilepath";
 
 export class ApiReferenceNodeConverter {
     apiDefinitionId: FernNavigation.V1.ApiDefinitionId;
@@ -47,7 +53,7 @@ export class ApiReferenceNodeConverter {
 
         this.#overviewPageId =
             this.apiSection.overviewAbsolutePath != null
-                ? FernNavigation.V1.PageId(this.toRelativeFilepath(this.apiSection.overviewAbsolutePath))
+                ? FernNavigation.V1.PageId(toRelativeFilepath(this.docsWorkspace, this.apiSection.overviewAbsolutePath))
                 : undefined;
 
         // the overview page markdown could contain a full slug, which would be used as the base slug for the API section.
@@ -148,24 +154,13 @@ export class ApiReferenceNodeConverter {
         page: docsYml.DocsNavigationItem.Page,
         parentSlug: FernNavigation.V1.SlugGenerator
     ): FernNavigation.V1.PageNode {
-        const pageId = FernNavigation.V1.PageId(this.toRelativeFilepath(page.absolutePath));
-        const pageSlug = parentSlug.apply({
-            fullSlug: this.markdownFilesToFullSlugs.get(page.absolutePath)?.split("/"),
-            urlSlug: page.slug ?? kebabCase(page.title)
+        return toPageNode({
+            page,
+            parentSlug,
+            docsWorkspace: this.docsWorkspace,
+            markdownFilesToFullSlugs: this.markdownFilesToFullSlugs,
+            idgen: this.#idgen
         });
-        return {
-            id: this.#idgen.get(pageId),
-            type: "page",
-            pageId,
-            title: page.title,
-            slug: pageSlug.get(),
-            icon: page.icon,
-            hidden: page.hidden,
-            noindex: page.noindex,
-            authed: undefined,
-            viewers: page.viewers,
-            orphaned: page.orphaned
-        };
     }
 
     #convertPackage(
@@ -174,7 +169,7 @@ export class ApiReferenceNodeConverter {
     ): FernNavigation.V1.ApiPackageNode {
         const overviewPageId =
             pkg.overviewAbsolutePath != null
-                ? FernNavigation.V1.PageId(this.toRelativeFilepath(pkg.overviewAbsolutePath))
+                ? FernNavigation.V1.PageId(toRelativeFilepath(this.docsWorkspace, pkg.overviewAbsolutePath))
                 : undefined;
 
         const maybeFullSlug =
@@ -265,7 +260,7 @@ export class ApiReferenceNodeConverter {
     ): FernNavigation.V1.ApiPackageNode {
         const overviewPageId =
             section.overviewAbsolutePath != null
-                ? FernNavigation.V1.PageId(this.toRelativeFilepath(section.overviewAbsolutePath))
+                ? FernNavigation.V1.PageId(toRelativeFilepath(this.docsWorkspace, section.overviewAbsolutePath))
                 : undefined;
 
         const maybeFullSlug =
@@ -512,33 +507,24 @@ export class ApiReferenceNodeConverter {
         left: FernNavigation.V1.ApiPackageChild[],
         right: FernNavigation.V1.ApiPackageChild[]
     ): FernNavigation.V1.ApiPackageChild[] {
-        return this.mergeEndpointPairs([...left, ...right]).filter((child) =>
-            child.type === "apiPackage" ? child.children.length > 0 : true
-        );
+        return mergeAndFilterChildren({
+            left,
+            right,
+            findEndpointById: (endpointId) => this.#holder.endpoints.get(endpointId),
+            stringifyEndpointPathParts: (endpoint) => stringifyEndpointPathParts(endpoint.path.parts),
+            disableEndpointPairs: this.disableEndpointPairs,
+            apiDefinitionId: this.apiDefinitionId
+        });
     }
 
     #enrichApiPackageChild(child: FernNavigation.V1.ApiPackageChild): FernNavigation.V1.ApiPackageChild {
-        if (child.type === "apiPackage") {
-            // expand the subpackage to include children that haven't been visited yet
-            const slug = FernNavigation.V1.SlugGenerator.init(child.slug);
-            const subpackageIds = this.#nodeIdToSubpackageId.get(child.id) ?? [];
-            const subpackageChildren = subpackageIds.flatMap((subpackageId) =>
-                this.#convertApiDefinitionPackageId(subpackageId, slug)
-            );
-
-            // recursively apply enrichment to children
-            const enrichedChildren = child.children.map((innerChild) => this.#enrichApiPackageChild(innerChild));
-
-            // combine children with subpackage (tacked on at the end to preserve order)
-            const children = this.#mergeAndFilterChildren(enrichedChildren, subpackageChildren);
-
-            return {
-                ...child,
-                children,
-                pointsTo: undefined
-            };
-        }
-        return child;
+        return enrichApiPackageChild({
+            child,
+            nodeIdToSubpackageId: this.#nodeIdToSubpackageId,
+            convertApiDefinitionPackageId: (subpackageId, slug) =>
+                this.#convertApiDefinitionPackageId(subpackageId, slug),
+            mergeAndFilterChildren: this.#mergeAndFilterChildren.bind(this)
+        });
     }
 
     #convertApiDefinitionPackage(
@@ -698,79 +684,17 @@ export class ApiReferenceNodeConverter {
     #convertPlaygroundSettings(
         playgroundSettings?: docsYml.RawSchemas.PlaygroundSettings
     ): FernNavigation.V1.PlaygroundSettings | undefined {
-        if (playgroundSettings) {
-            return {
-                environments:
-                    playgroundSettings.environments != null && playgroundSettings.environments.length > 0
-                        ? playgroundSettings.environments.map((environmentId) =>
-                              FernNavigation.V1.EnvironmentId(environmentId)
-                          )
-                        : undefined,
-                button:
-                    playgroundSettings.button != null && playgroundSettings.button.href
-                        ? { href: FernNavigation.V1.Url(playgroundSettings.button.href) }
-                        : undefined,
-                "limit-websocket-messages-per-connection":
-                    playgroundSettings.limitWebsocketMessagesPerConnection != null
-                        ? playgroundSettings.limitWebsocketMessagesPerConnection
-                        : undefined
-            };
-        }
-
-        return;
+        return convertPlaygroundSettings(playgroundSettings);
     }
 
     private mergeEndpointPairs(children: FernNavigation.V1.ApiPackageChild[]): FernNavigation.V1.ApiPackageChild[] {
-        if (this.disableEndpointPairs) {
-            return children;
-        }
-
-        const toRet: FernNavigation.V1.ApiPackageChild[] = [];
-
-        const methodAndPathToEndpointNode = new Map<string, FernNavigation.V1.EndpointNode>();
-        children.forEach((child) => {
-            if (child.type !== "endpoint") {
-                toRet.push(child);
-                return;
-            }
-
-            const endpoint = this.#holder.endpoints.get(child.endpointId);
-            if (endpoint == null) {
-                throw new Error(`Endpoint ${child.endpointId} not found`);
-            }
-
-            const methodAndPath = `${endpoint.method} ${stringifyEndpointPathParts(endpoint.path.parts)}`;
-
-            const existing = methodAndPathToEndpointNode.get(methodAndPath);
-            methodAndPathToEndpointNode.set(methodAndPath, child);
-
-            if (existing == null || existing.isResponseStream === child.isResponseStream) {
-                toRet.push(child);
-                return;
-            }
-
-            const idx = toRet.indexOf(existing);
-            const stream = child.isResponseStream ? child : existing;
-            const nonStream = child.isResponseStream ? existing : child;
-            const pairNode: FernNavigation.V1.EndpointPairNode = {
-                id: FernNavigation.V1.NodeId(`${this.apiDefinitionId}:${nonStream.endpointId}+${stream.endpointId}`),
-                type: "endpointPair",
-                stream,
-                nonStream
-            };
-
-            toRet[idx] = pairNode;
+        return mergeEndpointPairs({
+            children,
+            findEndpointById: (endpointId: APIV1Read.EndpointId) => this.#holder.endpoints.get(endpointId),
+            stringifyEndpointPathParts: (endpoint: APIV1Read.EndpointDefinition) =>
+                stringifyEndpointPathParts(endpoint.path.parts),
+            disableEndpointPairs: this.disableEndpointPairs,
+            apiDefinitionId: this.apiDefinitionId
         });
-
-        return toRet;
-    }
-
-    private toRelativeFilepath(filepath: AbsoluteFilePath): RelativeFilePath;
-    private toRelativeFilepath(filepath: AbsoluteFilePath | undefined): RelativeFilePath | undefined;
-    private toRelativeFilepath(filepath: AbsoluteFilePath | undefined): RelativeFilePath | undefined {
-        if (filepath == null) {
-            return undefined;
-        }
-        return relative(this.docsWorkspace.absoluteFilePath, filepath);
     }
 }
diff --git a/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts b/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts
index 0bb81339273..dca531db38d 100644
--- a/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts
+++ b/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts
@@ -1,19 +1,24 @@
 import { camelCase, kebabCase } from "lodash-es";
 import urlJoin from "url-join";
-import { threadId } from "worker_threads";
 
 import { docsYml } from "@fern-api/configuration-loader";
 import { isNonNullish } from "@fern-api/core-utils";
 import { FdrAPI, FernNavigation } from "@fern-api/fdr-sdk";
-import { AbsoluteFilePath, RelativeFilePath, relative } from "@fern-api/fs-utils";
+import { AbsoluteFilePath } from "@fern-api/fs-utils";
 import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
 import { TaskContext } from "@fern-api/task-context";
 import { titleCase, visitDiscriminatedUnion } from "@fern-api/ui-core-utils";
-import { DocsWorkspace, FernWorkspace } from "@fern-api/workspace-loader";
+import { DocsWorkspace } from "@fern-api/workspace-loader";
 
 import { ChangelogNodeConverter } from "./ChangelogNodeConverter";
 import { NodeIdGenerator } from "./NodeIdGenerator";
+import { convertPlaygroundSettings } from "./utils/convertPlaygroundSettings";
+import { enrichApiPackageChild } from "./utils/enrichApiPackageChild";
+import { mergeAndFilterChildren } from "./utils/mergeAndFilterChildren";
+import { mergeEndpointPairs } from "./utils/mergeEndpointPairs";
 import { stringifyEndpointPathParts } from "./utils/stringifyEndpointPathParts";
+import { toPageNode } from "./utils/toPageNode";
+import { toRelativeFilepath } from "./utils/toRelativeFilepath";
 
 // TODO: these functions need an extra piece of information from the fdr latest shape, to see if the operation id takes precedence over slug generation
 function getLatestEndpointUrlSlug(endpoint: FdrAPI.api.latest.endpoint.EndpointDefinition) {
@@ -68,7 +73,7 @@ export class ApiReferenceNodeConverterLatest {
 
         this.#overviewPageId =
             this.apiSection.overviewAbsolutePath != null
-                ? FernNavigation.V1.PageId(this.toRelativeFilepath(this.apiSection.overviewAbsolutePath))
+                ? FernNavigation.V1.PageId(toRelativeFilepath(this.docsWorkspace, this.apiSection.overviewAbsolutePath))
                 : undefined;
 
         // the overview page markdown could contain a full slug, which would be used as the base slug for the API section.
@@ -130,6 +135,16 @@ export class ApiReferenceNodeConverterLatest {
         };
     }
 
+    #findSubpackageByLocator(locator: string): FdrAPI.api.latest.SubpackageMetadata | undefined {
+        return (
+            this.#api?.subpackages[FdrAPI.api.v1.SubpackageId(locator)] ??
+            this.#api?.subpackages[
+                FdrAPI.api.v1.SubpackageId(locator.replace(".yml", "").replace(".yaml", "").split(".").pop() ?? "")
+            ] ??
+            this.#api?.subpackages[FdrAPI.api.v1.SubpackageId(locator.split("/").pop() ?? "")]
+        );
+    }
+
     #findEndpointByLocator(locator: string): FdrAPI.api.latest.endpoint.EndpointDefinition | undefined {
         return (
             this.#api?.endpoints[FdrAPI.EndpointId(locator)] ??
@@ -194,24 +209,13 @@ export class ApiReferenceNodeConverterLatest {
         page: docsYml.DocsNavigationItem.Page,
         parentSlug: FernNavigation.V1.SlugGenerator
     ): FernNavigation.V1.PageNode {
-        const pageId = FernNavigation.V1.PageId(this.toRelativeFilepath(page.absolutePath));
-        const pageSlug = parentSlug.apply({
-            fullSlug: this.markdownFilesToFullSlugs.get(page.absolutePath)?.split("/"),
-            urlSlug: page.slug ?? kebabCase(page.title)
+        return toPageNode({
+            docsWorkspace: this.docsWorkspace,
+            page,
+            parentSlug,
+            idgen: this.#idgen,
+            markdownFilesToFullSlugs: this.markdownFilesToFullSlugs
         });
-        return {
-            id: this.#idgen.get(pageId),
-            type: "page",
-            pageId,
-            title: page.title,
-            slug: pageSlug.get(),
-            icon: page.icon,
-            hidden: page.hidden,
-            noindex: page.noindex,
-            authed: undefined,
-            viewers: page.viewers,
-            orphaned: page.orphaned
-        };
     }
 
     #convertPackage(
@@ -220,18 +224,13 @@ export class ApiReferenceNodeConverterLatest {
     ): FernNavigation.V1.ApiPackageNode {
         const overviewPageId =
             pkg.overviewAbsolutePath != null
-                ? FernNavigation.V1.PageId(this.toRelativeFilepath(pkg.overviewAbsolutePath))
+                ? FernNavigation.V1.PageId(toRelativeFilepath(this.docsWorkspace, pkg.overviewAbsolutePath))
                 : undefined;
 
         const maybeFullSlug =
             pkg.overviewAbsolutePath != null ? this.markdownFilesToFullSlugs.get(pkg.overviewAbsolutePath) : undefined;
 
-        const subpackage =
-            this.#api.subpackages[FdrAPI.api.v1.SubpackageId(pkg.package)] ??
-            this.#api.subpackages[
-                FdrAPI.api.v1.SubpackageId(pkg.package.replace(".yml", "").replace(".yaml", "").split(".").pop() ?? "")
-            ] ??
-            this.#api.subpackages[FdrAPI.api.v1.SubpackageId(pkg.package.split("/").pop() ?? "")];
+        const subpackage = this.#findSubpackageByLocator(pkg.package);
 
         if (subpackage != null) {
             const subpackageNodeId = this.#idgen.get(overviewPageId ?? `${this.apiDefinitionId}:${subpackage.id}`);
@@ -313,7 +312,7 @@ export class ApiReferenceNodeConverterLatest {
     ): FernNavigation.V1.ApiPackageNode {
         const overviewPageId =
             section.overviewAbsolutePath != null
-                ? FernNavigation.V1.PageId(this.toRelativeFilepath(section.overviewAbsolutePath))
+                ? FernNavigation.V1.PageId(toRelativeFilepath(this.docsWorkspace, section.overviewAbsolutePath))
                 : undefined;
 
         const maybeFullSlug =
@@ -325,14 +324,7 @@ export class ApiReferenceNodeConverterLatest {
 
         const subpackageIds = section.referencedSubpackages
             .map((locator) => {
-                const subpackage =
-                    this.#api?.subpackages[FdrAPI.api.v1.SubpackageId(locator)] ??
-                    this.#api?.subpackages[
-                        FdrAPI.api.v1.SubpackageId(
-                            locator.replace(".yml", "").replace(".yaml", "").split(".").pop() ?? ""
-                        )
-                    ] ??
-                    this.#api?.subpackages[FdrAPI.api.v1.SubpackageId(locator.split("/").pop() ?? "")];
+                const subpackage = this.#findSubpackageByLocator(locator);
 
                 return subpackage != null ? subpackage.id : undefined;
             })
@@ -391,26 +383,20 @@ export class ApiReferenceNodeConverterLatest {
 
         // if the unknownIdentifier is a subpackage, we need to check subpackage metadata, and any locators (strip .yml)
 
-        const subpackage =
-            this.#api?.subpackages[FdrAPI.api.v1.SubpackageId(unknownIdentifier)] ??
-            this.#api?.subpackages[
-                FdrAPI.api.v1.SubpackageId(
-                    unknownIdentifier.replace(".yml", "").replace(".yaml", "").split(".").pop() ?? ""
-                )
-            ] ??
-            this.#api?.subpackages[FdrAPI.api.v1.SubpackageId(unknownIdentifier.split("/").pop() ?? "")];
+        const subpackage = this.#findSubpackageByLocator(unknownIdentifier);
 
         if (subpackage != null) {
-            const subpackageNodeId = this.#idgen.get(`${this.apiDefinitionId}:${subpackage.id}`);
+            const subpackageId = subpackage.id;
+            const subpackageNodeId = this.#idgen.get(`${this.apiDefinitionId}:${subpackageId}`);
 
-            if (this.#visitedSubpackages.has(subpackage.id)) {
+            if (this.#visitedSubpackages.has(subpackageId)) {
                 this.taskContext.logger.error(
-                    `Duplicate subpackage found in the API Reference layout: ${subpackage.id}`
+                    `Duplicate subpackage found in the API Reference layout: ${subpackageId}`
                 );
             }
 
-            this.#visitedSubpackages.add(subpackage.id);
-            this.#nodeIdToSubpackageId.set(subpackageNodeId, [subpackage.id]);
+            this.#visitedSubpackages.add(subpackageId);
+            this.#nodeIdToSubpackageId.set(subpackageNodeId, [subpackageId]);
             const urlSlug = subpackage.name;
             const slug = parentSlug.apply({ urlSlug });
             const subpackageNode: FernNavigation.V1.ApiPackageNode = {
@@ -432,7 +418,7 @@ export class ApiReferenceNodeConverterLatest {
                 orphaned: undefined
             };
 
-            this.#topLevelSubpackages.set(subpackage.id, subpackageNode);
+            this.#topLevelSubpackages.set(subpackageId, subpackageNode);
             return subpackageNode;
         }
 
@@ -563,33 +549,24 @@ export class ApiReferenceNodeConverterLatest {
         left: FernNavigation.V1.ApiPackageChild[],
         right: FernNavigation.V1.ApiPackageChild[]
     ): FernNavigation.V1.ApiPackageChild[] {
-        return this.mergeEndpointPairs([...left, ...right]).filter((child) =>
-            child.type === "apiPackage" ? child.children.length > 0 : true
-        );
+        return mergeAndFilterChildren({
+            left,
+            right,
+            findEndpointById: (endpointId) => this.#findEndpointByLocator(endpointId),
+            stringifyEndpointPathParts: (endpoint) => stringifyEndpointPathParts(endpoint.path),
+            disableEndpointPairs: this.disableEndpointPairs,
+            apiDefinitionId: this.apiDefinitionId
+        });
     }
 
     #enrichApiPackageChild(child: FernNavigation.V1.ApiPackageChild): FernNavigation.V1.ApiPackageChild {
-        if (child.type === "apiPackage") {
-            // expand the subpackage to include children that haven't been visited yet
-            const slug = FernNavigation.V1.SlugGenerator.init(child.slug);
-            const subpackageIds = this.#nodeIdToSubpackageId.get(child.id) ?? [];
-            const subpackageChildren = subpackageIds.flatMap((subpackageId) =>
-                this.#convertApiDefinitionPackageId(subpackageId, slug)
-            );
-
-            // recursively apply enrichment to children
-            const enrichedChildren = child.children.map((innerChild) => this.#enrichApiPackageChild(innerChild));
-
-            // combine children with subpackage (tacked on at the end to preserve order)
-            const children = this.#mergeAndFilterChildren(enrichedChildren, subpackageChildren);
-
-            return {
-                ...child,
-                children,
-                pointsTo: undefined
-            };
-        }
-        return child;
+        return enrichApiPackageChild({
+            child,
+            nodeIdToSubpackageId: this.#nodeIdToSubpackageId,
+            convertApiDefinitionPackageId: (subpackageId, slug) =>
+                this.#convertApiDefinitionPackageId(subpackageId, slug),
+            mergeAndFilterChildren: this.#mergeAndFilterChildren.bind(this)
+        });
     }
 
     #convertApiDefinitionPackage(
@@ -924,79 +901,17 @@ export class ApiReferenceNodeConverterLatest {
     #convertPlaygroundSettings(
         playgroundSettings?: docsYml.RawSchemas.PlaygroundSettings
     ): FernNavigation.V1.PlaygroundSettings | undefined {
-        if (playgroundSettings) {
-            return {
-                environments:
-                    playgroundSettings.environments != null && playgroundSettings.environments.length > 0
-                        ? playgroundSettings.environments.map((environmentId) =>
-                              FernNavigation.V1.EnvironmentId(environmentId)
-                          )
-                        : undefined,
-                button:
-                    playgroundSettings.button != null && playgroundSettings.button.href
-                        ? { href: FernNavigation.V1.Url(playgroundSettings.button.href) }
-                        : undefined,
-                "limit-websocket-messages-per-connection":
-                    playgroundSettings.limitWebsocketMessagesPerConnection != null
-                        ? playgroundSettings.limitWebsocketMessagesPerConnection
-                        : undefined
-            };
-        }
-
-        return;
+        return convertPlaygroundSettings(playgroundSettings);
     }
 
     private mergeEndpointPairs(children: FernNavigation.V1.ApiPackageChild[]): FernNavigation.V1.ApiPackageChild[] {
-        if (this.disableEndpointPairs) {
-            return children;
-        }
-
-        const toRet: FernNavigation.V1.ApiPackageChild[] = [];
-
-        const methodAndPathToEndpointNode = new Map<string, FernNavigation.V1.EndpointNode>();
-        children.forEach((child) => {
-            if (child.type !== "endpoint") {
-                toRet.push(child);
-                return;
-            }
-
-            const endpoint = this.#api?.endpoints[child.endpointId];
-            if (endpoint == null) {
-                throw new Error(`Endpoint ${child.endpointId} not found`);
-            }
-
-            const methodAndPath = `${endpoint.method} ${stringifyEndpointPathParts(endpoint.path)}`;
-
-            const existing = methodAndPathToEndpointNode.get(methodAndPath);
-            methodAndPathToEndpointNode.set(methodAndPath, child);
-
-            if (existing == null || existing.isResponseStream === child.isResponseStream) {
-                toRet.push(child);
-                return;
-            }
-
-            const idx = toRet.indexOf(existing);
-            const stream = child.isResponseStream ? child : existing;
-            const nonStream = child.isResponseStream ? existing : child;
-            const pairNode: FernNavigation.V1.EndpointPairNode = {
-                id: FernNavigation.V1.NodeId(`${this.apiDefinitionId}:${nonStream.endpointId}+${stream.endpointId}`),
-                type: "endpointPair",
-                stream,
-                nonStream
-            };
-
-            toRet[idx] = pairNode;
+        return mergeEndpointPairs({
+            children,
+            findEndpointById: (endpointId: FdrAPI.EndpointId) => this.#api?.endpoints[endpointId],
+            stringifyEndpointPathParts: (endpoint: FdrAPI.api.latest.EndpointDefinition) =>
+                stringifyEndpointPathParts(endpoint.path),
+            disableEndpointPairs: this.disableEndpointPairs,
+            apiDefinitionId: this.apiDefinitionId
         });
-
-        return toRet;
-    }
-
-    private toRelativeFilepath(filepath: AbsoluteFilePath): RelativeFilePath;
-    private toRelativeFilepath(filepath: AbsoluteFilePath | undefined): RelativeFilePath | undefined;
-    private toRelativeFilepath(filepath: AbsoluteFilePath | undefined): RelativeFilePath | undefined {
-        if (filepath == null) {
-            return undefined;
-        }
-        return relative(this.docsWorkspace.absoluteFilePath, filepath);
     }
 }
diff --git a/packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/docs.yml b/packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/docs.yml
new file mode 100644
index 00000000000..2d51970a5ac
--- /dev/null
+++ b/packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/docs.yml
@@ -0,0 +1,9 @@
+instances:
+  - url: https://fern-platform-test.docs.dev.buildwithfern.com
+  - url: https://fern-platform-test.docs.buildwithfern.com
+title: SmokeTest | Documentation
+navigation:
+  - api: API Reference
+colors:
+  accentPrimary: '#ffffff'
+  background: '#000000'
diff --git a/packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/fern.config.json b/packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/fern.config.json
new file mode 100644
index 00000000000..7980537f564
--- /dev/null
+++ b/packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/fern.config.json
@@ -0,0 +1,4 @@
+{
+    "organization": "fern",
+    "version": "*"
+}
\ No newline at end of file
diff --git a/packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/generators.yml b/packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/generators.yml
new file mode 100644
index 00000000000..0967ef424bc
--- /dev/null
+++ b/packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/generators.yml
@@ -0,0 +1 @@
+{}
diff --git a/packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/openapi.yml b/packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/openapi.yml
new file mode 100644
index 00000000000..79d4a073543
--- /dev/null
+++ b/packages/cli/docs-resolver/src/__test__/fixtures/openapi-latest/fern/openapi.yml
@@ -0,0 +1,332 @@
+openapi: 3.1.0
+info:
+  title: Swagger Petstore - OpenAPI 3.1
+  description: |-
+    This is a sample Pet Store Server based on the OpenAPI 3.1 specification.
+    You can find out more about
+    Swagger at [http://swagger.io](http://swagger.io).
+  summary: Pet Store 3.1
+  version: 1.0.0
+servers:
+  - url: /api/v31
+tags:
+  - name: pet
+    description: Everything about your Pets
+  - name: store
+    description: Access to Petstore orders
+  - name: user
+    description: Operations about user
+paths:
+  /pet:
+    put:
+      tags:
+        - pet
+      summary: Update an existing pet
+      description: Update an existing pet by Id
+      operationId: updatePet
+      requestBody:
+        description: Pet object that needs to be updated in the store
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/Pet"
+              description: A Pet in JSON Format
+              required:
+                - id
+              writeOnly: true
+          application/xml:
+            schema:
+              $ref: "#/components/schemas/Pet"
+              description: A Pet in XML Format
+              required:
+                - id
+              writeOnly: true
+        required: true
+      responses:
+        "200":
+          description: Successful operation
+          content:
+            application/xml:
+              schema:
+                $ref: "#/components/schemas/Pet"
+                description: A Pet in XML Format
+                readOnly: true
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Pet"
+                description: A Pet in JSON Format
+                readOnly: true
+        "400":
+          description: Invalid ID supplied
+        "404":
+          description: Pet not found
+        "405":
+          description: Validation exception
+      security:
+        - petstore_auth:
+            - "write:pets"
+            - "read:pets"
+    post:
+      tags:
+        - pet
+      summary: Add a new pet to the store
+      description: Add a new pet to the store
+      operationId: addPet
+      requestBody:
+        description: Create a new pet in the store
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/Pet"
+              description: A Pet in JSON Format
+              required:
+                - id
+              writeOnly: true
+          application/xml:
+            schema:
+              $ref: "#/components/schemas/Pet"
+              description: A Pet in XML Format
+              required:
+                - id
+              writeOnly: true
+        required: true
+      responses:
+        "200":
+          description: Successful operation
+          content:
+            application/xml:
+              schema:
+                $ref: "#/components/schemas/Pet"
+                description: A Pet in XML Format
+                readOnly: true
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Pet"
+                description: A Pet in JSON Format
+                readOnly: true
+        "405":
+          description: Invalid input
+      security:
+        - petstore_auth:
+            - "write:pets"
+            - "read:pets"
+  "/pet/{petId}":
+    get:
+      tags:
+        - pets
+      summary: Find pet by ID
+      description: >-
+        Returns a pet when 0 < ID <= 10.  ID > 10 or nonintegers will simulate
+        API error conditions
+      operationId: getPetById
+      parameters:
+        - name: petId
+          in: path
+          description: ID of pet that needs to be fetched
+          required: true
+          schema:
+            type: integer
+            format: int64
+            description: param ID of pet that needs to be fetched
+            exclusiveMaximum: 10
+            exclusiveMinimum: 1
+      responses:
+        "400":
+          description: Invalid ID supplied
+        "404":
+          description: Pet not found
+        default:
+          description: The pet
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Pet"
+                description: A Pet in JSON format
+            application/xml:
+              schema:
+                $ref: "#/components/schemas/Pet"
+                description: A Pet in XML format
+      security:
+        - petstore_auth:
+            - "write:pets"
+            - "read:pets"
+        - api_key: []
+components:
+  schemas:
+    Order:
+      x-swagger-router-model: io.swagger.petstore.model.Order
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 10
+        petId:
+          type: integer
+          format: int64
+          example: 198772
+        quantity:
+          type: integer
+          format: int32
+          example: 7
+        shipDate:
+          type: string
+          format: date-time
+        status:
+          type: string
+          description: Order Status
+          enum:
+            - placed
+            - approved
+            - delivered
+          example: approved
+        complete:
+          type: boolean
+      xml:
+        name: order
+      type: object
+    Customer:
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 100000
+        username:
+          type: string
+          example: fehguy
+        address:
+          type: array
+          items:
+            $ref: "#/components/schemas/Address"
+          xml:
+            wrapped: true
+            name: addresses
+      xml:
+        name: customer
+      type: object
+    Address:
+      properties:
+        street:
+          type: string
+          example: 437 Lytton
+        city:
+          type: string
+          example: Palo Alto
+        state:
+          type: string
+          example: CA
+        zip:
+          type: string
+          example: 94301
+      xml:
+        name: address
+      type: object
+    Category:
+      x-swagger-router-model: io.swagger.petstore.model.Category
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 1
+        name:
+          type: string
+          example: Dogs
+      xml:
+        name: category
+      type: object
+    User:
+      x-swagger-router-model: io.swagger.petstore.model.User
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 10
+        username:
+          type: string
+          example: theUser
+        firstName:
+          type: string
+          example: John
+        lastName:
+          type: string
+          example: James
+        email:
+          type: string
+          example: john@email.com
+        password:
+          type: string
+          example: 12345
+        phone:
+          type: string
+          example: 12345
+        userStatus:
+          type: integer
+          format: int32
+          example: 1
+          description: User Status
+      xml:
+        name: user
+      type: object
+    Tag:
+      x-swagger-router-model: io.swagger.petstore.model.Tag
+      properties:
+        id:
+          type: integer
+          format: int64
+        name:
+          type: string
+      xml:
+        name: tag
+      type: object
+    Pet:
+      x-swagger-router-model: io.swagger.petstore.model.Pet
+      required:
+        - name
+        - photoUrls
+      properties:
+        id:
+          type: integer
+          format: int64
+          example: 10
+        name:
+          type: string
+          example: doggie
+        category:
+          $ref: "#/components/schemas/Category"
+        photoUrls:
+          type: array
+          xml:
+            wrapped: true
+          items:
+            type: string
+            xml:
+              name: photoUrl
+        tags:
+          type: array
+          xml:
+            wrapped: true
+          items:
+            $ref: "#/components/schemas/Tag"
+            xml:
+              name: tag
+        status:
+          type: string
+          description: pet status in the store
+          enum:
+            - available
+            - pending
+            - sold
+      xml:
+        name: pet
+      type: object
+    ApiResponse:
+      properties:
+        code:
+          type: integer
+          format: int32
+        type:
+          type: string
+        message:
+          type: string
+      xml:
+        name: "##default"
+      type: object
diff --git a/packages/cli/docs-resolver/src/__test__/openapi-latest.test.ts b/packages/cli/docs-resolver/src/__test__/openapi-latest.test.ts
new file mode 100644
index 00000000000..746910f1638
--- /dev/null
+++ b/packages/cli/docs-resolver/src/__test__/openapi-latest.test.ts
@@ -0,0 +1,79 @@
+import { parseDocsConfiguration } from "@fern-api/configuration-loader";
+import { FernNavigation } from "@fern-api/fdr-sdk";
+import { AbsoluteFilePath, resolve } from "@fern-api/fs-utils";
+import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
+import { createMockTaskContext } from "@fern-api/task-context";
+import { loadAPIWorkspace, loadDocsWorkspace } from "@fern-api/workspace-loader";
+
+import { ApiReferenceNodeConverterLatest } from "../ApiReferenceNodeConverterLatest";
+import { NodeIdGenerator } from "../NodeIdGenerator";
+import { generateFdrFromOpenApiWorkspace } from "../utils/generateFdrFromOpenApiWorkspace";
+
+const context = createMockTaskContext();
+
+// eslint-disable-next-line jest/no-disabled-tests
+it.skip("converts to api reference latest node", async () => {
+    const docsWorkspace = await loadDocsWorkspace({
+        fernDirectory: resolve(AbsoluteFilePath.of(__dirname), "fixtures/openapi-latest/fern"),
+        context
+    });
+
+    if (docsWorkspace == null) {
+        throw new Error("Workspace is null");
+    }
+
+    const parsedDocsConfig = await parseDocsConfiguration({
+        rawDocsConfiguration: docsWorkspace.config,
+        context,
+        absolutePathToFernFolder: docsWorkspace.absoluteFilePath,
+        absoluteFilepathToDocsConfig: docsWorkspace.absoluteFilepathToDocsConfig
+    });
+
+    if (parsedDocsConfig.navigation.type !== "untabbed") {
+        throw new Error("Expected untabbed navigation");
+    }
+
+    if (parsedDocsConfig.navigation.items[0]?.type !== "apiSection") {
+        throw new Error("Expected apiSection");
+    }
+
+    const apiSection = parsedDocsConfig.navigation.items[0];
+
+    const result = await loadAPIWorkspace({
+        absolutePathToWorkspace: resolve(AbsoluteFilePath.of(__dirname), "fixtures/openapi-latest/fern"),
+        context,
+        cliVersion: "0.0.0",
+        workspaceName: undefined
+    });
+
+    if (!result.didSucceed) {
+        throw new Error("API workspace failed to load");
+    }
+
+    const apiWorkspace = result.workspace;
+
+    if (!(apiWorkspace instanceof OSSWorkspace)) {
+        throw new Error("Expected oss workspace");
+    }
+
+    const slug = FernNavigation.V1.SlugGenerator.init("/base/path");
+
+    const api = await generateFdrFromOpenApiWorkspace(apiWorkspace, context);
+
+    if (api == null) {
+        throw new Error("API is null");
+    }
+
+    const node = new ApiReferenceNodeConverterLatest(
+        apiSection,
+        api,
+        slug,
+        apiWorkspace,
+        docsWorkspace,
+        context,
+        new Map(),
+        NodeIdGenerator.init()
+    ).get();
+
+    expect(node).toMatchSnapshot();
+});
diff --git a/packages/cli/docs-resolver/src/utils/convertIrToApiDefinition.ts b/packages/cli/docs-resolver/src/utils/convertIrToApiDefinition.ts
index a0e02a633eb..0ca7cec8471 100644
--- a/packages/cli/docs-resolver/src/utils/convertIrToApiDefinition.ts
+++ b/packages/cli/docs-resolver/src/utils/convertIrToApiDefinition.ts
@@ -1,10 +1,4 @@
-import {
-    APIV1Read,
-    DocsV1Read,
-    SDKSnippetHolder,
-    convertAPIDefinitionToDb,
-    convertDbAPIDefinitionToRead
-} from "@fern-api/fdr-sdk";
+import { APIV1Read, SDKSnippetHolder, convertAPIDefinitionToDb, convertDbAPIDefinitionToRead } from "@fern-api/fdr-sdk";
 import { IntermediateRepresentation } from "@fern-api/ir-sdk";
 import { convertIrToFdrApi } from "@fern-api/register";
 
diff --git a/packages/cli/docs-resolver/src/utils/convertPlaygroundSettings.ts b/packages/cli/docs-resolver/src/utils/convertPlaygroundSettings.ts
new file mode 100644
index 00000000000..c5a5acf56e1
--- /dev/null
+++ b/packages/cli/docs-resolver/src/utils/convertPlaygroundSettings.ts
@@ -0,0 +1,27 @@
+import { docsYml } from "@fern-api/configuration-loader";
+import { FernNavigation } from "@fern-api/fdr-sdk";
+
+export function convertPlaygroundSettings(
+    playgroundSettings?: docsYml.RawSchemas.PlaygroundSettings
+): FernNavigation.V1.PlaygroundSettings | undefined {
+    if (playgroundSettings) {
+        return {
+            environments:
+                playgroundSettings.environments != null && playgroundSettings.environments.length > 0
+                    ? playgroundSettings.environments.map((environmentId) =>
+                          FernNavigation.V1.EnvironmentId(environmentId)
+                      )
+                    : undefined,
+            button:
+                playgroundSettings.button != null && playgroundSettings.button.href
+                    ? { href: FernNavigation.V1.Url(playgroundSettings.button.href) }
+                    : undefined,
+            "limit-websocket-messages-per-connection":
+                playgroundSettings.limitWebsocketMessagesPerConnection != null
+                    ? playgroundSettings.limitWebsocketMessagesPerConnection
+                    : undefined
+        };
+    }
+
+    return;
+}
diff --git a/packages/cli/docs-resolver/src/utils/enrichApiPackageChild.ts b/packages/cli/docs-resolver/src/utils/enrichApiPackageChild.ts
new file mode 100644
index 00000000000..9f2ad6cd772
--- /dev/null
+++ b/packages/cli/docs-resolver/src/utils/enrichApiPackageChild.ts
@@ -0,0 +1,48 @@
+import { FernNavigation } from "@fern-api/fdr-sdk";
+
+export function enrichApiPackageChild({
+    child,
+    nodeIdToSubpackageId,
+    convertApiDefinitionPackageId,
+    mergeAndFilterChildren
+}: {
+    child: FernNavigation.V1.ApiPackageChild;
+    nodeIdToSubpackageId: Map<string, string[]>;
+    convertApiDefinitionPackageId: (
+        subpackageId: string,
+        slug: FernNavigation.V1.SlugGenerator
+    ) => FernNavigation.V1.ApiPackageChild[];
+    mergeAndFilterChildren: (
+        children: FernNavigation.V1.ApiPackageChild[],
+        subpackageChildren: FernNavigation.V1.ApiPackageChild[]
+    ) => FernNavigation.V1.ApiPackageChild[];
+}): FernNavigation.V1.ApiPackageChild {
+    if (child.type === "apiPackage") {
+        // expand the subpackage to include children that haven't been visited yet
+        const slug = FernNavigation.V1.SlugGenerator.init(child.slug);
+        const subpackageIds = nodeIdToSubpackageId.get(child.id) ?? [];
+        const subpackageChildren = subpackageIds.flatMap((subpackageId) =>
+            convertApiDefinitionPackageId(subpackageId, slug)
+        );
+
+        // recursively apply enrichment to children
+        const enrichedChildren = child.children.map((innerChild) =>
+            enrichApiPackageChild({
+                child: innerChild,
+                nodeIdToSubpackageId,
+                convertApiDefinitionPackageId,
+                mergeAndFilterChildren
+            })
+        );
+
+        // combine children with subpackage (tacked on at the end to preserve order)
+        const children = mergeAndFilterChildren(enrichedChildren, subpackageChildren);
+
+        return {
+            ...child,
+            children,
+            pointsTo: undefined
+        };
+    }
+    return child;
+}
diff --git a/packages/cli/docs-resolver/src/utils/mergeAndFilterChildren.ts b/packages/cli/docs-resolver/src/utils/mergeAndFilterChildren.ts
new file mode 100644
index 00000000000..0b018753808
--- /dev/null
+++ b/packages/cli/docs-resolver/src/utils/mergeAndFilterChildren.ts
@@ -0,0 +1,27 @@
+import { FernNavigation } from "@fern-api/fdr-sdk";
+
+import { mergeEndpointPairs } from "./mergeEndpointPairs";
+
+export function mergeAndFilterChildren<EndpointType extends { method: string }>({
+    left,
+    right,
+    findEndpointById,
+    stringifyEndpointPathParts,
+    disableEndpointPairs,
+    apiDefinitionId
+}: {
+    left: FernNavigation.V1.ApiPackageChild[];
+    right: FernNavigation.V1.ApiPackageChild[];
+    findEndpointById: (endpointId: FernNavigation.EndpointId) => EndpointType | undefined;
+    stringifyEndpointPathParts: (endpoint: EndpointType) => string;
+    disableEndpointPairs: boolean;
+    apiDefinitionId: FernNavigation.V1.ApiDefinitionId;
+}): FernNavigation.V1.ApiPackageChild[] {
+    return mergeEndpointPairs({
+        children: [...left, ...right],
+        findEndpointById,
+        stringifyEndpointPathParts,
+        disableEndpointPairs,
+        apiDefinitionId
+    }).filter((child) => (child.type === "apiPackage" ? child.children.length > 0 : true));
+}
diff --git a/packages/cli/docs-resolver/src/utils/mergeEndpointPairs.ts b/packages/cli/docs-resolver/src/utils/mergeEndpointPairs.ts
new file mode 100644
index 00000000000..f0ba4617a3c
--- /dev/null
+++ b/packages/cli/docs-resolver/src/utils/mergeEndpointPairs.ts
@@ -0,0 +1,58 @@
+import { FernNavigation } from "@fern-api/fdr-sdk";
+
+export function mergeEndpointPairs<EndpointType extends { method: string }>({
+    children,
+    findEndpointById,
+    stringifyEndpointPathParts,
+    disableEndpointPairs,
+    apiDefinitionId
+}: {
+    children: FernNavigation.V1.ApiPackageChild[];
+    findEndpointById: (endpointId: FernNavigation.EndpointId) => EndpointType | undefined;
+    stringifyEndpointPathParts: (endpoint: EndpointType) => string;
+    disableEndpointPairs: boolean;
+    apiDefinitionId: FernNavigation.V1.ApiDefinitionId;
+}): FernNavigation.V1.ApiPackageChild[] {
+    if (disableEndpointPairs) {
+        return children;
+    }
+
+    const toRet: FernNavigation.V1.ApiPackageChild[] = [];
+
+    const methodAndPathToEndpointNode = new Map<string, FernNavigation.V1.EndpointNode>();
+    children.forEach((child) => {
+        if (child.type !== "endpoint") {
+            toRet.push(child);
+            return;
+        }
+
+        const endpoint = findEndpointById(child.endpointId);
+        if (endpoint == null) {
+            throw new Error(`Endpoint ${child.endpointId} not found`);
+        }
+
+        const methodAndPath = `${endpoint.method} ${stringifyEndpointPathParts(endpoint)}`;
+
+        const existing = methodAndPathToEndpointNode.get(methodAndPath);
+        methodAndPathToEndpointNode.set(methodAndPath, child);
+
+        if (existing == null || existing.isResponseStream === child.isResponseStream) {
+            toRet.push(child);
+            return;
+        }
+
+        const idx = toRet.indexOf(existing);
+        const stream = child.isResponseStream ? child : existing;
+        const nonStream = child.isResponseStream ? existing : child;
+        const pairNode: FernNavigation.V1.EndpointPairNode = {
+            id: FernNavigation.V1.NodeId(`${apiDefinitionId}:${nonStream.endpointId}+${stream.endpointId}`),
+            type: "endpointPair",
+            stream,
+            nonStream
+        };
+
+        toRet[idx] = pairNode;
+    });
+
+    return toRet;
+}
diff --git a/packages/cli/docs-resolver/src/utils/toPageNode.ts b/packages/cli/docs-resolver/src/utils/toPageNode.ts
new file mode 100644
index 00000000000..612aeced7a7
--- /dev/null
+++ b/packages/cli/docs-resolver/src/utils/toPageNode.ts
@@ -0,0 +1,42 @@
+import { kebabCase } from "lodash-es";
+
+import { docsYml } from "@fern-api/configuration-loader";
+import { FernNavigation } from "@fern-api/fdr-sdk";
+import { AbsoluteFilePath } from "@fern-api/fs-utils";
+import { DocsWorkspace } from "@fern-api/workspace-loader";
+
+import { NodeIdGenerator } from "../NodeIdGenerator";
+import { toRelativeFilepath } from "./toRelativeFilepath";
+
+export function toPageNode({
+    docsWorkspace,
+    page,
+    parentSlug,
+    idgen,
+    markdownFilesToFullSlugs
+}: {
+    docsWorkspace: DocsWorkspace;
+    page: docsYml.DocsNavigationItem.Page;
+    parentSlug: FernNavigation.V1.SlugGenerator;
+    idgen: NodeIdGenerator;
+    markdownFilesToFullSlugs: Map<AbsoluteFilePath, string>;
+}): FernNavigation.V1.PageNode {
+    const pageId = FernNavigation.V1.PageId(toRelativeFilepath(docsWorkspace, page.absolutePath));
+    const pageSlug = parentSlug.apply({
+        fullSlug: markdownFilesToFullSlugs.get(page.absolutePath)?.split("/"),
+        urlSlug: page.slug ?? kebabCase(page.title)
+    });
+    return {
+        id: idgen.get(pageId),
+        type: "page",
+        pageId,
+        title: page.title,
+        slug: pageSlug.get(),
+        icon: page.icon,
+        hidden: page.hidden,
+        noindex: page.noindex,
+        authed: undefined,
+        viewers: page.viewers,
+        orphaned: page.orphaned
+    };
+}
diff --git a/packages/cli/docs-resolver/src/utils/toRelativeFilepath.ts b/packages/cli/docs-resolver/src/utils/toRelativeFilepath.ts
new file mode 100644
index 00000000000..136d21006f1
--- /dev/null
+++ b/packages/cli/docs-resolver/src/utils/toRelativeFilepath.ts
@@ -0,0 +1,17 @@
+import { AbsoluteFilePath, RelativeFilePath, relative } from "@fern-api/fs-utils";
+import { DocsWorkspace } from "@fern-api/workspace-loader";
+
+export function toRelativeFilepath(docsWorkspace: DocsWorkspace, filepath: AbsoluteFilePath): RelativeFilePath;
+export function toRelativeFilepath(
+    docsWorkspace: DocsWorkspace,
+    filepath: AbsoluteFilePath | undefined
+): RelativeFilePath | undefined;
+export function toRelativeFilepath(
+    docsWorkspace: DocsWorkspace,
+    filepath: AbsoluteFilePath | undefined
+): RelativeFilePath | undefined {
+    if (filepath == null) {
+        return undefined;
+    }
+    return relative(docsWorkspace.absoluteFilePath, filepath);
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d31e87d907e..a219a116672 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -4710,8 +4710,8 @@ importers:
         specifier: workspace:*
         version: link:../docs-markdown-utils
       '@fern-api/docs-parsers':
-        specifier: ^0.0.19
-        version: 0.0.19(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)
+        specifier: ^0.0.20
+        version: 0.0.20(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)
       '@fern-api/fdr-sdk':
         specifier: 0.127.4-331678a74
         version: 0.127.4-331678a74(typescript@4.6.4)
@@ -8276,8 +8276,8 @@ packages:
   '@fern-api/core-utils@0.4.24-rc1':
     resolution: {integrity: sha512-aYu4lQK2qZIKzTF9TeFrICTPJ/zGEZUEWQmZt6pJeHu+R6afrcCBNkUleWU1OpHlDbe+xXUUBOktRg0PM9Hywg==}
 
-  '@fern-api/docs-parsers@0.0.19':
-    resolution: {integrity: sha512-DWXyxW25dG/lCwAilvHcd394vHpSAF8wF1Q8P/PFxKBATHkVZxXHfmNeRC+soS4rn4E0vPOZJO3QR8d+ULZZkg==}
+  '@fern-api/docs-parsers@0.0.20':
+    resolution: {integrity: sha512-N4Xvc1GA5EkZiYkFLnbeOH2fwe4omYC3L/2fArYDvP0KZgpMigSGQOjwbH8MDboZ45BcXzbEs5NsOeCeNMHkgA==}
 
   '@fern-api/dynamic-ir-sdk@53.24.0':
     resolution: {integrity: sha512-4XvzvSsh7lNZz5oYN0LH+FRpFGxg9TjfdipSJMpgHvPShe85m/tcfbOzbS0DHBpQGlKb/gHQtQRPAoBR1wdDAw==}
@@ -15638,7 +15638,7 @@ snapshots:
       lodash-es: 4.17.21
       strip-ansi: 7.1.0
 
-  '@fern-api/docs-parsers@0.0.19(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)':
+  '@fern-api/docs-parsers@0.0.20(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5)(typescript@4.6.4)':
     dependencies:
       '@fern-api/logger': 0.4.24-rc1
       '@fern-api/ui-core-utils': 0.0.0

From d948e83ce17c8d9e17d8ce8ae41a08dcd526fb63 Mon Sep 17 00:00:00 2001
From: Rohin Bhargava <rohin@buildwithfern.com>
Date: Wed, 8 Jan 2025 17:28:05 -0500
Subject: [PATCH 10/11] address comments

---
 fern/apis/docs-yml/definition/docs.yml           |  4 ++--
 .../commands/generate/generateDocsWorkspace.ts   | 12 ++----------
 .../writeDocsDefinitionForProject.ts             | 12 ++----------
 .../cli/cli/src/utils/filterOssWorkspaces.ts     | 16 ++++++++++++++++
 .../resources/docs/types/ExperimentalConfig.ts   |  4 ++--
 .../resources/docs/types/ExperimentalConfig.ts   |  4 ++--
 packages/cli/docs-preview/src/previewDocs.ts     | 14 ++++++++++----
 .../docs-resolver/src/DocsDefinitionResolver.ts  |  2 +-
 8 files changed, 37 insertions(+), 31 deletions(-)
 create mode 100644 packages/cli/cli/src/utils/filterOssWorkspaces.ts

diff --git a/fern/apis/docs-yml/definition/docs.yml b/fern/apis/docs-yml/definition/docs.yml
index f7fdaea99f9..ad03f1b9102 100644
--- a/fern/apis/docs-yml/definition/docs.yml
+++ b/fern/apis/docs-yml/definition/docs.yml
@@ -974,10 +974,10 @@ types:
           If `disable-stream-toggle` is set to true, the stream toggle will be disabled.
 
           This behavior is unstable and may change in the future.
-      direct-openapi-parser:
+      openapi-parser-v2:
         type: optional<boolean>
         docs: |
-          If `direct-openapi-parser` is set to true, the OpenAPI parser will be used directly, without Fern.
+          If `openapi-parser-v2` is set to true, the OpenAPI parser will be used directly, without Fern.
 
   PlaygroundSettings:
     properties:
diff --git a/packages/cli/cli/src/commands/generate/generateDocsWorkspace.ts b/packages/cli/cli/src/commands/generate/generateDocsWorkspace.ts
index 389500144c3..53d6499b36b 100644
--- a/packages/cli/cli/src/commands/generate/generateDocsWorkspace.ts
+++ b/packages/cli/cli/src/commands/generate/generateDocsWorkspace.ts
@@ -6,6 +6,7 @@ import { Project } from "@fern-api/project-loader";
 import { runRemoteGenerationForDocsWorkspace } from "@fern-api/remote-workspace-runner";
 
 import { CliContext } from "../../cli-context/CliContext";
+import { filterOssWorkspaces } from "../../utils/filterOssWorkspaces";
 import { validateDocsWorkspaceAndLogIssues } from "../validate/validateDocsWorkspaceAndLogIssues";
 
 export async function generateDocsWorkspace({
@@ -60,16 +61,7 @@ export async function generateDocsWorkspace({
             })
         );
 
-        const ossWorkspaces = (
-            await Promise.all(
-                project.apiWorkspaces.map(async (workspace) => {
-                    if (workspace instanceof OSSWorkspace) {
-                        return workspace as OSSWorkspace;
-                    }
-                    return null;
-                })
-            )
-        ).filter(isNonNullish);
+        const ossWorkspaces = await filterOssWorkspaces(project);
 
         await runRemoteGenerationForDocsWorkspace({
             organization: project.config.organization,
diff --git a/packages/cli/cli/src/commands/write-docs-definition/writeDocsDefinitionForProject.ts b/packages/cli/cli/src/commands/write-docs-definition/writeDocsDefinitionForProject.ts
index 92b9aa4ce02..dbf7dde153c 100644
--- a/packages/cli/cli/src/commands/write-docs-definition/writeDocsDefinitionForProject.ts
+++ b/packages/cli/cli/src/commands/write-docs-definition/writeDocsDefinitionForProject.ts
@@ -8,6 +8,7 @@ import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
 import { Project } from "@fern-api/project-loader";
 
 import { CliContext } from "../../cli-context/CliContext";
+import { filterOssWorkspaces } from "../../utils/filterOssWorkspaces";
 
 export async function writeDocsDefinitionForProject({
     project,
@@ -24,16 +25,7 @@ export async function writeDocsDefinitionForProject({
     }
 
     await cliContext.runTaskForWorkspace(docsWorkspace, async (context) => {
-        const ossWorkspaces = (
-            await Promise.all(
-                project.apiWorkspaces.map(async (workspace) => {
-                    if (workspace instanceof OSSWorkspace) {
-                        return workspace as OSSWorkspace;
-                    }
-                    return null;
-                })
-            )
-        ).filter(isNonNullish);
+        const ossWorkspaces = await filterOssWorkspaces(project);
 
         const fernWorkspaces = await Promise.all(
             project.apiWorkspaces.map(async (workspace) => {
diff --git a/packages/cli/cli/src/utils/filterOssWorkspaces.ts b/packages/cli/cli/src/utils/filterOssWorkspaces.ts
new file mode 100644
index 00000000000..48b0080ff97
--- /dev/null
+++ b/packages/cli/cli/src/utils/filterOssWorkspaces.ts
@@ -0,0 +1,16 @@
+import { isNonNullish } from "@fern-api/core-utils";
+import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
+import { Project } from "@fern-api/project-loader";
+
+export async function filterOssWorkspaces(project: Project) {
+    return (
+        await Promise.all(
+            project.apiWorkspaces.map(async (workspace) => {
+                if (workspace instanceof OSSWorkspace) {
+                    return workspace as OSSWorkspace;
+                }
+                return null;
+            })
+        )
+    ).filter(isNonNullish);
+}
diff --git a/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/ExperimentalConfig.ts b/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/ExperimentalConfig.ts
index 2be87a68ee0..bf1dea97ac2 100644
--- a/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/ExperimentalConfig.ts
+++ b/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/ExperimentalConfig.ts
@@ -14,6 +14,6 @@ export interface ExperimentalConfig {
      * This behavior is unstable and may change in the future.
      */
     disableStreamToggle?: boolean;
-    /** If `direct-openapi-parser` is set to true, the OpenAPI parser will be used directly, without Fern. */
-    directOpenapiParser?: boolean;
+    /** If `openapi-parser-v2` is set to true, the OpenAPI parser will be used directly, without Fern. */
+    openapiParserV2?: boolean;
 }
diff --git a/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/ExperimentalConfig.ts b/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/ExperimentalConfig.ts
index 15e56d8453f..67ed0562277 100644
--- a/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/ExperimentalConfig.ts
+++ b/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/ExperimentalConfig.ts
@@ -15,13 +15,13 @@ export const ExperimentalConfig: core.serialization.ObjectSchema<
         core.serialization.list(core.serialization.string()).optional(),
     ),
     disableStreamToggle: core.serialization.property("disable-stream-toggle", core.serialization.boolean().optional()),
-    directOpenapiParser: core.serialization.property("direct-openapi-parser", core.serialization.boolean().optional()),
+    openapiParserV2: core.serialization.property("openapi-parser-v2", core.serialization.boolean().optional()),
 });
 
 export declare namespace ExperimentalConfig {
     export interface Raw {
         "mdx-components"?: string[] | null;
         "disable-stream-toggle"?: boolean | null;
-        "direct-openapi-parser"?: boolean | null;
+        "openapi-parser-v2"?: boolean | null;
     }
 }
diff --git a/packages/cli/docs-preview/src/previewDocs.ts b/packages/cli/docs-preview/src/previewDocs.ts
index 1ec1f6abb51..5ddf4d498e0 100644
--- a/packages/cli/docs-preview/src/previewDocs.ts
+++ b/packages/cli/docs-preview/src/previewDocs.ts
@@ -105,8 +105,8 @@ export async function getPreviewDocsDefinition({
     });
 
     return {
-        apis: parsedDocsConfig.experimental?.directOpenapiParser ? {} : apiCollector.getAPIsForDefinition(),
-        apisV2: parsedDocsConfig.experimental?.directOpenapiParser ? apiCollectorV2.getAPIsForDefinition() : {},
+        apis: parsedDocsConfig.experimental?.openapiParserV2 ? {} : apiCollector.getAPIsForDefinition(),
+        apisV2: parsedDocsConfig.experimental?.openapiParserV2 ? apiCollectorV2.getAPIsForDefinition() : {},
         config: readDocsConfig,
         files: {},
         filesV2,
@@ -156,7 +156,10 @@ class ReferencedAPICollector {
         } catch (e) {
             // Print Error
             const err = e as Error;
-            this.context.logger.error(`Failed to read referenced API: ${err?.message} ${err?.stack}`);
+            this.context.logger.debug(`Failed to read referenced API: ${err?.message} ${err?.stack}`);
+            this.context.logger.error(
+                "An error occured while trying to read an API definition. Please reach out to support."
+            );
             if (err.stack != null) {
                 this.context.logger.error(err?.stack);
             }
@@ -181,7 +184,10 @@ class ReferencedAPICollectorV2 {
         } catch (e) {
             // Print Error
             const err = e as Error;
-            this.context.logger.error(`Failed to read referenced API: ${err?.message} ${err?.stack}`);
+            this.context.logger.debug(`Failed to read referenced API: ${err?.message} ${err?.stack}`);
+            this.context.logger.error(
+                "An error occured while trying to read an API definition. Please reach out to support."
+            );
             if (err.stack != null) {
                 this.context.logger.error(err?.stack);
             }
diff --git a/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts b/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts
index 15db2285e27..fb8c5c560f1 100644
--- a/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts
+++ b/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts
@@ -576,7 +576,7 @@ export class DocsDefinitionResolver {
         item: docsYml.DocsNavigationItem.ApiSection,
         parentSlug: FernNavigation.V1.SlugGenerator
     ): Promise<FernNavigation.V1.ApiReferenceNode> {
-        if (this.parsedDocsConfig.experimental?.directOpenapiParser) {
+        if (this.parsedDocsConfig.experimental?.openapiParserV2) {
             const workspace = this.getOpenApiWorkspaceForApiSection(item);
             const api = await generateFdrFromOpenApiWorkspace(workspace, this.taskContext);
             if (api == null) {

From 917cd17bd27ffe64e308895aa8ec1a9d26832449 Mon Sep 17 00:00:00 2001
From: Rohin Bhargava <rohin@buildwithfern.com>
Date: Wed, 8 Jan 2025 17:38:27 -0500
Subject: [PATCH 11/11] ci/cd

---
 docs-yml.schema.json                                           | 2 +-
 packages/cli/cli/src/utils/filterOssWorkspaces.ts              | 2 +-
 packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts    | 3 ++-
 .../cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts   | 3 ++-
 4 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/docs-yml.schema.json b/docs-yml.schema.json
index bf779c195b1..7bb37f2dc7b 100644
--- a/docs-yml.schema.json
+++ b/docs-yml.schema.json
@@ -2259,7 +2259,7 @@
             }
           ]
         },
-        "direct-openapi-parser": {
+        "openapi-parser-v2": {
           "oneOf": [
             {
               "type": "boolean"
diff --git a/packages/cli/cli/src/utils/filterOssWorkspaces.ts b/packages/cli/cli/src/utils/filterOssWorkspaces.ts
index 48b0080ff97..259bd895217 100644
--- a/packages/cli/cli/src/utils/filterOssWorkspaces.ts
+++ b/packages/cli/cli/src/utils/filterOssWorkspaces.ts
@@ -2,7 +2,7 @@ import { isNonNullish } from "@fern-api/core-utils";
 import { OSSWorkspace } from "@fern-api/lazy-fern-workspace";
 import { Project } from "@fern-api/project-loader";
 
-export async function filterOssWorkspaces(project: Project) {
+export async function filterOssWorkspaces(project: Project): Promise<OSSWorkspace[]> {
     return (
         await Promise.all(
             project.apiWorkspaces.map(async (workspace) => {
diff --git a/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts b/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts
index 5c222480b4a..1702ff82daf 100644
--- a/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts
+++ b/packages/cli/docs-resolver/src/ApiReferenceNodeConverter.ts
@@ -511,7 +511,8 @@ export class ApiReferenceNodeConverter {
             left,
             right,
             findEndpointById: (endpointId) => this.#holder.endpoints.get(endpointId),
-            stringifyEndpointPathParts: (endpoint) => stringifyEndpointPathParts(endpoint.path.parts),
+            stringifyEndpointPathParts: (endpoint: APIV1Read.EndpointDefinition) =>
+                stringifyEndpointPathParts(endpoint.path.parts),
             disableEndpointPairs: this.disableEndpointPairs,
             apiDefinitionId: this.apiDefinitionId
         });
diff --git a/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts b/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts
index dca531db38d..5a913ddf9d4 100644
--- a/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts
+++ b/packages/cli/docs-resolver/src/ApiReferenceNodeConverterLatest.ts
@@ -553,7 +553,8 @@ export class ApiReferenceNodeConverterLatest {
             left,
             right,
             findEndpointById: (endpointId) => this.#findEndpointByLocator(endpointId),
-            stringifyEndpointPathParts: (endpoint) => stringifyEndpointPathParts(endpoint.path),
+            stringifyEndpointPathParts: (endpoint: FdrAPI.api.latest.EndpointDefinition) =>
+                stringifyEndpointPathParts(endpoint.path),
             disableEndpointPairs: this.disableEndpointPairs,
             apiDefinitionId: this.apiDefinitionId
         });