0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-02-17 22:04:19 -05:00

refactor(core,ui): fix cache issue when sign in to live preview (#3495)

This commit is contained in:
Gao Sun 2023-03-19 11:39:16 +08:00 committed by GitHub
parent c17fb35298
commit 5a2f3c3461
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 65 additions and 18 deletions

View file

@ -9,7 +9,6 @@ import i18next from 'i18next';
import Provider, { errors, ResourceServer } from 'oidc-provider';
import snakecaseKeys from 'snakecase-keys';
import { wellKnownCache } from '#src/caches/well-known.js';
import type { EnvSet } from '#src/env-set/index.js';
import { addOidcEventListeners } from '#src/event-listeners/index.js';
import koaAuditLog from '#src/middleware/koa-audit-log.js';
@ -151,16 +150,11 @@ export default function initOidc(
const appendParameters = (path: string) => {
// `notification` is for showing a text banner on the homepage
return isDemoApp ? path + `?notification=demo_app.notification` : path;
return isDemoApp ? path + `?notification=demo_app.notification&no_cache` : path;
};
switch (interaction.prompt.name) {
case 'login': {
// Always fetch the latest sign-in experience config for demo app (live preview)
if (isDemoApp) {
wellKnownCache.invalidate(tenantId, ['sie', 'sie-full']);
}
const isSignUp =
ctx.oidc.params?.[OIDCExtraParametersKey.InteractionMode] === InteractionMode.signUp;

View file

@ -16,7 +16,7 @@ export default function koaInteractionSie<StateT, ContextT, ResponseT>(
tenantId: string
): MiddlewareType<StateT, WithInteractionSieContext<ContextT>, ResponseT> {
return async (ctx, next) => {
if (noCache(ctx.headers)) {
if (noCache(ctx.request)) {
wellKnownCache.invalidate(tenantId, ['sie']);
}

View file

@ -39,8 +39,9 @@ export default function wellKnownRoutes<T extends AnonymousRouter>(
'/.well-known/sign-in-exp',
koaGuard({ response: guardFullSignInExperience, status: 200 }),
async (ctx, next) => {
if (noCache(ctx.headers)) {
if (noCache(ctx.request)) {
wellKnownCache.invalidate(tenantId, ['sie', 'sie-full']);
console.log('invalidated');
}
ctx.body = await getFullSignInExperience();
@ -59,7 +60,7 @@ export default function wellKnownRoutes<T extends AnonymousRouter>(
status: 200,
}),
async (ctx, next) => {
if (noCache(ctx.headers)) {
if (noCache(ctx.request)) {
wellKnownCache.invalidate(tenantId, ['sie', 'phrases-lng-tags', 'phrases']);
}

View file

@ -1,5 +1,8 @@
import type { IncomingHttpHeaders } from 'http';
import type { Request } from 'koa';
export const noCache = (headers: IncomingHttpHeaders): boolean =>
headers['cache-control']?.split(',').some((value) => value.trim().toLowerCase() === 'no-cache') ??
false;
export const noCache = (request: Request): boolean =>
Boolean(
request.headers['cache-control']
?.split(',')
.some((value) => ['no-cache', 'no-store'].includes(value.trim().toLowerCase()))
) || request.URL.searchParams.get('no_cache') !== null;

View file

@ -23,10 +23,13 @@ import SocialLinkAccount from './pages/SocialLinkAccount';
import SocialSignIn from './pages/SocialSignInCallback';
import Springboard from './pages/Springboard';
import VerificationCode from './pages/VerificationCode';
import { handleSearchParametersData } from './utils/search-parameters';
import { getSignInExperienceSettings, setFavIcon } from './utils/sign-in-experience';
import './scss/normalized.scss';
handleSearchParametersData();
const App = () => {
const { context, Provider } = usePageContext();
const { experienceSettings, setLoading, setExperienceSettings } = context;

View file

@ -3,13 +3,29 @@
* The API will be deprecated in the future once SSR is implemented.
*/
import { conditionalString } from '@silverhand/essentials';
import type { Nullable, Optional } from '@silverhand/essentials';
import { conditional } from '@silverhand/essentials';
import ky from 'ky';
import type { SignInExperienceResponse } from '@/types';
import { searchKeys } from '@/utils/search-parameters';
const buildSearchParameters = (record: Record<string, Nullable<Optional<string>>>) => {
const entries = Object.entries(record).filter((entry): entry is [string, string] =>
Boolean(entry[0] && entry[1])
);
return conditional(entries.length > 0 && entries);
};
export const getSignInExperience = async <T extends SignInExperienceResponse>(): Promise<T> => {
return ky.get('/api/.well-known/sign-in-exp').json<T>();
return ky
.get('/api/.well-known/sign-in-exp', {
searchParams: buildSearchParameters({
[searchKeys.noCache]: sessionStorage.getItem(searchKeys.noCache),
}),
})
.json<T>();
};
export const getPhrases = async ({
@ -31,4 +47,9 @@ export const getPhrases = async ({
],
},
})
.get(`/api/.well-known/phrases${conditionalString(language && `?lng=${language}`)}`);
.get('/api/.well-known/phrases', {
searchParams: buildSearchParameters({
[searchKeys.noCache]: sessionStorage.getItem(searchKeys.noCache),
lng: language,
}),
});

View file

@ -5,6 +5,7 @@ import { Trans, useTranslation } from 'react-i18next';
import { AppNotification as Notification } from '@/components/Notification';
import usePlatform from '@/hooks/use-platform';
import { searchKeys } from '@/utils/search-parameters';
import * as styles from './index.module.scss';
@ -26,7 +27,7 @@ const AppNotification = () => {
}, []);
useEffect(() => {
setNotification(new URLSearchParams(window.location.search).get('notification'));
setNotification(sessionStorage.getItem(searchKeys.notification));
}, []);
useEffect(() => {

View file

@ -0,0 +1,24 @@
export const searchKeys = Object.freeze({
notification: 'notification',
noCache: 'no_cache',
});
export const handleSearchParametersData = () => {
const { search } = window.location;
if (!search) {
return;
}
const parameters = new URLSearchParams(search);
const notification = parameters.get(searchKeys.notification);
if (notification) {
sessionStorage.setItem(searchKeys.notification, notification);
}
if (parameters.get(searchKeys.noCache) !== null) {
sessionStorage.setItem(searchKeys.noCache, 'true');
}
};