From c225719d70822d529bfafeacbaaa02b158ead46f Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Sun, 12 Feb 2023 14:28:57 +0800 Subject: [PATCH] refactor(core,console): update well-known for endpoints --- packages/console/src/App.tsx | 9 ++++---- packages/console/src/consts/index.ts | 2 ++ packages/console/src/consts/tenants.ts | 4 ++++ .../containers/AppEndpointsProvider/index.tsx | 14 ++++++----- packages/console/src/hooks/use-api.ts | 23 +++++++++++-------- .../console/src/hooks/use-user-preferences.ts | 6 ++--- .../Applications/components/Guide/index.tsx | 6 +++-- packages/console/src/pages/GetStarted/hook.ts | 17 +++++++------- .../components/Preview/index.tsx | 8 +++---- packages/core/src/routes/well-known.ts | 19 +++++++-------- .../core/src/tenants/TenantPoolContext.ts | 5 ---- packages/ui/src/App.tsx | 1 - 12 files changed, 62 insertions(+), 52 deletions(-) create mode 100644 packages/console/src/consts/tenants.ts delete mode 100644 packages/core/src/tenants/TenantPoolContext.ts diff --git a/packages/console/src/App.tsx b/packages/console/src/App.tsx index b6243613c..a4244203b 100644 --- a/packages/console/src/App.tsx +++ b/packages/console/src/App.tsx @@ -45,7 +45,8 @@ import { RoleDetailsTabs, SignInExperiencePage, UserDetailsTabs, -} from './consts/page-tabs'; + adminTenantEndpoint, +} from './consts'; import AppContent from './containers/AppContent'; import AppEndpointsProvider, { AppEndpointsContext } from './containers/AppEndpointsProvider'; import ApiResourcePermissions from './pages/ApiResourceDetails/ApiResourcePermissions'; @@ -63,9 +64,9 @@ void initI18n(); const Main = () => { const swrOptions = useSwrOptions(); - const { app, console } = useContext(AppEndpointsContext); + const { userEndpoint } = useContext(AppEndpointsContext); - if (!app || !console) { + if (!userEndpoint) { return ; } @@ -162,7 +163,7 @@ const App = () => ( { useEffect(() => { const getEndpoint = async () => { - const { app, console } = await ky - .get(new URL('api/.well-known/endpoints', window.location.origin)) - .json<{ app: string; console: string }>(); - setEndpoints({ app: new URL(app), console: new URL(console) }); + const { user } = await ky + .get(new URL(`api/.well-known/endpoints/${userTenantId}`, adminTenantEndpoint)) + .json<{ user: string }>(); + setEndpoints({ userEndpoint: new URL(user) }); }; void getEndpoint(); diff --git a/packages/console/src/hooks/use-api.ts b/packages/console/src/hooks/use-api.ts index 225bdf806..d87c6361e 100644 --- a/packages/console/src/hooks/use-api.ts +++ b/packages/console/src/hooks/use-api.ts @@ -6,7 +6,6 @@ import { toast } from 'react-hot-toast'; import { useTranslation } from 'react-i18next'; import { managementApi, requestTimeout } from '@/consts'; -import type { AppEndpointKey } from '@/containers/AppEndpointsProvider'; import { AppEndpointsContext } from '@/containers/AppEndpointsProvider'; export class RequestError extends Error { @@ -20,18 +19,17 @@ export class RequestError extends Error { } } -type Props = { - endpointKey?: AppEndpointKey; +type StaticApiProps = { + prefixUrl: string; hideErrorToast?: boolean; resourceIndicator?: string; }; -const useApi = ({ +export const useStaticApi = ({ + prefixUrl, hideErrorToast, - endpointKey = 'app', resourceIndicator = managementApi.indicator, -}: Props = {}) => { - const endpoints = useContext(AppEndpointsContext); +}: StaticApiProps) => { const { isAuthenticated, getAccessToken } = useLogto(); const { t, i18n } = useTranslation(undefined, { keyPrefix: 'admin_console' }); @@ -52,7 +50,7 @@ const useApi = ({ const api = useMemo( () => ky.create({ - prefixUrl: endpoints[endpointKey], + prefixUrl, timeout: requestTimeout, hooks: { beforeError: hideErrorToast @@ -76,8 +74,7 @@ const useApi = ({ }, }), [ - endpoints, - endpointKey, + prefixUrl, hideErrorToast, toastError, isAuthenticated, @@ -90,4 +87,10 @@ const useApi = ({ return api; }; +const useApi = (props: Omit = {}) => { + const { userEndpoint } = useContext(AppEndpointsContext); + + return useStaticApi({ ...props, prefixUrl: userEndpoint?.toString() ?? '' }); +}; + export default useApi; diff --git a/packages/console/src/hooks/use-user-preferences.ts b/packages/console/src/hooks/use-user-preferences.ts index 134576766..3d97b9589 100644 --- a/packages/console/src/hooks/use-user-preferences.ts +++ b/packages/console/src/hooks/use-user-preferences.ts @@ -9,10 +9,10 @@ import type { BareFetcher } from 'swr'; import useSWR from 'swr'; import { z } from 'zod'; -import { meApi, themeStorageKey } from '@/consts'; +import { meApi, themeStorageKey, adminTenantEndpoint } from '@/consts'; import type { RequestError } from './use-api'; -import useApi from './use-api'; +import { useStaticApi } from './use-api'; import useLogtoUserId from './use-logto-user-id'; const userPreferencesGuard = z.object({ @@ -36,7 +36,7 @@ const useUserPreferences = () => { const { isAuthenticated, error: authError } = useLogto(); const userId = useLogtoUserId(); const shouldFetch = isAuthenticated && !authError && userId; - const api = useApi({ endpointKey: 'console', resourceIndicator: meApi.indicator }); + const api = useStaticApi({ prefixUrl: adminTenantEndpoint, resourceIndicator: meApi.indicator }); const fetcher = useCallback( async (resource, init) => { const response = await api.get(resource, init); diff --git a/packages/console/src/pages/Applications/components/Guide/index.tsx b/packages/console/src/pages/Applications/components/Guide/index.tsx index fd556014c..97f46389d 100644 --- a/packages/console/src/pages/Applications/components/Guide/index.tsx +++ b/packages/console/src/pages/Applications/components/Guide/index.tsx @@ -4,10 +4,11 @@ import type { Optional } from '@silverhand/essentials'; import i18next from 'i18next'; import type { MDXProps } from 'mdx/types'; import type { LazyExoticComponent } from 'react'; -import { cloneElement, lazy, Suspense, useEffect, useState } from 'react'; +import { useContext, cloneElement, lazy, Suspense, useEffect, useState } from 'react'; import CodeEditor from '@/components/CodeEditor'; import TextLink from '@/components/TextLink'; +import { AppEndpointsContext } from '@/containers/AppEndpointsProvider'; import DetailsSummary from '@/mdx-components/DetailsSummary'; import type { SupportedSdk } from '@/types/applications'; import { applicationTypeAndSdkTypeMappings } from '@/types/applications'; @@ -53,6 +54,7 @@ const Guide = ({ app, isCompact, onClose }: Props) => { const sdks = applicationTypeAndSdkTypeMappings[appType]; const [selectedSdk, setSelectedSdk] = useState>(sdks[0]); const [activeStepIndex, setActiveStepIndex] = useState(-1); + const { userEndpoint } = useContext(AppEndpointsContext); // Directly close guide if no SDK available useEffect(() => { @@ -110,7 +112,7 @@ const Guide = ({ app, isCompact, onClose }: Props) => { { const { getDocumentationUrl } = useDocumentationUrl(); const { configs, updateConfigs } = useConfigs(); - const { app } = useContext(AppEndpointsContext); + const { userEndpoint } = useContext(AppEndpointsContext); const theme = useTheme(); const isLightMode = theme === AppearanceMode.LightMode; const { data: demoApp, error } = useSWR( @@ -69,7 +69,7 @@ const useGetStartedMetadata = () => { isHidden: hideDemo, onClick: async () => { void updateConfigs({ demoChecked: true }); - window.open(new URL('/demo-app', app), '_blank'); + window.open(new URL('/demo-app', userEndpoint), '_blank'); }, }, { @@ -135,17 +135,18 @@ const useGetStartedMetadata = () => { return metadataItems.filter(({ isHidden }) => !isHidden); }, [ - getDocumentationUrl, - hideDemo, isLightMode, - navigate, - configs?.applicationCreated, configs?.demoChecked, - configs?.furtherReadingsChecked, - configs?.passwordlessConfigured, + configs?.applicationCreated, configs?.signInExperienceCustomized, + configs?.passwordlessConfigured, configs?.socialSignInConfigured, + configs?.furtherReadingsChecked, + hideDemo, updateConfigs, + userEndpoint, + navigate, + getDocumentationUrl, ]); return { diff --git a/packages/console/src/pages/SignInExperience/components/Preview/index.tsx b/packages/console/src/pages/SignInExperience/components/Preview/index.tsx index 498931e9f..7e8ed74de 100644 --- a/packages/console/src/pages/SignInExperience/components/Preview/index.tsx +++ b/packages/console/src/pages/SignInExperience/components/Preview/index.tsx @@ -31,7 +31,7 @@ const Preview = ({ signInExperience, className }: Props) => { const { data: allConnectors } = useSWR('api/connectors'); const previewRef = useRef(null); const { customPhrases, languages } = useUiLanguages(); - const { app: appEndpoint } = useContext(AppEndpointsContext); + const { userEndpoint } = useContext(AppEndpointsContext); const modeOptions = useMemo(() => { const light = { value: AppearanceMode.LightMode, title: t('sign_in_exp.preview.light') }; @@ -120,9 +120,9 @@ const Preview = ({ signInExperience, className }: Props) => { previewRef.current?.contentWindow?.postMessage( { sender: 'ac_preview', config }, - appEndpoint?.origin ?? '' + userEndpoint?.origin ?? '' ); - }, [appEndpoint?.origin, config, customPhrases]); + }, [userEndpoint?.origin, config, customPhrases]); useEffect(() => { postPreviewMessage(); @@ -210,7 +210,7 @@ const Preview = ({ signInExperience, className }: Props) => { ref={previewRef} // Allow all sandbox rules sandbox={undefined} - src={new URL('/sign-in?preview=true', appEndpoint).toString()} + src={new URL('/sign-in?preview=true', userEndpoint).toString()} tabIndex={-1} title={t('sign_in_exp.preview.title')} /> diff --git a/packages/core/src/routes/well-known.ts b/packages/core/src/routes/well-known.ts index 651022377..29157640c 100644 --- a/packages/core/src/routes/well-known.ts +++ b/packages/core/src/routes/well-known.ts @@ -1,6 +1,6 @@ import type { ConnectorMetadata } from '@logto/connector-kit'; import { ConnectorType } from '@logto/connector-kit'; -import { adminConsoleApplicationId } from '@logto/schemas'; +import { adminConsoleApplicationId, adminTenantId } from '@logto/schemas'; import etag from 'etag'; import { EnvSet } from '#src/env-set/index.js'; @@ -9,21 +9,22 @@ import { getApplicationIdFromInteraction } from '#src/libraries/session.js'; import type { AnonymousRouter, RouterInitArgs } from './types.js'; export default function wellKnownRoutes( - ...[router, { provider, libraries }]: RouterInitArgs + ...[router, { provider, libraries, id }]: RouterInitArgs ) { const { signInExperiences: { getSignInExperienceForApplication }, connectors: { getLogtoConnectors }, } = libraries; - router.get('/.well-known/endpoints', async (ctx, next) => { - ctx.body = { - console: EnvSet.values.adminUrlSet.endpoint, - app: EnvSet.values.urlSet.endpoint, - }; + if (id === adminTenantId) { + router.get('/.well-known/endpoints/:tenantId', async (ctx, next) => { + ctx.body = { + user: EnvSet.values.urlSet.endpoint.replace('*', ctx.params.tenantId ?? '*'), + }; - return next(); - }); + return next(); + }); + } router.get( '/.well-known/sign-in-exp', diff --git a/packages/core/src/tenants/TenantPoolContext.ts b/packages/core/src/tenants/TenantPoolContext.ts deleted file mode 100644 index 399abdb7b..000000000 --- a/packages/core/src/tenants/TenantPoolContext.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type TenantContext from './TenantContext.js'; - -export default abstract class TenantPoolContext { - public abstract get(tenantId: string): Promise; -} diff --git a/packages/ui/src/App.tsx b/packages/ui/src/App.tsx index f54db8e1b..7901a432f 100644 --- a/packages/ui/src/App.tsx +++ b/packages/ui/src/App.tsx @@ -63,7 +63,6 @@ const App = () => { }> - } /> } />