Skip to content

Commit

Permalink
fix circular deps
Browse files Browse the repository at this point in the history
  • Loading branch information
abvthecity committed Dec 19, 2024
1 parent 7d29ebf commit b6d31d5
Show file tree
Hide file tree
Showing 19 changed files with 134 additions and 141 deletions.
3 changes: 1 addition & 2 deletions packages/ui/app/src/analytics/posthog.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import posthog, { type PostHog } from "posthog-js";
import { ReactNode, useEffect } from "react";
import { useFernUser } from "../atoms";
import { useApiRoute } from "../hooks/useApiRoute";
import { useApiRoute, useFernUser } from "../atoms";
import { useRouteChangeComplete } from "../hooks/useRouteChanged";
import { useSafeListenTrackEvents } from "./track";

Expand Down
2 changes: 1 addition & 1 deletion packages/ui/app/src/atoms/launchdarkly.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { atom, useAtomValue, useSetAtom } from "jotai";
import * as LDClient from "launchdarkly-js-client-sdk";
import { useCallback, useEffect, useState } from "react";
import { useApiRouteSWR } from "../hooks/useApiRouteSWR";
import { useApiRouteSWR } from "./navigation";

// NOTE do not export this file in any index.ts file so that it can be properly tree-shaken
// otherwise we risk importing launchdarkly-js-client-sdk in all of our bundles
Expand Down
115 changes: 112 additions & 3 deletions packages/ui/app/src/atoms/navigation.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import type { ApiDefinition } from "@fern-api/fdr-sdk/api-definition";
import * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import { withDefaultProtocol } from "@fern-api/ui-core-utils";
import { visitDiscriminatedUnion, withDefaultProtocol } from "@fern-api/ui-core-utils";
import type { SidebarTab, VersionSwitcherInfo } from "@fern-ui/fdr-utils";
import { useEventCallback } from "@fern-ui/react-commons";
import { isEqual } from "es-toolkit/predicate";
import { Atom, atom, useAtomValue } from "jotai";
import { atom, useAtomValue, type Atom, type Getter } from "jotai";
import { atomWithLocation } from "jotai-location";
import { selectAtom, useAtomCallback } from "jotai/utils";
import { Router } from "next/router";
import { useCallback } from "react";
import useSWR, { preload, type Fetcher, type SWRConfiguration, type SWRResponse } from "swr";
import useSWRImmutable from "swr/immutable";
import urlJoin from "url-join";
import { useCallbackOne } from "use-memo-one";
import { z } from "zod";
import type { DocsContent } from "../resolver/DocsContent";
import { withSkewProtection } from "../util/withSkewProtection";
import { WRITE_API_DEFINITION_ATOM } from "./apis";
import { DOCS_ATOM } from "./docs";
import { useAtomEffect } from "./hooks";
import { NavbarLink } from "./types";
import type { NavbarLink } from "./types";

export const DOMAIN_ATOM = atom<string>((get) => get(DOCS_ATOM).baseUrl.domain);
DOMAIN_ATOM.debugLabel = "DOMAIN_ATOM";
Expand Down Expand Up @@ -276,3 +281,107 @@ export function useHref(slug: FernNavigation.Slug | undefined, anchor?: string):
export function selectHref(get: <T>(atom: Atom<T>) => T, slug: FernNavigation.Slug): string {
return getToHref(get(TRAILING_SLASH_ATOM))(slug);
}

export type FernDocsApiRoute = `/api/fern-docs/${string}`;

// see useHref.ts for a similar pattern
export function getApiRouteSupplier({
includeTrailingSlash,
basepath,
}: {
includeTrailingSlash?: boolean;
basepath?: string;
}): (route: FernDocsApiRoute) => string {
return (route) => {
// note: if the first argument of urjoin is "", it will strip the leading slash. `|| "/"` ensures "" -> "/"
if (includeTrailingSlash) {
return urlJoin(basepath || "/", route, "/");
} else {
return urlJoin(basepath || "/", route);
}
};
}

export function useApiRoute(
route: FernDocsApiRoute,
options?: {
includeTrailingSlash?: boolean;
basepath?: string;
},
): string {
const basepath = useAtomValue(BASEPATH_ATOM);
const includeTrailingSlash = useAtomValue(TRAILING_SLASH_ATOM);
return getApiRouteSupplier({ includeTrailingSlash, basepath, ...options })(route);
}

export function selectApiRoute(
get: Getter,
route: FernDocsApiRoute,
options?: {
includeTrailingSlash?: boolean;
basepath?: string;
},
): string {
const basepath = get(BASEPATH_ATOM);
const includeTrailingSlash = get(TRAILING_SLASH_ATOM);
return getApiRouteSupplier({ includeTrailingSlash, basepath, ...options })(route);
}

interface Options<T> extends SWRConfiguration<T, Error, Fetcher<T>> {
disabled?: boolean;
request?: RequestInit & { headers?: Record<string, string> };
validate?: z.ZodType<T>;
}

function createFetcher<T>(
init?: RequestInit & { headers?: Record<string, string> },
validate?: z.ZodType<T>,
): (url: string) => Promise<T> {
return async (url: string): Promise<T> => {
const request = { ...init, headers: withSkewProtection(init?.headers) };
const r = await fetch(url, request);
const data = await r.json();
if (validate) {
return validate.parse(data);
}
return data;
};
}

export function useApiRouteSWR<T>(
route: FernDocsApiRoute,
{ disabled, request, validate, ...options }: Options<T> = {},
): SWRResponse<T> {
const key = useApiRoute(route);
return useSWR(disabled ? null : key, createFetcher(request, validate), options);
}

export function useApiRouteSWRImmutable<T>(
route: FernDocsApiRoute,
{ disabled, request, validate, ...options }: Options<T> = {},
): SWRResponse<T> {
const key = useApiRoute(route);
return useSWRImmutable(disabled ? null : key, createFetcher(request, validate), options);
}

const fetcher = (url: string): Promise<ApiDefinition> => fetch(url).then((res) => res.json());

export function usePreloadApiLeaf(): (node: FernNavigation.NavigationNodeApiLeaf) => Promise<ApiDefinition> {
return useAtomCallback(
useCallbackOne(async (get, set, node: FernNavigation.NavigationNodeApiLeaf) => {
const route = selectApiRoute(
get,
`/api/fern-docs/api-definition/${encodeURIComponent(node.apiDefinitionId)}/${visitDiscriminatedUnion(
node,
)._visit({
endpoint: (node) => `endpoint/${encodeURIComponent(node.endpointId)}`,
webSocket: (node) => `websocket/${encodeURIComponent(node.webSocketId)}`,
webhook: (node) => `webhook/${encodeURIComponent(node.webhookId)}`,
})}`,
);
const apiDefinition = await preload(route, fetcher);
set(WRITE_API_DEFINITION_ATOM, apiDefinition);
return apiDefinition;
}, []),
);
}
20 changes: 9 additions & 11 deletions packages/ui/app/src/atoms/playground.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
import {
EndpointContext,
WebSocketContext,
createEndpointContext,
createWebSocketContext,
type EndpointContext,
type WebSocketContext,
} from "@fern-api/fdr-sdk/api-definition";
import * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import { useEventCallback } from "@fern-ui/react-commons";
import { WritableAtom, atom, useAtom, useAtomValue, useSetAtom } from "jotai";
import { atom, useAtom, useAtomValue, useSetAtom, type WritableAtom } from "jotai";
import { RESET, atomFamily, atomWithStorage, useAtomCallback } from "jotai/utils";
import { Dispatch, SetStateAction, useEffect } from "react";
import { useEffect, type Dispatch, type SetStateAction } from "react";
import { useCallbackOne } from "use-memo-one";
import { selectHref } from "../atoms";
import { usePreloadApiLeaf } from "../playground/hooks/usePreloadApiLeaf";
import {
PLAYGROUND_AUTH_STATE_BASIC_AUTH_INITIAL,
PLAYGROUND_AUTH_STATE_BEARER_TOKEN_INITIAL,
PLAYGROUND_AUTH_STATE_HEADER_INITIAL,
PLAYGROUND_AUTH_STATE_OAUTH_INITIAL,
PlaygroundAuthStateBasicAuth,
PlaygroundAuthStateBearerToken,
PlaygroundAuthStateHeader,
PlaygroundAuthStateOAuth,
PlaygroundAuthStateSchema,
type PlaygroundAuthState,
type PlaygroundAuthStateBasicAuth,
type PlaygroundAuthStateBearerToken,
type PlaygroundAuthStateHeader,
type PlaygroundAuthStateOAuth,
type PlaygroundEndpointRequestFormState,
type PlaygroundRequestFormState,
type PlaygroundWebSocketRequestFormState,
Expand All @@ -36,7 +34,7 @@ import { FERN_USER_ATOM } from "./auth";
import { FEATURE_FLAGS_ATOM } from "./flags";
import { useAtomEffect } from "./hooks";
import { HEADER_HEIGHT_ATOM } from "./layout";
import { CURRENT_NODE_ATOM, LOCATION_ATOM, NAVIGATION_NODES_ATOM } from "./navigation";
import { CURRENT_NODE_ATOM, LOCATION_ATOM, NAVIGATION_NODES_ATOM, selectHref, usePreloadApiLeaf } from "./navigation";
import { atomWithStorageValidation } from "./utils/atomWithStorageValidation";
import { IS_MOBILE_SCREEN_ATOM } from "./viewport";

Expand Down
2 changes: 1 addition & 1 deletion packages/ui/app/src/components/LinkPreload.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Head from "next/head";
import { ReactElement } from "react";
import { useApiRoute } from "../atoms";
import { useIsLocalPreview } from "../contexts/local-preview";
import { useApiRoute } from "../hooks/useApiRoute";

export function LinkPreload({ href }: { href: string }): ReactElement {
return (
Expand Down
34 changes: 0 additions & 34 deletions packages/ui/app/src/hooks/useApiRoute.ts

This file was deleted.

42 changes: 0 additions & 42 deletions packages/ui/app/src/hooks/useApiRouteSWR.ts

This file was deleted.

3 changes: 1 addition & 2 deletions packages/ui/app/src/hooks/useStandardProxyEnvironment.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { withDefaultProtocol } from "@fern-api/ui-core-utils";
import { once } from "es-toolkit/function";
import { useBasePath, useFeatureFlags } from "../atoms";
import { useApiRoute } from "./useApiRoute";
import { useApiRoute, useBasePath, useFeatureFlags } from "../atoms";

const APP_BUILDWITHFERN_COM = "app.buildwithfern.com";

Expand Down
1 change: 0 additions & 1 deletion packages/ui/app/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ export type { DocsProps, NavbarLink } from "./atoms";
export * from "./docs/DocsPage";
export * from "./docs/NextApp";
export { NotFoundPage } from "./docs/NotFoundPage";
export { getApiRouteSupplier } from "./hooks/useApiRoute";
export * from "./mdx/types";
export { Stream } from "./playground/Stream";
export { ProxyRequestSchema } from "./playground/types";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { useAtomValue, useSetAtom } from "jotai";
import { useSearchParams } from "next/navigation";
import { ReactElement, useEffect } from "react";
import urlJoin from "url-join";
import { PLAYGROUND_AUTH_STATE_ATOM, PLAYGROUND_AUTH_STATE_BEARER_TOKEN_ATOM } from "../../atoms";
import { useApiRoute } from "../../hooks/useApiRoute";
import { PLAYGROUND_AUTH_STATE_ATOM, PLAYGROUND_AUTH_STATE_BEARER_TOKEN_ATOM, useApiRoute } from "../../atoms";
import { Callout } from "../../mdx/components/callout";
import { PlaygroundAuthorizationForm } from "./PlaygroundAuthorizationForm";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import {
PLAYGROUND_AUTH_STATE_ATOM,
PLAYGROUND_AUTH_STATE_OAUTH_ATOM,
store,
useApiRoute,
useBasePath,
useFeatureFlags,
usePlaygroundEndpointFormState,
} from "../../atoms";
import { useApiRoute } from "../../hooks/useApiRoute";
import { usePlaygroundSettings } from "../../hooks/usePlaygroundSettings";
import { getAppBuildwithfernCom } from "../../hooks/useStandardProxyEnvironment";
import { executeGrpc } from "../fetch-utils/executeGrpc";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import clsx from "clsx";
import { atom, useAtomValue } from "jotai";
import { ReactElement, forwardRef } from "react";
import { useMemoOne } from "use-memo-one";
import { getApiDefinitionAtom, useOpenPlayground } from "../../atoms";
import { getApiDefinitionAtom, useOpenPlayground, usePreloadApiLeaf } from "../../atoms";
import { Markdown } from "../../mdx/Markdown";
import { usePreloadApiLeaf } from "../hooks/usePreloadApiLeaf";

interface PlaygroundEndpointSelectorLeafNodeProps {
node: FernNavigation.EndpointNode | FernNavigation.WebSocketNode;
Expand Down
1 change: 0 additions & 1 deletion packages/ui/app/src/playground/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export { useEndpointContext } from "./useEndpointContext";
export { useOAuthEndpointContext } from "./useOAuthEndpointContext";
export { usePreloadApiLeaf } from "./usePreloadApiLeaf";
export { useWebSocketContext } from "./useWebSocketContext";
export { useWebsocketMessages } from "./useWebsocketMessages";
3 changes: 1 addition & 2 deletions packages/ui/app/src/playground/hooks/useEndpointContext.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { createEndpointContext, type ApiDefinition, type EndpointContext } from "@fern-api/fdr-sdk/api-definition";
import type * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import { useMemo } from "react";
import { useWriteApiDefinitionAtom } from "../../atoms";
import { useApiRouteSWRImmutable } from "../../hooks/useApiRouteSWR";
import { useApiRouteSWRImmutable, useWriteApiDefinitionAtom } from "../../atoms";

interface LoadableEndpointContext {
context: EndpointContext | undefined;
Expand Down
30 changes: 0 additions & 30 deletions packages/ui/app/src/playground/hooks/usePreloadApiLeaf.ts

This file was deleted.

3 changes: 1 addition & 2 deletions packages/ui/app/src/playground/hooks/useWebSocketContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import { createWebSocketContext } from "@fern-api/fdr-sdk/api-definition";
import type * as FernNavigation from "@fern-api/fdr-sdk/navigation";
import { useSetAtom } from "jotai";
import { useEffect, useMemo } from "react";
import { WRITE_API_DEFINITION_ATOM } from "../../atoms";
import { useApiRouteSWRImmutable } from "../../hooks/useApiRouteSWR";
import { WRITE_API_DEFINITION_ATOM, useApiRouteSWRImmutable } from "../../atoms";

interface LoadableWebSocketContext {
context: WebSocketContext | undefined;
Expand Down
Loading

0 comments on commit b6d31d5

Please sign in to comment.