diff --git a/packages/ui/app/src/api-reference/examples/AudioExample.tsx b/packages/ui/app/src/api-reference/examples/AudioExample.tsx index cb439a1068..7b29009298 100644 --- a/packages/ui/app/src/api-reference/examples/AudioExample.tsx +++ b/packages/ui/app/src/api-reference/examples/AudioExample.tsx @@ -17,7 +17,7 @@ const AudioExampleInternal: FC = ({ ...props }) => { return ( diff --git a/packages/ui/docs-bundle/.depcheckrc.json b/packages/ui/docs-bundle/.depcheckrc.json index 83c9a1d808..af1c0509a2 100644 --- a/packages/ui/docs-bundle/.depcheckrc.json +++ b/packages/ui/docs-bundle/.depcheckrc.json @@ -12,8 +12,6 @@ "tailwindcss", "jsonpath", "cssnano", - "node-fetch", - "@types/node-fetch", "sharp", "esbuild", "glslify-import", diff --git a/packages/ui/docs-bundle/package.json b/packages/ui/docs-bundle/package.json index 674ec950fa..ee8fa4d94d 100644 --- a/packages/ui/docs-bundle/package.json +++ b/packages/ui/docs-bundle/package.json @@ -32,7 +32,6 @@ "@fern-api/fdr-sdk": "workspace:*", "@fern-api/ui-core-utils": "workspace:*", "@fern-fern/fern-docs-sdk": "0.0.5", - "@fern-fern/proxy-sdk": "0.0.26", "@fern-ui/components": "workspace:*", "@fern-ui/fdr-utils": "workspace:*", "@fern-ui/fern-docs-auth": "workspace:*", @@ -55,12 +54,10 @@ "es-toolkit": "^1.27.0", "esbuild": "0.20.2", "feed": "^4.2.2", - "form-data": "4.0.0", "iron-session": "^8.0.3", "jose": "^5.2.3", "jsonpath": "^1.1.1", "next": "^14", - "node-fetch": "2.7.0", "postcss-import": "^16.0.1", "posthog-node": "^4.2.1", "qs": "6.12.0", @@ -78,7 +75,6 @@ "@tailwindcss/forms": "^0.5.7", "@tailwindcss/typography": "^0.5.10", "@types/node": "^18.7.18", - "@types/node-fetch": "2.6.9", "@types/react": "^18", "@types/react-dom": "^18", "autoprefixer": "^10.4.16", diff --git a/packages/ui/docs-bundle/src/pages/api/fern-docs/proxy/file.ts b/packages/ui/docs-bundle/src/app/api/fern-docs/proxy/file/route.ts similarity index 64% rename from packages/ui/docs-bundle/src/pages/api/fern-docs/proxy/file.ts rename to packages/ui/docs-bundle/src/app/api/fern-docs/proxy/file/route.ts index 2b05058607..404c7228f8 100644 --- a/packages/ui/docs-bundle/src/pages/api/fern-docs/proxy/file.ts +++ b/packages/ui/docs-bundle/src/app/api/fern-docs/proxy/file/route.ts @@ -1,32 +1,22 @@ +import { buildRequestBody } from "@/server/buildRequestBody"; +import { withProxyCors } from "@/server/withProxyCors"; +import { getDocsDomainEdge } from "@/server/xfernhost/edge"; import { ProxyRequestSchema } from "@fern-ui/ui"; -import { buildRequestBody } from "./rest"; +import { NextRequest, NextResponse } from "next/server"; /** * Note: edge functions must return a response within 25 seconds. */ export const runtime = "edge"; -export const dynamic = "force-dynamic"; -export default async function handler(req: Request): Promise { - if (req.method !== "POST" && req.method !== "OPTIONS") { - return new Response(null, { status: 405 }); - } - - const origin = req.headers.get("origin"); - if (origin == null) { - return new Response(null, { status: 400 }); - } - - const headers = new Headers({ - "Access-Control-Allow-Origin": origin, - "Access-Control-Allow-Methods": "POST", - "Access-Control-Allow-Headers": "Content-Type", - }); +export async function OPTIONS(req: NextRequest): Promise { + const headers = new Headers(withProxyCors(getDocsDomainEdge(req))); + return new NextResponse(null, { status: 204, headers }); +} - if (req.method === "OPTIONS") { - return new Response(null, { status: 204, headers }); - } +export async function POST(req: NextRequest): Promise { + const headers = new Headers(withProxyCors(getDocsDomainEdge(req))); // eslint-disable-next-line no-console console.log("Starting proxy request to", req.url); @@ -56,13 +46,13 @@ export default async function handler(req: Request): Promise { headers.set(name, value); }); - return new Response(response.body, { + return new NextResponse(response.body, { status: response.status, headers, }); } catch (err) { // eslint-disable-next-line no-console console.error(err); - return new Response(null, { status: 500 }); + return new NextResponse(null, { status: 500 }); } } diff --git a/packages/ui/docs-bundle/src/app/api/fern-docs/proxy/rest/route.ts b/packages/ui/docs-bundle/src/app/api/fern-docs/proxy/rest/route.ts new file mode 100644 index 0000000000..9c98ccb6e2 --- /dev/null +++ b/packages/ui/docs-bundle/src/app/api/fern-docs/proxy/rest/route.ts @@ -0,0 +1,94 @@ +import { buildRequestBody } from "@/server/buildRequestBody"; +import { withProxyCors } from "@/server/withProxyCors"; +import { getDocsDomainEdge } from "@/server/xfernhost/edge"; +import { ProxyRequestSchema } from "@fern-ui/ui"; +import { NextRequest, NextResponse } from "next/server"; + +/** + * Note: edge functions must return a response within 25 seconds. + */ + +export const runtime = "edge"; + +export async function OPTIONS(req: NextRequest): Promise { + const headers = new Headers(withProxyCors(getDocsDomainEdge(req))); + + return new NextResponse(null, { status: 204, headers }); +} + +export async function POST(req: NextRequest): Promise { + const headers = new Headers(withProxyCors(getDocsDomainEdge(req))); + + // eslint-disable-next-line no-console + console.log("Starting proxy request to", req.url); + + try { + const body = await req.json(); + const proxyRequest = ProxyRequestSchema.parse(body); + const [mime, requestBody] = await buildRequestBody(proxyRequest.body); + const proxyHeaders = new Headers(proxyRequest.headers); + + // omit content-type for multipart/form-data so that fetch can set it automatically with the boundary + const contentType = proxyHeaders.get("Content-Type"); + if (contentType != null && contentType.toLowerCase().includes("multipart/form-data")) { + proxyHeaders.delete("Content-Type"); + } else if (mime != null) { + proxyHeaders.set("Content-Type", mime); + } + + const startTime = Date.now(); + + const response = await fetch(proxyRequest.url, { + method: proxyRequest.method, + headers: proxyHeaders, + body: requestBody, + }); + + // eslint-disable-next-line no-console + console.log("Proxy request to", req.url, "completed with status", response.status); + + let responseBody = await response.text(); + const endTime = Date.now(); + + // eslint-disable-next-line no-console + console.log("Proxy request to", req.url, "received response body after", endTime - startTime, "milliseconds"); + + try { + responseBody = JSON.parse(responseBody); + } catch (e) { + // eslint-disable-next-line no-console + console.log("Failed to parse response body as JSON, but will return it as text."); + // eslint-disable-next-line no-console + console.error(e); + } + + response.headers.forEach((value, name) => { + headers.set(name, value); + }); + + return new NextResponse( + JSON.stringify({ + response: { + headers: Object.fromEntries(response.headers.entries()), + ok: response.ok, + redirected: response.redirected, + status: response.status, + statusText: response.statusText, + type: response.type, + url: response.url, + body: responseBody, + }, + time: endTime - startTime, + size: response.headers.get("Content-Length"), + }), + { + status: 200, + headers, + }, + ); + } catch (err) { + // eslint-disable-next-line no-console + console.error(err); + return new NextResponse(null, { status: 500 }); + } +} diff --git a/packages/ui/docs-bundle/src/pages/api/fern-docs/proxy/stream.ts b/packages/ui/docs-bundle/src/app/api/fern-docs/proxy/stream/route.ts similarity index 74% rename from packages/ui/docs-bundle/src/pages/api/fern-docs/proxy/stream.ts rename to packages/ui/docs-bundle/src/app/api/fern-docs/proxy/stream/route.ts index 5b29f0206a..991eaa1a99 100644 --- a/packages/ui/docs-bundle/src/pages/api/fern-docs/proxy/stream.ts +++ b/packages/ui/docs-bundle/src/app/api/fern-docs/proxy/stream/route.ts @@ -1,3 +1,5 @@ +import { withProxyCors } from "@/server/withProxyCors"; +import { getDocsDomainEdge } from "@/server/xfernhost/edge"; import { ProxyRequestSchema } from "@fern-ui/ui"; import { NextRequest, NextResponse } from "next/server"; @@ -6,27 +8,15 @@ import { NextRequest, NextResponse } from "next/server"; */ export const runtime = "edge"; -export const dynamic = "force-dynamic"; -export default async function POST(req: NextRequest): Promise> { - if (req.method !== "POST" && req.method !== "OPTIONS") { - return new NextResponse(null, { status: 405 }); - } - - const origin = req.headers.get("Origin"); - if (origin == null) { - return new NextResponse(null, { status: 400 }); - } +export async function OPTIONS(req: NextRequest): Promise { + const headers = new Headers(withProxyCors(getDocsDomainEdge(req))); + return new NextResponse(null, { status: 204, headers }); +} - const corsHeaders = { - "Access-Control-Allow-Origin": origin, - "Access-Control-Allow-Methods": "POST", - "Access-Control-Allow-Headers": "Content-Type", - }; +export async function POST(req: NextRequest): Promise> { + const corsHeaders = new Headers(withProxyCors(getDocsDomainEdge(req))); - if (req.method === "OPTIONS") { - return new NextResponse(null, { status: 204, headers: corsHeaders }); - } try { const proxyRequest = ProxyRequestSchema.parse(await req.json()); const startTime = Date.now(); diff --git a/packages/ui/docs-bundle/src/pages/api/fern-docs/proxy/grpc.ts b/packages/ui/docs-bundle/src/pages/api/fern-docs/proxy/grpc.ts deleted file mode 100644 index 93b42f1eff..0000000000 --- a/packages/ui/docs-bundle/src/pages/api/fern-docs/proxy/grpc.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { buildFormData } from "@/server/buildFormData"; -import { resolveSerializableFile } from "@/server/resolveSerializableFile"; -import { assertNever } from "@fern-api/ui-core-utils"; -import { FernProxyClient } from "@fern-fern/proxy-sdk"; -import type { ProxyRequest } from "@fern-ui/ui"; -import type { NextApiRequest, NextApiResponse } from "next/types"; -import { type BodyInit } from "node-fetch"; -import { parse } from "url"; - -/** - * Note: this API route must be deployed as an node.js serverless function because - * edge functions must return a response within 25 seconds. - * - * NodeJS serverless functions can have a maximum execution time of 5 minutes. - * - * TODO: this is kind of expensive to run as a serverless function in vercel. We should consider moving this to cloudflare workers. - */ - -export const config = { - maxDuration: 300, // 5 minutes -}; - -export async function buildRequestBody( - body: ProxyRequest.SerializableBody | undefined, -): Promise<[mime: string | undefined, BodyInit | undefined]> { - if (body == null) { - return [undefined, undefined]; - } - - switch (body.type) { - case "json": - return ["application/json", JSON.stringify(body.value)]; - case "form-data": { - const form = await buildFormData(body.value); - return [undefined, form]; - } - case "octet-stream": { - if (body.value == null) { - return [undefined, undefined]; - } - return resolveSerializableFile(body.value); - } - default: - assertNever(body); - } -} - -export default async function handler(req: NextApiRequest, res: NextApiResponse): Promise { - if (req.method !== "POST" && req.method !== "OPTIONS") { - return res.status(405).send(null); - } - - const origin = req.headers.origin; - if (origin == null) { - return res.status(400).send(null); - } - - res.setHeader("Access-Control-Allow-Origin", origin); - res.setHeader("Access-Control-Allow-Methods", "POST"); - res.setHeader("Access-Control-Allow-Headers", "Content-Type"); - - if (req.method === "OPTIONS") { - return res.status(204).send(null); - } - - // eslint-disable-next-line no-console - console.log("Starting proxy request to", req.url); - - try { - const request = JSON.parse(req.body); - - const startTime = Date.now(); - - const grpcClient = new FernProxyClient({ - environment: "https://kmxxylsbwyu2f4x7rbhreris3i0zfbys.lambda-url.us-east-1.on.aws", - }); - - const baseUrl = parse(request.baseUrl); - const grpcResponse = (await grpcClient.grpc({ - baseUrl: `${baseUrl.protocol}//${baseUrl.host}`, - endpoint: request.endpoint, - headers: request.headers, - body: request.body, - })) as unknown as string; - - if (grpcResponse === "Cannot convert undefined or null to object" || grpcResponse.includes("exit code")) { - throw new Error(grpcResponse); - } - // commented out - // let body = grpcResponse.body as string; - - const endTime = Date.now(); - - // eslint-disable-next-line no-console - console.log("Proxy request to", req.url, "received response body after", endTime - startTime, "milliseconds"); - - let body; - try { - body = JSON.parse(grpcResponse); - } catch (e) { - // eslint-disable-next-line no-console - console.log("Failed to parse response body as JSON, but will return it as text."); - // eslint-disable-next-line no-console - console.error(e); - } - - return res.status(200).json({ - response: { - body, - }, - time: endTime - startTime, - size: new TextEncoder().encode(JSON.stringify(body)).length, - }); - } catch (err) { - // eslint-disable-next-line no-console - console.error(err); - return res.status(500).send(null); - } -} diff --git a/packages/ui/docs-bundle/src/pages/api/fern-docs/proxy/rest.ts b/packages/ui/docs-bundle/src/pages/api/fern-docs/proxy/rest.ts deleted file mode 100644 index 3851a8a2d6..0000000000 --- a/packages/ui/docs-bundle/src/pages/api/fern-docs/proxy/rest.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { buildFormData } from "@/server/buildFormData"; -import { resolveSerializableFile } from "@/server/resolveSerializableFile"; -import { assertNever } from "@fern-api/ui-core-utils"; -import type { ProxyRequest } from "@fern-ui/ui"; -import { ProxyRequestSchema } from "@fern-ui/ui"; -import type { NextApiRequest, NextApiResponse } from "next/types"; -import fetch, { Headers, type BodyInit } from "node-fetch"; - -/** - * Note: this API route must be deployed as an node.js serverless function because - * edge functions must return a response within 25 seconds. - * - * NodeJS serverless functions can have a maximum execution time of 5 minutes. - * - * TODO: this is kind of expensive to run as a serverless function in vercel. We should consider moving this to cloudflare workers. - */ - -export const config = { - maxDuration: 300, // 5 minutes -}; - -export async function buildRequestBody( - body: ProxyRequest.SerializableBody | undefined, -): Promise<[mime: string | undefined, BodyInit | undefined]> { - if (body == null) { - return [undefined, undefined]; - } - - switch (body.type) { - case "json": - return ["application/json", JSON.stringify(body.value)]; - case "form-data": { - const form = await buildFormData(body.value); - return [undefined, form]; - } - case "octet-stream": { - if (body.value == null) { - return [undefined, undefined]; - } - return resolveSerializableFile(body.value); - } - default: - assertNever(body); - } -} - -export default async function handler(req: NextApiRequest, res: NextApiResponse): Promise { - if (req.method !== "POST" && req.method !== "OPTIONS") { - return res.status(405).send(null); - } - - const origin = req.headers.origin; - if (origin == null) { - return res.status(400).send(null); - } - - res.setHeader("Access-Control-Allow-Origin", origin); - res.setHeader("Access-Control-Allow-Methods", "POST"); - res.setHeader("Access-Control-Allow-Headers", "Content-Type"); - - if (req.method === "OPTIONS") { - return res.status(204).send(null); - } - - // eslint-disable-next-line no-console - console.log("Starting proxy request to", req.url); - - try { - const proxyRequest = ProxyRequestSchema.parse(req.body); - const [mime, requestBody] = await buildRequestBody(proxyRequest.body); - const headers = new Headers(proxyRequest.headers); - - // omit content-type for multipart/form-data so that fetch can set it automatically with the boundary - const contentType = headers.get("Content-Type"); - if (contentType != null && contentType.toLowerCase().includes("multipart/form-data")) { - headers.delete("Content-Type"); - } else if (mime != null) { - headers.set("Content-Type", mime); - } - - const startTime = Date.now(); - - const response = await fetch(proxyRequest.url, { - method: proxyRequest.method, - headers, - body: requestBody, - }); - - // eslint-disable-next-line no-console - console.log("Proxy request to", req.url, "completed with status", response.status); - - let body = await response.text(); - const endTime = Date.now(); - - // eslint-disable-next-line no-console - console.log("Proxy request to", req.url, "received response body after", endTime - startTime, "milliseconds"); - - try { - body = JSON.parse(body); - } catch (e) { - // eslint-disable-next-line no-console - console.log("Failed to parse response body as JSON, but will return it as text."); - // eslint-disable-next-line no-console - console.error(e); - } - const responseHeaders = response.headers; - - return res.status(200).json({ - response: { - headers: Object.fromEntries(responseHeaders.entries()), - ok: response.ok, - redirected: response.redirected, - status: response.status, - statusText: response.statusText, - type: response.type, - url: response.url, - body, - }, - time: endTime - startTime, - size: responseHeaders.get("Content-Length"), - }); - } catch (err) { - // eslint-disable-next-line no-console - console.error(err); - return res.status(500).send(null); - } -} diff --git a/packages/ui/docs-bundle/src/server/DocsLoader.ts b/packages/ui/docs-bundle/src/server/DocsLoader.ts index 5994ca1738..6e344d0756 100644 --- a/packages/ui/docs-bundle/src/server/DocsLoader.ts +++ b/packages/ui/docs-bundle/src/server/DocsLoader.ts @@ -88,7 +88,7 @@ export class DocsLoader { } const v1 = res.definition.apis[key]; const latest = - res.definition.apisV2[key] ?? + res.definition.apisV2?.[key] ?? (v1 != null ? ApiDefinitionV1ToLatest.from(v1, this.featureFlags).migrate() : undefined); if (!latest) { return undefined; diff --git a/packages/ui/docs-bundle/src/server/__test__/buildFormData.test.ts b/packages/ui/docs-bundle/src/server/__test__/buildFormData.test.ts index 02bda5af02..0080922638 100644 --- a/packages/ui/docs-bundle/src/server/__test__/buildFormData.test.ts +++ b/packages/ui/docs-bundle/src/server/__test__/buildFormData.test.ts @@ -21,7 +21,7 @@ describe("buildFormData", () => { const form = await buildFormData(serializedFormData); // Assert - expect(form.getLengthSync()).toBeGreaterThan(0); + expect(form.get("file")).toBeTruthy(); }); it("should build a form data object with a file array", async () => { @@ -49,6 +49,6 @@ describe("buildFormData", () => { }; const form = await buildFormData(serializedFormData); - expect(form.getLengthSync()).toBeGreaterThan(0); + expect(form.get("files")).toBeTruthy(); }); }); diff --git a/packages/ui/docs-bundle/src/server/buildFormData.ts b/packages/ui/docs-bundle/src/server/buildFormData.ts index eef7af976e..2d6af8fd17 100644 --- a/packages/ui/docs-bundle/src/server/buildFormData.ts +++ b/packages/ui/docs-bundle/src/server/buildFormData.ts @@ -1,10 +1,10 @@ import { assertNever, unknownToString } from "@fern-api/ui-core-utils"; import type { SerializableFormDataEntryValue } from "@fern-ui/ui"; -import FormData from "form-data"; import { resolveSerializableFile } from "./resolveSerializableFile"; export async function buildFormData( serializedFormData: Record, + jsonBlobShouldContainContentType: boolean = false, ): Promise { const form = new FormData(); for (const [key, value] of Object.entries(serializedFormData)) { @@ -12,19 +12,15 @@ export async function buildFormData( case "file": if (value.value != null) { const [contentType, buffer] = await resolveSerializableFile(value.value); - form.append(key, buffer, { - filename: value.value.name, - contentType, - }); + const blob = new Blob([buffer], { type: contentType }); + form.append(key, blob, value.value.name); } break; case "fileArray": { for (const serializedFile of value.value) { const [contentType, buffer] = await resolveSerializableFile(serializedFile); - form.append(key, buffer, { - filename: serializedFile.name, - contentType, - }); + const blob = new Blob([buffer], { type: contentType }); + form.append(key, blob, serializedFile.name); } break; } @@ -32,7 +28,10 @@ export async function buildFormData( const content = value.contentType?.includes("application/json") ? JSON.stringify(value.value) : unknownToString(value.value); - form.append(key, content, { contentType: value.contentType }); + const blob = jsonBlobShouldContainContentType + ? new Blob([content], { type: value.contentType ?? "application/json" }) + : content; + form.append(key, blob); break; } default: diff --git a/packages/ui/docs-bundle/src/server/buildRequestBody.ts b/packages/ui/docs-bundle/src/server/buildRequestBody.ts new file mode 100644 index 0000000000..a91037ffed --- /dev/null +++ b/packages/ui/docs-bundle/src/server/buildRequestBody.ts @@ -0,0 +1,29 @@ +import { assertNever } from "@fern-api/ui-core-utils"; +import { ProxyRequest } from "@fern-ui/ui"; +import { buildFormData } from "./buildFormData"; +import { resolveSerializableFile } from "./resolveSerializableFile"; + +export async function buildRequestBody( + body: ProxyRequest.SerializableBody | undefined, +): Promise<[mime: string | undefined, BodyInit | undefined]> { + if (body == null) { + return [undefined, undefined]; + } + + switch (body.type) { + case "json": + return ["application/json", JSON.stringify(body.value)]; + case "form-data": { + const form = await buildFormData(body.value); + return [undefined, form]; + } + case "octet-stream": { + if (body.value == null) { + return [undefined, undefined]; + } + return resolveSerializableFile(body.value); + } + default: + assertNever(body); + } +} diff --git a/packages/ui/docs-bundle/src/server/resolveSerializableFile.ts b/packages/ui/docs-bundle/src/server/resolveSerializableFile.ts index f7d92f596f..a636b6e840 100644 --- a/packages/ui/docs-bundle/src/server/resolveSerializableFile.ts +++ b/packages/ui/docs-bundle/src/server/resolveSerializableFile.ts @@ -1,5 +1,4 @@ import { SerializableFile } from "@fern-ui/ui"; -import fetch from "node-fetch"; export async function resolveSerializableFile( file: Pick, diff --git a/packages/ui/docs-bundle/src/server/withProxyCors.ts b/packages/ui/docs-bundle/src/server/withProxyCors.ts new file mode 100644 index 0000000000..1379c59bb8 --- /dev/null +++ b/packages/ui/docs-bundle/src/server/withProxyCors.ts @@ -0,0 +1,7 @@ +export function withProxyCors(origin: string): HeadersInit { + return { + "Access-Control-Allow-Origin": origin, + "Access-Control-Allow-Methods": "POST", + "Access-Control-Allow-Headers": "Content-Type", + }; +} diff --git a/packages/ui/docs-bundle/tsconfig.json b/packages/ui/docs-bundle/tsconfig.json index d32138ac96..1de58e5a0b 100644 --- a/packages/ui/docs-bundle/tsconfig.json +++ b/packages/ui/docs-bundle/tsconfig.json @@ -5,7 +5,8 @@ "rootDir": ".", "paths": { "@/*": ["./src/*"] - } + }, + "strictNullChecks": true }, "exclude": ["node_modules"], "include": ["./src/**/*", ".next/types/**/*.ts", "__mocks__"], diff --git a/packages/ui/fern-docs-server/src/ApiDefinitionLoader.ts b/packages/ui/fern-docs-server/src/ApiDefinitionLoader.ts index ad563f354e..9290105f00 100644 --- a/packages/ui/fern-docs-server/src/ApiDefinitionLoader.ts +++ b/packages/ui/fern-docs-server/src/ApiDefinitionLoader.ts @@ -101,15 +101,6 @@ export class ApiDefinitionLoader { // } const latest = await this.#getClient().api.latest.getApiLatest(this.apiDefinitionId); - if (!latest.ok) { - if (latest.error.error === "ApiDoesNotExistError") { - return undefined; - } else { - // eslint-disable-next-line no-console - console.error(latest?.error?.content); - throw new Error("Failed to load API definition"); - } - } if (latest.ok) { return latest.body; } @@ -128,6 +119,16 @@ export class ApiDefinitionLoader { return ApiDefinitionV1ToLatest.from(v1.body, this.flags).migrate(); } + if (!latest.ok) { + if (latest.error.error === "ApiDoesNotExistError") { + return undefined; + } else { + // eslint-disable-next-line no-console + console.error(latest?.error?.content); + throw new Error("Failed to load API definition"); + } + } + return undefined; // await this.cache.setApiDefinition(apiDefinition); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ed10a4a027..3955eef312 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1720,9 +1720,6 @@ importers: '@fern-fern/fern-docs-sdk': specifier: 0.0.5 version: 0.0.5 - '@fern-fern/proxy-sdk': - specifier: 0.0.26 - version: 0.0.26 '@fern-ui/components': specifier: workspace:* version: link:../components @@ -1789,9 +1786,6 @@ importers: feed: specifier: ^4.2.2 version: 4.2.2 - form-data: - specifier: 4.0.0 - version: 4.0.0 iron-session: specifier: ^8.0.3 version: 8.0.3 @@ -1804,9 +1798,6 @@ importers: next: specifier: npm:@fern-api/next@14.2.9-fork.2 version: '@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)' - node-fetch: - specifier: 2.7.0 - version: 2.7.0 postcss-import: specifier: ^16.0.1 version: 16.1.0(postcss@8.4.31) @@ -1866,9 +1857,6 @@ importers: '@types/node': specifier: ^18.7.18 version: 18.19.33 - '@types/node-fetch': - specifier: 2.6.9 - version: 2.6.9 '@types/react': specifier: ^18 version: 18.3.3 @@ -4695,9 +4683,6 @@ packages: '@fern-fern/paged-generators-sdk@0.0.5706': resolution: {integrity: sha512-E+qk3MT+opUqt4JXPw4OQ/2GwssUk5GJvLY3ytwIT7BQ/8F3/IVDqcpOP6/wByVCwU0UKRGJQUf/HrUwbk0XYA==} - '@fern-fern/proxy-sdk@0.0.26': - resolution: {integrity: sha512-BEt0sfP5VcyDe4cipSSaDZ6jf4CgNaq0SlsqyEi64vC14VCeVupes9WLBExdMsCXK8ve7ov9E54Eh6ccpb+8UA==} - '@fern-fern/revalidation-sdk@0.0.9': resolution: {integrity: sha512-iZhm1odMdgWqlJi8B6lUPkza8YFfPz6iAhLfTkTnG4cpgPLER4sdQ8tlO+sUcGJF07Z3KkCRKmD6k54wNhv6Gg==} @@ -18413,17 +18398,6 @@ snapshots: transitivePeerDependencies: - encoding - '@fern-fern/proxy-sdk@0.0.26': - dependencies: - form-data: 4.0.0 - formdata-node: 6.0.3 - node-fetch: 2.7.0 - qs: 6.11.2 - readable-stream: 4.5.2 - url-join: 4.0.1 - transitivePeerDependencies: - - encoding - '@fern-fern/revalidation-sdk@0.0.9': dependencies: form-data: 4.0.0 diff --git a/servers/fdr-deploy/scripts/fdr-deploy-stack.ts b/servers/fdr-deploy/scripts/fdr-deploy-stack.ts index 14b3e97b7e..7f43a5f630 100644 --- a/servers/fdr-deploy/scripts/fdr-deploy-stack.ts +++ b/servers/fdr-deploy/scripts/fdr-deploy-stack.ts @@ -215,6 +215,7 @@ export class FdrDeployStack extends Stack { environmentType === "DEV2" ? "https://files-dev2.buildwithfern.com" : "https://files.buildwithfern.com", + NODE_ENV: "production", }, containerName: CONTAINER_NAME, containerPort: 8080,