diff --git a/fern/apis/proxy/generators.yml b/fern/apis/proxy/generators.yml index eaebaa0035..3e34fea07a 100644 --- a/fern/apis/proxy/generators.yml +++ b/fern/apis/proxy/generators.yml @@ -1,18 +1,18 @@ default-group: local groups: sdk: - generators: [] - # - name: fernapi/fern-typescript-node-sdk - # version: 0.17.1 - # output: - # location: npm - # url: npm.buildwithfern.com - # package-name: "@fern-fern/proxy-sdk" - # config: - # skipResponseValidation: true - # outputEsm: true - # noSerdeLayer: true - # noOptionalProperties: true + generators: + - name: fernapi/fern-typescript-node-sdk + version: 0.40.7 + output: + location: npm + url: npm.buildwithfern.com + package-name: "@fern-fern/proxy-sdk" + config: + skipResponseValidation: true + outputEsm: true + noSerdeLayer: true + noOptionalProperties: true local: generators: diff --git a/packages/ui/app/package.json b/packages/ui/app/package.json index 54346fac0f..2509103c86 100644 --- a/packages/ui/app/package.json +++ b/packages/ui/app/package.json @@ -43,6 +43,7 @@ "@fern-ui/next-seo": "workspace:*", "@fern-ui/react-commons": "workspace:*", "@fern-ui/search-utils": "workspace:*", + "@fern-fern/proxy-sdk": "0.0.21", "@inkeep/widgets": "^0.2.288", "@next/third-parties": "14.2.9", "@radix-ui/colors": "^3.0.0", diff --git a/packages/ui/app/src/playground/fetch-utils/executeGrpc.ts b/packages/ui/app/src/playground/fetch-utils/executeGrpc.ts index 9c9362aa6b..48d4d66afd 100644 --- a/packages/ui/app/src/playground/fetch-utils/executeGrpc.ts +++ b/packages/ui/app/src/playground/fetch-utils/executeGrpc.ts @@ -1,6 +1,6 @@ +import { FernProxyClient } from "@fern-fern/proxy-sdk"; import { GrpcProxyRequest, ProxyResponse } from "../types"; import { PlaygroundResponse } from "../types/playgroundResponse"; -import { FernProxyClient } from "./generated"; export async function executeGrpc(grpcClient: FernProxyClient, req: GrpcProxyRequest): Promise { let time = 0; @@ -22,6 +22,7 @@ export async function executeGrpc(grpcClient: FernProxyClient, req: GrpcProxyReq endpoint: req.endpointId, headers: req.headers, body: req.body, + schema: undefined, }); stopTimer(); diff --git a/packages/ui/app/src/playground/fetch-utils/generated/Client.ts b/packages/ui/app/src/playground/fetch-utils/generated/Client.ts deleted file mode 100644 index 219c51b2e9..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/Client.ts +++ /dev/null @@ -1,253 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -import * as core from "./core"; -import * as FernProxy from "./api/index"; -import urlJoin from "url-join"; -import * as errors from "./errors/index"; -import * as stream from "stream"; - -export declare namespace FernProxyClient { - interface Options { - environment: core.Supplier; - } - - interface RequestOptions { - timeoutInSeconds?: number; - maxRetries?: number; - abortSignal?: AbortSignal; - } -} - -export class FernProxyClient { - constructor(protected readonly _options: FernProxyClient.Options) {} - - /** - * @param {FernProxy.ProxyRequest} request - * @param {FernProxyClient.RequestOptions} requestOptions - Request-specific configuration. - * - * @example - * await fernProxy.rest({ - * url: "string", - * method: "string", - * headers: { - * "string": "string" - * }, - * body: { - * type: "json", - * value: { - * "key": "value" - * } - * }, - * stream: true, - * streamTerminator: "string" - * }) - */ - public async rest( - request: FernProxy.ProxyRequest, - requestOptions?: FernProxyClient.RequestOptions - ): Promise { - const _response = await core.fetcher({ - url: urlJoin(await core.Supplier.get(this._options.environment), "/api/fern-docs/proxy/rest"), - method: "POST", - headers: { - "X-Fern-Language": "JavaScript", - "X-Fern-Runtime": core.RUNTIME.type, - "X-Fern-Runtime-Version": core.RUNTIME.version, - }, - contentType: "application/json", - body: request, - timeoutMs: requestOptions?.timeoutInSeconds != null ? requestOptions.timeoutInSeconds * 1000 : 60000, - maxRetries: requestOptions?.maxRetries, - abortSignal: requestOptions?.abortSignal, - }); - if (_response.ok) { - return _response.body as FernProxy.ProxyResponse; - } - - if (_response.error.reason === "status-code") { - throw new errors.FernProxyError({ - statusCode: _response.error.statusCode, - body: _response.error.body, - }); - } - - switch (_response.error.reason) { - case "non-json": - throw new errors.FernProxyError({ - statusCode: _response.error.statusCode, - body: _response.error.rawBody, - }); - case "timeout": - throw new errors.FernProxyTimeoutError(); - case "unknown": - throw new errors.FernProxyError({ - message: _response.error.errorMessage, - }); - } - } - - /** - * @param {FernProxy.GrpcProxyRequest} request - * @param {FernProxyClient.RequestOptions} requestOptions - Request-specific configuration. - * - * @example - * await fernProxy.grpc({ - * baseUrl: "string", - * endpoint: "string", - * headers: { - * "string": "string" - * }, - * schema: { - * type: "remote" - * }, - * body: { - * "key": "value" - * } - * }) - */ - public async grpc( - request: FernProxy.GrpcProxyRequest, - requestOptions?: FernProxyClient.RequestOptions - ): Promise { - const _response = await core.fetcher({ - url: urlJoin(await core.Supplier.get(this._options.environment), "/api/fern-docs/proxy/grpc"), - method: "POST", - headers: { - "X-Fern-Language": "JavaScript", - "X-Fern-Runtime": core.RUNTIME.type, - "X-Fern-Runtime-Version": core.RUNTIME.version, - }, - contentType: "application/json", - body: request, - timeoutMs: requestOptions?.timeoutInSeconds != null ? requestOptions.timeoutInSeconds * 1000 : 60000, - maxRetries: requestOptions?.maxRetries, - abortSignal: requestOptions?.abortSignal, - }); - if (_response.ok) { - return _response.body as FernProxy.GrpcProxyResponse; - } - - if (_response.error.reason === "status-code") { - throw new errors.FernProxyError({ - statusCode: _response.error.statusCode, - body: _response.error.body, - }); - } - - switch (_response.error.reason) { - case "non-json": - throw new errors.FernProxyError({ - statusCode: _response.error.statusCode, - body: _response.error.rawBody, - }); - case "timeout": - throw new errors.FernProxyTimeoutError(); - case "unknown": - throw new errors.FernProxyError({ - message: _response.error.errorMessage, - }); - } - } - - public async file( - request: FernProxy.ProxyRequest, - requestOptions?: FernProxyClient.RequestOptions - ): Promise { - const _response = await core.fetcher({ - url: urlJoin(await core.Supplier.get(this._options.environment), "/api/fern-docs/proxy/file"), - method: "POST", - headers: { - "X-Fern-Language": "JavaScript", - "X-Fern-Runtime": core.RUNTIME.type, - "X-Fern-Runtime-Version": core.RUNTIME.version, - }, - contentType: "application/json", - body: request, - responseType: "streaming", - timeoutMs: requestOptions?.timeoutInSeconds != null ? requestOptions.timeoutInSeconds * 1000 : 60000, - maxRetries: requestOptions?.maxRetries, - abortSignal: requestOptions?.abortSignal, - }); - if (_response.ok) { - return _response.body; - } - - if (_response.error.reason === "status-code") { - throw new errors.FernProxyError({ - statusCode: _response.error.statusCode, - body: _response.error.body, - }); - } - - switch (_response.error.reason) { - case "non-json": - throw new errors.FernProxyError({ - statusCode: _response.error.statusCode, - body: _response.error.rawBody, - }); - case "timeout": - throw new errors.FernProxyTimeoutError(); - case "unknown": - throw new errors.FernProxyError({ - message: _response.error.errorMessage, - }); - } - } - - public async stream( - request: FernProxy.ProxyRequest, - requestOptions?: FernProxyClient.RequestOptions - ): Promise> { - const _response = await core.fetcher({ - url: urlJoin(await core.Supplier.get(this._options.environment), "/api/fern-docs/proxy/stream"), - method: "POST", - headers: { - "X-Fern-Language": "JavaScript", - "X-Fern-Runtime": core.RUNTIME.type, - "X-Fern-Runtime-Version": core.RUNTIME.version, - }, - contentType: "application/json", - body: request, - responseType: "streaming", - timeoutMs: requestOptions?.timeoutInSeconds != null ? requestOptions.timeoutInSeconds * 1000 : 60000, - maxRetries: requestOptions?.maxRetries, - abortSignal: requestOptions?.abortSignal, - }); - if (_response.ok) { - return new core.Stream({ - stream: _response.body, - parse: async (data) => { - return data; - }, - signal: requestOptions?.abortSignal, - eventShape: { - type: "json", - messageTerminator: "\n", - }, - }); - } - - if (_response.error.reason === "status-code") { - throw new errors.FernProxyError({ - statusCode: _response.error.statusCode, - body: _response.error.body, - }); - } - - switch (_response.error.reason) { - case "non-json": - throw new errors.FernProxyError({ - statusCode: _response.error.statusCode, - body: _response.error.rawBody, - }); - case "timeout": - throw new errors.FernProxyTimeoutError(); - case "unknown": - throw new errors.FernProxyError({ - message: _response.error.errorMessage, - }); - } - } -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/index.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/index.ts deleted file mode 100644 index eea524d655..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./types"; diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/types/FormDataJsonEntry.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/types/FormDataJsonEntry.ts deleted file mode 100644 index 89672e5de9..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/types/FormDataJsonEntry.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -export interface FormDataJsonEntry { - value?: unknown; - contentType?: string; -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/types/GrpcProxyRequest.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/types/GrpcProxyRequest.ts deleted file mode 100644 index 2b46076aab..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/types/GrpcProxyRequest.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -import * as FernProxy from "../index"; - -export interface GrpcProxyRequest { - /** The base URL to use for the call (e.g. https://acme.co). */ - baseUrl: string; - /** The gRPC endpoint name (e.g. user.v1.UserService/GetUser). */ - endpoint: string; - /** The set of encoded headers to send with the request (e.g. 'Authorization: Bearer ...'). */ - headers: Record; - /** - * The Protobuf schema that defines the API. If not specified, it's assumed the server - * supports gRPC reflection. - */ - schema?: FernProxy.ProtobufSchema; - /** The request body (represented as JSON) to include in the request, if any. */ - body?: unknown; -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/types/GrpcProxyResponse.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/types/GrpcProxyResponse.ts deleted file mode 100644 index 9973f450ce..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/types/GrpcProxyResponse.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -export interface GrpcProxyResponse { - body?: unknown; -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/types/ProtobufSchema.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/types/ProtobufSchema.ts deleted file mode 100644 index cd8c2d5ba3..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/types/ProtobufSchema.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -import * as FernProxy from "../index"; - -export type ProtobufSchema = FernProxy.ProtobufSchema.Remote; - -export declare namespace ProtobufSchema { - interface Remote extends FernProxy.RemoteProtobufSchema { - type: "remote"; - } -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/types/ProxyRequest.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/types/ProxyRequest.ts deleted file mode 100644 index 6d5d78393b..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/types/ProxyRequest.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -import * as FernProxy from "../index"; - -export interface ProxyRequest { - url: string; - method: string; - headers: Record; - body: FernProxy.RequestSerializableBody; - stream?: boolean; - streamTerminator?: string; -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/types/ProxyResponse.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/types/ProxyResponse.ts deleted file mode 100644 index dc39f65da9..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/types/ProxyResponse.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -import * as FernProxy from "../index"; - -export interface ProxyResponse { - response: FernProxy.ResponseSerializableBody; - time: number; - size?: string; -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/types/RemoteProtobufSchema.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/types/RemoteProtobufSchema.ts deleted file mode 100644 index 8cb1e22b4c..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/types/RemoteProtobufSchema.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -export interface RemoteProtobufSchema { - /** - * The remote URL containing the Protobuf schema files that define this API. - * The content is assumed to be in a .zip file. - */ - sourceUrl: string; -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/types/RequestSerializableBody.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/types/RequestSerializableBody.ts deleted file mode 100644 index ec7ab40685..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/types/RequestSerializableBody.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -import * as FernProxy from "../index"; - -export type RequestSerializableBody = - | FernProxy.RequestSerializableBody.Json - | FernProxy.RequestSerializableBody.FormData - | FernProxy.RequestSerializableBody.OctetStream; - -export declare namespace RequestSerializableBody { - interface Json { - type: "json"; - value?: unknown; - } - - interface FormData { - type: "form-data"; - value: Record; - } - - interface OctetStream extends FernProxy.SerializableFile { - type: "octet-stream"; - } -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/types/ResponseSerializableBody.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/types/ResponseSerializableBody.ts deleted file mode 100644 index 455a64269c..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/types/ResponseSerializableBody.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -import * as FernProxy from "../index"; - -export interface ResponseSerializableBody { - headers: Record; - ok: boolean; - redirected: boolean; - status: number; - statusText: string; - type: FernProxy.ResponseType; - url: string; -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/types/ResponseType.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/types/ResponseType.ts deleted file mode 100644 index 20c25fe5b5..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/types/ResponseType.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -export type ResponseType = "basic" | "cors" | "default" | "error" | "opaque" | "opaqueredirect"; - -export const ResponseType = { - Basic: "basic", - Cors: "cors", - Default: "default", - Error: "error", - Opaque: "opaque", - Opaqueredirect: "opaqueredirect", -} as const; diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/types/SerializableFile.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/types/SerializableFile.ts deleted file mode 100644 index 47ba7ea629..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/types/SerializableFile.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -import * as FernProxy from "../index"; - -export interface SerializableFile { - value: FernProxy.SerializableFileValue; -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/types/SerializableFileValue.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/types/SerializableFileValue.ts deleted file mode 100644 index 1de369c33f..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/types/SerializableFileValue.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -export interface SerializableFileValue { - name: string; - lastModified: number; - size: number; - type: string; - dataUrl: string; -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/types/SerializableFormDataEntryValue.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/types/SerializableFormDataEntryValue.ts deleted file mode 100644 index ea472ba8e3..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/types/SerializableFormDataEntryValue.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -import * as FernProxy from "../index"; - -export type SerializableFormDataEntryValue = - | FernProxy.SerializableFormDataEntryValue.File_ - | FernProxy.SerializableFormDataEntryValue.FileArray - | FernProxy.SerializableFormDataEntryValue.Json; - -export declare namespace SerializableFormDataEntryValue { - interface File_ { - type: "file"; - value?: FernProxy.SerializableFile; - } - - interface FileArray { - type: "fileArray"; - value: FernProxy.SerializableFileValue[]; - } - - interface Json extends FernProxy.FormDataJsonEntry { - type: "json"; - } -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/api/types/index.ts b/packages/ui/app/src/playground/fetch-utils/generated/api/types/index.ts deleted file mode 100644 index 39674cdfd6..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/api/types/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -export * from "./ProxyRequest"; -export * from "./ProxyResponse"; -export * from "./RequestSerializableBody"; -export * from "./ResponseSerializableBody"; -export * from "./SerializableFormDataEntryValue"; -export * from "./FormDataJsonEntry"; -export * from "./SerializableFile"; -export * from "./SerializableFileValue"; -export * from "./ResponseType"; -export * from "./GrpcProxyRequest"; -export * from "./GrpcProxyResponse"; -export * from "./ProtobufSchema"; -export * from "./RemoteProtobufSchema"; diff --git a/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/APIResponse.ts b/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/APIResponse.ts deleted file mode 100644 index 3664d09e16..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/APIResponse.ts +++ /dev/null @@ -1,12 +0,0 @@ -export type APIResponse = SuccessfulResponse | FailedResponse; - -export interface SuccessfulResponse { - ok: true; - body: T; - headers?: Record; -} - -export interface FailedResponse { - ok: false; - error: T; -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/Fetcher.ts b/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/Fetcher.ts deleted file mode 100644 index 37e527fecf..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/Fetcher.ts +++ /dev/null @@ -1,273 +0,0 @@ -import qs from "qs"; -import { RUNTIME } from "../runtime"; -import { APIResponse } from "./APIResponse"; - -export type FetchFunction = (args: Fetcher.Args) => Promise>; - -export declare namespace Fetcher { - export interface Args { - url: string; - method: string; - contentType?: string; - headers?: Record; - queryParameters?: Record; - body?: unknown; - timeoutMs?: number; - maxRetries?: number; - withCredentials?: boolean; - abortSignal?: AbortSignal; - responseType?: "json" | "blob" | "streaming" | "text"; - } - - export type Error = FailedStatusCodeError | NonJsonError | TimeoutError | UnknownError; - - export interface FailedStatusCodeError { - reason: "status-code"; - statusCode: number; - body: unknown; - } - - export interface NonJsonError { - reason: "non-json"; - statusCode: number; - rawBody: string; - } - - export interface TimeoutError { - reason: "timeout"; - } - - export interface UnknownError { - reason: "unknown"; - errorMessage: string; - } -} - -const INITIAL_RETRY_DELAY = 1; -const MAX_RETRY_DELAY = 60; -const DEFAULT_MAX_RETRIES = 2; - -async function fetcherImpl(args: Fetcher.Args): Promise> { - const headers: Record = {}; - if (args.body !== undefined && args.contentType != null) { - headers["Content-Type"] = args.contentType; - } - - if (args.headers != null) { - for (const [key, value] of Object.entries(args.headers)) { - if (value != null) { - headers[key] = value; - } - } - } - - const url = - Object.keys(args.queryParameters ?? {}).length > 0 - ? `${args.url}?${qs.stringify(args.queryParameters, { arrayFormat: "repeat" })}` - : args.url; - - let body: BodyInit | undefined = undefined; - const maybeStringifyBody = (body: any) => { - if (body instanceof Uint8Array) { - return body; - } else if (args.contentType === "application/x-www-form-urlencoded" && typeof args.body === "string") { - return args.body; - } else { - return JSON.stringify(body); - } - }; - - if (RUNTIME.type === "node") { - if (args.body instanceof (await import("formdata-node")).FormData) { - // @ts-expect-error - body = args.body; - } else { - body = maybeStringifyBody(args.body); - } - } else { - if (args.body instanceof (await import("form-data")).default) { - // @ts-expect-error - body = args.body; - } else { - body = maybeStringifyBody(args.body); - } - } - - // In Node.js environments, the SDK always uses`node-fetch`. - // If not in Node.js the SDK uses global fetch if available, - // and falls back to node-fetch. - const fetchFn = - RUNTIME.type === "node" - ? // `.default` is required due to this issue: - // https://github.com/node-fetch/node-fetch/issues/450#issuecomment-387045223 - ((await import("node-fetch")).default as any) - : typeof fetch == "function" - ? fetch - : ((await import("node-fetch")).default as any); - - const makeRequest = async (): Promise => { - const signals: AbortSignal[] = []; - - // Add timeout signal - let timeoutAbortId: NodeJS.Timeout | undefined = undefined; - if (args.timeoutMs != null) { - const { signal, abortId } = getTimeoutSignal(args.timeoutMs); - timeoutAbortId = abortId; - signals.push(signal); - } - - // Add arbitrary signal - if (args.abortSignal != null) { - signals.push(args.abortSignal); - } - - const response = await fetchFn(url, { - method: args.method, - headers, - body, - signal: anySignal(signals), - credentials: args.withCredentials ? "include" : undefined, - }); - - if (timeoutAbortId != null) { - clearTimeout(timeoutAbortId); - } - - return response; - }; - - try { - let response = await makeRequest(); - - for (let i = 0; i < (args.maxRetries ?? DEFAULT_MAX_RETRIES); ++i) { - if ( - response.status === 408 || - response.status === 409 || - response.status === 429 || - response.status >= 500 - ) { - const delay = Math.min(INITIAL_RETRY_DELAY * Math.pow(i, 2), MAX_RETRY_DELAY); - await new Promise((resolve) => setTimeout(resolve, delay)); - response = await makeRequest(); - } else { - break; - } - } - - let body: unknown; - if (response.body != null && args.responseType === "blob") { - body = await response.blob(); - } else if (response.body != null && args.responseType === "streaming") { - body = response.body; - } else if (response.body != null && args.responseType === "text") { - body = await response.text(); - } else { - const text = await response.text(); - if (text.length > 0) { - try { - body = JSON.parse(text); - } catch (err) { - return { - ok: false, - error: { - reason: "non-json", - statusCode: response.status, - rawBody: text, - }, - }; - } - } - } - - if (response.status >= 200 && response.status < 400) { - return { - ok: true, - body: body as R, - headers: response.headers, - }; - } else { - return { - ok: false, - error: { - reason: "status-code", - statusCode: response.status, - body, - }, - }; - } - } catch (error) { - if (args.abortSignal != null && args.abortSignal.aborted) { - return { - ok: false, - error: { - reason: "unknown", - errorMessage: "The user aborted a request", - }, - }; - } else if (error instanceof Error && error.name === "AbortError") { - return { - ok: false, - error: { - reason: "timeout", - }, - }; - } else if (error instanceof Error) { - return { - ok: false, - error: { - reason: "unknown", - errorMessage: error.message, - }, - }; - } - - return { - ok: false, - error: { - reason: "unknown", - errorMessage: JSON.stringify(error), - }, - }; - } -} - -const TIMEOUT = "timeout"; - -function getTimeoutSignal(timeoutMs: number): { signal: AbortSignal; abortId: NodeJS.Timeout } { - const controller = new AbortController(); - const abortId = setTimeout(() => controller.abort(TIMEOUT), timeoutMs); - return { signal: controller.signal, abortId }; -} - -/** - * Returns an abort signal that is getting aborted when - * at least one of the specified abort signals is aborted. - * - * Requires at least node.js 18. - */ -function anySignal(...args: AbortSignal[] | [AbortSignal[]]): AbortSignal { - // Allowing signals to be passed either as array - // of signals or as multiple arguments. - const signals = (args.length === 1 && Array.isArray(args[0]) ? args[0] : args); - - const controller = new AbortController(); - - for (const signal of signals) { - if (signal.aborted) { - // Exiting early if one of the signals - // is already aborted. - controller.abort((signal as any)?.reason); - break; - } - - // Listening for signals and removing the listeners - // when at least one symbol is aborted. - signal.addEventListener("abort", () => controller.abort((signal as any)?.reason), { - signal: controller.signal, - }); - } - - return controller.signal; -} - -export const fetcher: FetchFunction = fetcherImpl; diff --git a/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/Supplier.ts b/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/Supplier.ts deleted file mode 100644 index 867c931c02..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/Supplier.ts +++ /dev/null @@ -1,11 +0,0 @@ -export type Supplier = T | Promise | (() => T | Promise); - -export const Supplier = { - get: async (supplier: Supplier): Promise => { - if (typeof supplier === "function") { - return (supplier as () => T)(); - } else { - return supplier; - } - }, -}; diff --git a/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/getHeader.ts b/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/getHeader.ts deleted file mode 100644 index 50f922b0e8..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/getHeader.ts +++ /dev/null @@ -1,8 +0,0 @@ -export function getHeader(headers: Record, header: string): string | undefined { - for (const [headerKey, headerValue] of Object.entries(headers)) { - if (headerKey.toLowerCase() === header.toLowerCase()) { - return headerValue; - } - } - return undefined; -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/index.ts b/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/index.ts deleted file mode 100644 index 2d658ca48f..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/core/fetcher/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type { APIResponse } from "./APIResponse"; -export { fetcher } from "./Fetcher"; -export type { Fetcher, FetchFunction } from "./Fetcher"; -export { getHeader } from "./getHeader"; -export { Supplier } from "./Supplier"; diff --git a/packages/ui/app/src/playground/fetch-utils/generated/core/index.ts b/packages/ui/app/src/playground/fetch-utils/generated/core/index.ts deleted file mode 100644 index 8fdd24e9db..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/core/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./fetcher"; -export * from "./runtime"; -export * from "./streaming-fetcher"; diff --git a/packages/ui/app/src/playground/fetch-utils/generated/core/runtime/index.ts b/packages/ui/app/src/playground/fetch-utils/generated/core/runtime/index.ts deleted file mode 100644 index 5c76dbb133..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/core/runtime/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { RUNTIME } from "./runtime"; diff --git a/packages/ui/app/src/playground/fetch-utils/generated/core/runtime/runtime.ts b/packages/ui/app/src/playground/fetch-utils/generated/core/runtime/runtime.ts deleted file mode 100644 index f0692ab3d2..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/core/runtime/runtime.ts +++ /dev/null @@ -1,112 +0,0 @@ -interface DenoGlobal { - version: { - deno: string; - }; -} - -interface BunGlobal { - version: string; -} - -declare const Deno: DenoGlobal; -declare const Bun: BunGlobal; - -/** - * A constant that indicates whether the environment the code is running is a Web Browser. - */ -const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined"; - -/** - * A constant that indicates whether the environment the code is running is a Web Worker. - */ -const isWebWorker = - typeof self === "object" && - // @ts-ignore - typeof self?.importScripts === "function" && - (self.constructor?.name === "DedicatedWorkerGlobalScope" || - self.constructor?.name === "ServiceWorkerGlobalScope" || - self.constructor?.name === "SharedWorkerGlobalScope"); - -/** - * A constant that indicates whether the environment the code is running is Deno. - */ -const isDeno = - typeof Deno !== "undefined" && typeof Deno.version !== "undefined" && typeof Deno.version.deno !== "undefined"; - -/** - * A constant that indicates whether the environment the code is running is Bun.sh. - */ -const isBun = typeof Bun !== "undefined" && typeof Bun.version !== "undefined"; - -/** - * A constant that indicates whether the environment the code is running is Node.JS. - */ -const isNode = - typeof process !== "undefined" && - Boolean(process.version) && - Boolean(process.versions?.node) && - // Deno spoofs process.versions.node, see https://deno.land/std@0.177.0/node/process.ts?s=versions - !isDeno && - !isBun; - -/** - * A constant that indicates whether the environment the code is running is in React-Native. - * https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Core/setUpNavigator.js - */ -const isReactNative = typeof navigator !== "undefined" && navigator?.product === "ReactNative"; - -/** - * A constant that indicates which environment and version the SDK is running in. - */ -export const RUNTIME: Runtime = evaluateRuntime(); - -export interface Runtime { - type: "browser" | "web-worker" | "deno" | "bun" | "node" | "react-native" | "unknown"; - version?: string; -} - -function evaluateRuntime(): Runtime { - if (isBrowser) { - return { - type: "browser", - version: window.navigator.userAgent, - }; - } - - if (isWebWorker) { - return { - type: "web-worker", - }; - } - - if (isDeno) { - return { - type: "deno", - version: Deno.version.deno, - }; - } - - if (isBun) { - return { - type: "bun", - version: Bun.version, - }; - } - - if (isNode) { - return { - type: "node", - version: process.versions.node, - }; - } - - if (isReactNative) { - return { - type: "react-native", - }; - } - - return { - type: "unknown", - }; -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/core/streaming-fetcher/Stream.ts b/packages/ui/app/src/playground/fetch-utils/generated/core/streaming-fetcher/Stream.ts deleted file mode 100644 index 5fcb49684a..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/core/streaming-fetcher/Stream.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { Readable } from "stream"; -import { RUNTIME } from "../runtime"; - -export declare namespace Stream { - interface Args { - /** - * The HTTP response stream to read from. - */ - stream: Readable | ReadableStream; - /** - * The event shape to use for parsing the stream data. - */ - eventShape: JsonEvent | SseEvent; - /** - * An abort signal to stop the stream. - */ - signal?: AbortSignal; - } - - interface JsonEvent { - type: "json"; - messageTerminator: string; - } - - interface SseEvent { - type: "sse"; - streamTerminator?: string; - } -} - -const DATA_PREFIX = "data:"; - -export class Stream implements AsyncIterable { - private stream: Readable | ReadableStream; - private parse: (val: unknown) => Promise; - /** - * The prefix to use for each message. For example, - * for SSE, the prefix is "data: ". - */ - private prefix: string | undefined; - private messageTerminator: string; - private streamTerminator: string | undefined; - private controller: AbortController = new AbortController(); - - constructor({ stream, parse, eventShape, signal }: Stream.Args & { parse: (val: unknown) => Promise }) { - this.stream = stream; - this.parse = parse; - if (eventShape.type === "sse") { - this.prefix = DATA_PREFIX; - this.messageTerminator = "\n"; - this.streamTerminator = eventShape.streamTerminator; - } else { - this.messageTerminator = eventShape.messageTerminator; - } - signal?.addEventListener("abort", () => this.controller.abort()); - } - - private async *iterMessages(): AsyncGenerator { - this.controller.signal; - const stream = readableStreamAsyncIterable(this.stream); - let buf = ""; - let prefixSeen = false; - for await (const chunk of stream) { - buf += this.decodeChunk(chunk); - - let terminatorIndex: number; - // Parse the chunk into as many messages as possible - while ((terminatorIndex = buf.indexOf(this.messageTerminator)) >= 0) { - // Extract the line from the buffer - let line = buf.slice(0, terminatorIndex + 1); - buf = buf.slice(terminatorIndex + 1); - - // Skip empty lines - if (line.length === 0) { - continue; - } - - // Skip the chunk until the prefix is found - if (!prefixSeen && this.prefix != null) { - const prefixIndex = line.indexOf(this.prefix); - if (prefixIndex === -1) { - continue; - } - prefixSeen = true; - line = line.slice(prefixIndex + this.prefix.length); - } - - // If the stream terminator is present, return - if (this.streamTerminator != null && line.includes(this.streamTerminator)) { - return; - } - - // Otherwise, yield message from the prefix to the terminator - const message = await this.parse(JSON.parse(line)); - yield message; - prefixSeen = false; - } - } - } - - async *[Symbol.asyncIterator](): AsyncIterator { - for await (const message of this.iterMessages()) { - yield message; - } - } - - private decodeChunk(chunk: any): string { - let decoded = ""; - // Buffer is present in Node.js environment - if (RUNTIME.type === "node" && typeof chunk != "undefined") { - decoded += Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk); - } - // TextDecoder is present in Browser environment - else if (RUNTIME.type === "browser" && typeof TextDecoder !== "undefined") { - const decoder = new TextDecoder("utf8"); - decoded += decoder.decode(chunk); - } - return decoded; - } -} - -/** - * Browser polyfill for ReadableStream - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function readableStreamAsyncIterable(stream: any): AsyncIterableIterator { - if (stream[Symbol.asyncIterator]) { - return stream; - } - - const reader = stream.getReader(); - return { - async next() { - try { - const result = await reader.read(); - if (result?.done) { - reader.releaseLock(); - } // release lock when stream becomes closed - return result; - } catch (e) { - reader.releaseLock(); // release lock when stream becomes errored - throw e; - } - }, - async return() { - const cancelPromise = reader.cancel(); - reader.releaseLock(); - await cancelPromise; - return { done: true, value: undefined }; - }, - [Symbol.asyncIterator]() { - return this; - }, - }; -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/core/streaming-fetcher/index.ts b/packages/ui/app/src/playground/fetch-utils/generated/core/streaming-fetcher/index.ts deleted file mode 100644 index 7cbb4d156f..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/core/streaming-fetcher/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { Stream } from "./Stream"; diff --git a/packages/ui/app/src/playground/fetch-utils/generated/errors/FernProxyError.ts b/packages/ui/app/src/playground/fetch-utils/generated/errors/FernProxyError.ts deleted file mode 100644 index bb30593a5d..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/errors/FernProxyError.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -export class FernProxyError extends Error { - readonly statusCode?: number; - readonly body?: unknown; - - constructor({ message, statusCode, body }: { message?: string; statusCode?: number; body?: unknown }) { - super(buildMessage({ message, statusCode, body })); - Object.setPrototypeOf(this, FernProxyError.prototype); - if (statusCode != null) { - this.statusCode = statusCode; - } - - if (body !== undefined) { - this.body = body; - } - } -} - -function buildMessage({ - message, - statusCode, - body, -}: { - message: string | undefined; - statusCode: number | undefined; - body: unknown | undefined; -}): string { - let lines: string[] = []; - if (message != null) { - lines.push(message); - } - - if (statusCode != null) { - lines.push(`Status code: ${statusCode.toString()}`); - } - - if (body != null) { - lines.push(`Body: ${JSON.stringify(body, undefined, 2)}`); - } - - return lines.join("\n"); -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/errors/FernProxyTimeoutError.ts b/packages/ui/app/src/playground/fetch-utils/generated/errors/FernProxyTimeoutError.ts deleted file mode 100644 index 6fd209505b..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/errors/FernProxyTimeoutError.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -export class FernProxyTimeoutError extends Error { - constructor() { - super("Timeout"); - Object.setPrototypeOf(this, FernProxyTimeoutError.prototype); - } -} diff --git a/packages/ui/app/src/playground/fetch-utils/generated/errors/index.ts b/packages/ui/app/src/playground/fetch-utils/generated/errors/index.ts deleted file mode 100644 index 1463896605..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/errors/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { FernProxyError } from "./FernProxyError"; -export { FernProxyTimeoutError } from "./FernProxyTimeoutError"; diff --git a/packages/ui/app/src/playground/fetch-utils/generated/index.ts b/packages/ui/app/src/playground/fetch-utils/generated/index.ts deleted file mode 100644 index 77f9549bc2..0000000000 --- a/packages/ui/app/src/playground/fetch-utils/generated/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * as FernProxy from "./api"; -export { FernProxyClient } from "./Client"; -export { FernProxyError, FernProxyTimeoutError } from "./errors"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5fbbf6ac0f..f5aef13650 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1055,6 +1055,9 @@ importers: '@fern-api/template-resolver': specifier: workspace:* version: link:../../template-resolver + '@fern-fern/proxy-sdk': + specifier: 0.0.21 + version: 0.0.21 '@fern-ui/chatbot': specifier: workspace:* version: link:../chatbot @@ -4057,6 +4060,9 @@ 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.21': + resolution: {integrity: sha512-BawSADGCkPI9BAmYlGz+HS9mbbf11UAHfh2ZmpVByY1WRIIJ2H/pWE9/gPzuyEqV44KnR4E4iwuSXef9gQH94A==} + '@fern-fern/vercel@0.0.4655': resolution: {integrity: sha512-twz/gFcQo9Gk38byYLFsJDbHnvvBsOHfofdef15vzIeFCIr1yPsTWYmNoPllBeRLc4RjMel6T06afFZJMc8JSg==} @@ -18823,6 +18829,17 @@ snapshots: transitivePeerDependencies: - encoding + '@fern-fern/proxy-sdk@0.0.21': + 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/vercel@0.0.4655': dependencies: form-data: 4.0.0