From f4525f00dedd36778544b17325e12cfa34db48a2 Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Tue, 25 Jun 2024 13:34:37 +0800 Subject: [PATCH] feat: demo app dev panel --- .changeset/few-moose-sniff.md | 5 + packages/console/package.json | 2 +- packages/demo-app/package.json | 3 +- packages/demo-app/src/App.module.scss | 129 ++++++++---- packages/demo-app/src/App.tsx | 72 ++++++- packages/demo-app/src/DevPanel.tsx | 114 +++++++++++ packages/demo-app/src/utils.ts | 70 +++++++ .../src/locales/de/translation/demo-app.ts | 1 - .../src/locales/en/translation/demo-app.ts | 2 +- .../src/locales/es/translation/demo-app.ts | 1 - .../src/locales/fr/translation/demo-app.ts | 1 - .../src/locales/it/translation/demo-app.ts | 1 - .../src/locales/ja/translation/demo-app.ts | 1 - .../src/locales/ko/translation/demo-app.ts | 1 - .../src/locales/pl-pl/translation/demo-app.ts | 1 - .../src/locales/pt-br/translation/demo-app.ts | 1 - .../src/locales/pt-pt/translation/demo-app.ts | 1 - .../src/locales/ru/translation/demo-app.ts | 1 - .../src/locales/tr-tr/translation/demo-app.ts | 1 - .../src/locales/zh-cn/translation/demo-app.ts | 1 - .../src/locales/zh-hk/translation/demo-app.ts | 1 - .../src/locales/zh-tw/translation/demo-app.ts | 1 - pnpm-lock.yaml | 185 ++++++++++++------ 23 files changed, 478 insertions(+), 118 deletions(-) create mode 100644 .changeset/few-moose-sniff.md create mode 100644 packages/demo-app/src/DevPanel.tsx create mode 100644 packages/demo-app/src/utils.ts diff --git a/.changeset/few-moose-sniff.md b/.changeset/few-moose-sniff.md new file mode 100644 index 00000000000..1f7b91aaf35 --- /dev/null +++ b/.changeset/few-moose-sniff.md @@ -0,0 +1,5 @@ +--- +"@logto/demo-app": minor +--- + +add dev panel diff --git a/packages/console/package.json b/packages/console/package.json index 02627ef3155..5b0d4279d02 100644 --- a/packages/console/package.json +++ b/packages/console/package.json @@ -33,7 +33,7 @@ "@logto/language-kit": "workspace:^1.1.0", "@logto/phrases": "workspace:^1.11.0", "@logto/phrases-experience": "workspace:^1.6.1", - "@logto/react": "^3.0.8", + "@logto/react": "^3.0.11", "@logto/schemas": "workspace:^1.17.0", "@logto/shared": "workspace:^3.1.1", "@mdx-js/react": "^1.6.22", diff --git a/packages/demo-app/package.json b/packages/demo-app/package.json index 3f3601d3276..ff0551ec4c1 100644 --- a/packages/demo-app/package.json +++ b/packages/demo-app/package.json @@ -22,7 +22,7 @@ "@logto/core-kit": "workspace:^2.4.0", "@logto/language-kit": "workspace:^1.1.0", "@logto/phrases": "workspace:^1.10.0", - "@logto/react": "^3.0.8", + "@logto/react": "^3.0.11", "@logto/schemas": "workspace:^1.15.0", "@parcel/core": "2.9.3", "@parcel/transformer-sass": "2.9.3", @@ -37,6 +37,7 @@ "eslint": "^8.56.0", "i18next": "^22.4.15", "i18next-browser-languagedetector": "^8.0.0", + "jose": "^5.0.0", "lint-staged": "^15.0.0", "parcel": "2.9.3", "postcss": "^8.4.31", diff --git a/packages/demo-app/src/App.module.scss b/packages/demo-app/src/App.module.scss index fbf059be47b..b739ae10399 100644 --- a/packages/demo-app/src/App.module.scss +++ b/packages/demo-app/src/App.module.scss @@ -3,40 +3,113 @@ @use '@logto/core-kit/scss/console-themes' as themes; .app { + input { + background-color: var(--color-layer-1); + font: var(--font-body-2); + color: var(--color-text); + padding: 0 _.unit(3); + height: 36px; + border: 1px solid var(--color-border); + outline: 3px solid transparent; + border-radius: 6px; + } + + .button { + display: inline-block; + user-select: none; + border: 1px solid var(--color-border); + background-color: var(--color-layer-1); + border-radius: 8px; + padding: _.unit(3) _.unit(6); + font: var(--font-label-2); + color: var(--color-text); + transition: background ease-in-out 0.2s; + + &:hover { + cursor: pointer; + background: var(--color-hover); + } + + &:focus { + outline: 3px solid var(--color-focused-variant); + } + } + + .card { background: var(--color-layer-1); border-radius: 16px; - position: absolute; - left: 50%; - top: 50%; - width: 640px; - height: 640px; - transform: translate(-50%, -50%); display: flex; flex-direction: column; - align-items: center; - text-align: center; font-size: 14px; line-height: 20px; - img { - margin-top: _.unit(25); - width: 120px; - height: 120px; - } - .title { - margin-top: _.unit(6); color: var(--color-neutral-10); font: var(--font-title-2); } .text { - margin-top: _.unit(1); font: var(--font-body-2); color: var(--color-text-secondary); } + &.congrats { + position: absolute; + left: 50%; + top: 50%; + align-items: center; + text-align: center; + width: 640px; + height: 640px; + transform: translate(-50%, -50%); + + .title { + margin-top: _.unit(6); + } + + .text { + margin-top: _.unit(1); + } + + .button { + margin-top: _.unit(8); + } + } + + &.devPanel { + max-width: 800px; + width: 25vw; + position: fixed; + left: _.unit(2); + top: _.unit(2); + padding: _.unit(4); + gap: _.unit(3); + + .item { + margin: _.unit(2) 0; + display: flex; + flex-direction: column; + gap: _.unit(1); + } + + .button { + align-self: flex-end; + } + + .action { + display: flex; + justify-content: space-between; + align-items: center; + } + } + + img { + margin-top: _.unit(25); + width: 120px; + height: 120px; + } + .infoCard { margin-top: _.unit(4); padding: _.unit(4); @@ -61,25 +134,6 @@ } } - .button { - user-select: none; - margin-top: _.unit(8); - border: 1px solid var(--color-border); - border-radius: 8px; - padding: _.unit(3) _.unit(6); - font: var(--font-label-2); - color: var(--color-text); - transition: background ease-in-out 0.2s; - - &:hover { - cursor: pointer; - background: var(--color-hover); - } - - &:focus { - outline: 3px solid var(--color-focused-variant); - } - } .continue { margin-top: _.unit(12); @@ -121,6 +175,11 @@ } } +.error { + color: var(--color-neutral-10); + margin: _.unit(3); +} + @media (prefers-color-scheme: light) { body { @include themes.light; diff --git a/packages/demo-app/src/App.tsx b/packages/demo-app/src/App.tsx index b5e4b876857..be4102bbc1b 100644 --- a/packages/demo-app/src/App.tsx +++ b/packages/demo-app/src/App.tsx @@ -1,28 +1,41 @@ -import type { IdTokenClaims } from '@logto/react'; -import { LogtoProvider, useLogto, Prompt, UserScope } from '@logto/react'; +import { type IdTokenClaims, LogtoProvider, useLogto, type Prompt } from '@logto/react'; import { demoAppApplicationId } from '@logto/schemas'; -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import '@/scss/normalized.scss'; + import * as styles from './App.module.scss'; import Callback from './Callback'; +import DevPanel from './DevPanel'; import congratsDark from './assets/congrats-dark.svg'; import congrats from './assets/congrats.svg'; import initI18n from './i18n/init'; +import { getLocalData, setLocalData } from './utils'; void initI18n(); const Main = () => { + const params = new URL(window.location.href).searchParams; const { isAuthenticated, isLoading, getIdTokenClaims, signIn, signOut } = useLogto(); const [user, setUser] = useState>(); const { t } = useTranslation(undefined, { keyPrefix: 'demo_app' }); - const isInCallback = Boolean(new URL(window.location.href).searchParams.get('code')); + const isInCallback = Boolean(params.get('code')); const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; const [congratsIcon, setCongratsIcon] = useState(isDarkMode ? congratsDark : congrats); + const [showDevPanel, setShowDevPanel] = useState(getLocalData('ui').showDevPanel ?? false); + const error = params.get('error'); + const errorDescription = params.get('error_description'); + + const toggleDevPanel = useCallback(() => { + setShowDevPanel((previous) => { + setLocalData('ui', { showDevPanel: !previous }); + return !previous; + }); + }, []); useEffect(() => { - if (isInCallback || isLoading) { + if (isInCallback || isLoading || error) { return; } @@ -43,7 +56,7 @@ const Main = () => { extraParams: Object.fromEntries(new URLSearchParams(window.location.search).entries()), }); } - }, [getIdTokenClaims, isAuthenticated, isInCallback, isLoading, signIn, user]); + }, [error, getIdTokenClaims, isAuthenticated, isInCallback, isLoading, signIn, user]); useEffect(() => { const onThemeChange = (event: MediaQueryListEvent) => { @@ -64,13 +77,37 @@ const Main = () => { return ; } + if (error) { + return ( +
+
+

+ Error occurred: {error} +
+ {errorDescription} +

+ +
+
+ ); + } + if (!isAuthenticated || !user) { return null; } return (
-
+ {showDevPanel && } +
{congratsIcon && Congrats}
{t('title')}
{t('subtitle')}
@@ -99,19 +136,36 @@ const Main = () => { > {t('sign_out')}
+
{ + if (key === 'Enter' || key === ' ') { + toggleDevPanel(); + } + }} + > + {showDevPanel ? 'Close' : 'Open'} dev panel +
); }; const App = () => { + const config = getLocalData('config'); + return (
diff --git a/packages/demo-app/src/DevPanel.tsx b/packages/demo-app/src/DevPanel.tsx new file mode 100644 index 00000000000..3ec27ea1a99 --- /dev/null +++ b/packages/demo-app/src/DevPanel.tsx @@ -0,0 +1,114 @@ +import { useLogto } from '@logto/react'; +import { decodeJwt } from 'jose'; +import { useCallback, useState, type FormEventHandler } from 'react'; + +import * as styles from './App.module.scss'; +import { getLocalData, setLocalData } from './utils'; + +const safeDecodeJwt = (token: string) => { + try { + return decodeJwt(token); + } catch { + return token; + } +}; + +const DevPanel = () => { + const config = getLocalData('config'); + const [showSaved, setShowSaved] = useState(false); + const { getAccessToken, getIdTokenClaims, fetchUserInfo } = useLogto(); + + const submitConfig: FormEventHandler = useCallback((event) => { + event.preventDefault(); + const formData = new FormData(event.currentTarget); + const data = Object.fromEntries(formData.entries()); + setLocalData('config', data); + setShowSaved(true); + + setTimeout(() => { + setShowSaved(false); + }, 500); + }, []); + + const requestToken: FormEventHandler = useCallback( + async (event) => { + event.preventDefault(); + const formData = new FormData(event.currentTarget); + const data = Object.fromEntries(formData.entries()); + const token = await getAccessToken( + data.resource ? String(data.resource) : undefined, + data.organizationId ? String(data.organizationId) : undefined + ); + console.log(token ? safeDecodeJwt(token) : 'No token'); + }, + [getAccessToken] + ); + + return ( +
+
+
Logto config
+
+
Prompt
+ +
+
+
Scope
+ +
+
+
Resource (space delimited)
+ +
+
+
Sign out to apply changes.
+ +
+
+
+
Refresh token grant
+
+
Resource
+ +
+
+
Organization ID
+ +
+
+
See console for the result.
+ +
+
+
+
User info
+
See console for the result.
+

+ +

+

+ +

+
+
+ ); +}; +export default DevPanel; diff --git a/packages/demo-app/src/utils.ts b/packages/demo-app/src/utils.ts new file mode 100644 index 00000000000..23eeb569a47 --- /dev/null +++ b/packages/demo-app/src/utils.ts @@ -0,0 +1,70 @@ +import { Prompt, UserScope } from '@logto/react'; +import { z } from 'zod'; + +type LocalLogtoConfig = { + prompt?: string; + scope?: string; + resource?: string; +}; + +const localLogtoConfigGuard = z.object({ + prompt: z.string(), + scope: z.string(), + resource: z.string(), +}) satisfies z.ZodType; + +type LocalUiConfig = { + showDevPanel?: boolean; +}; + +const localUiConfigGuard = z.object({ + showDevPanel: z.boolean(), +}) satisfies z.ZodType; + +type Key = 'config' | 'ui'; + +const keyPrefix = 'logto:demo-app:dev:'; + +type KeyToType = { + config: LocalLogtoConfig; + ui: LocalUiConfig; +}; + +const keyToGuard: Readonly<{ + [K in Key]: z.ZodType; +}> = Object.freeze({ + config: localLogtoConfigGuard, + ui: localUiConfigGuard, +}); + +const keyToDefault = Object.freeze({ + config: { + prompt: [Prompt.Login, Prompt.Consent].join(' '), + scope: [UserScope.Organizations, UserScope.OrganizationRoles].join(' '), + }, + ui: {}, +} satisfies Record); + +const safeJsonParse = (value: string): unknown => { + try { + return JSON.parse(value); + } catch { + return null; + } +}; + +const safeZodParse = (guard: z.ZodType, value: unknown) => { + const result = guard.safeParse(value); + return result.success ? result.data : {}; +}; + +export const getLocalData = (key: K): KeyToType[K] => { + const result = keyToGuard[key].safeParse( + safeJsonParse(localStorage.getItem(`${keyPrefix}${key}`) ?? '') + ); + return result.success ? result.data : keyToDefault[key]; +}; + +export const setLocalData = (key: Key, value: unknown) => { + localStorage.setItem(`${keyPrefix}${key}`, JSON.stringify(safeZodParse(keyToGuard[key], value))); +}; diff --git a/packages/phrases/src/locales/de/translation/demo-app.ts b/packages/phrases/src/locales/de/translation/demo-app.ts index 387aa9a6b12..c029a2031a7 100644 --- a/packages/phrases/src/locales/de/translation/demo-app.ts +++ b/packages/phrases/src/locales/de/translation/demo-app.ts @@ -1,6 +1,5 @@ const demo_app = { title: 'Sie haben sich erfolgreich bei der Live-Vorschau angemeldet!', - subtitle: 'Hier sind Ihre Anmeldeinformationen:', username: 'Benutzername: ', user_id: 'Benutzer ID: ', sign_out: 'Abmeldung von der Live-Vorschau', diff --git a/packages/phrases/src/locales/en/translation/demo-app.ts b/packages/phrases/src/locales/en/translation/demo-app.ts index 112b45dbee6..f97b4d0b673 100644 --- a/packages/phrases/src/locales/en/translation/demo-app.ts +++ b/packages/phrases/src/locales/en/translation/demo-app.ts @@ -1,6 +1,6 @@ const demo_app = { title: "You've successfully signed in the live preview!", - subtitle: 'Here is your log in information:', + subtitle: 'Here is your user information:', username: 'Username: ', user_id: 'User ID: ', sign_out: 'Sign out the live preview', diff --git a/packages/phrases/src/locales/es/translation/demo-app.ts b/packages/phrases/src/locales/es/translation/demo-app.ts index 6355736c642..007e52626a4 100644 --- a/packages/phrases/src/locales/es/translation/demo-app.ts +++ b/packages/phrases/src/locales/es/translation/demo-app.ts @@ -1,6 +1,5 @@ const demo_app = { title: '¡Ha iniciado sesión correctamente en la vista previa en vivo!', - subtitle: 'Aquí está su información de inicio de sesión:', username: 'Nombre de usuario: ', user_id: 'ID de usuario: ', sign_out: 'Cerrar sesión en la vista previa en vivo', diff --git a/packages/phrases/src/locales/fr/translation/demo-app.ts b/packages/phrases/src/locales/fr/translation/demo-app.ts index 1116656f477..9513c7c0e1d 100644 --- a/packages/phrases/src/locales/fr/translation/demo-app.ts +++ b/packages/phrases/src/locales/fr/translation/demo-app.ts @@ -1,6 +1,5 @@ const demo_app = { title: "Vous vous êtes connecté avec succès à l'aperçu en direct !", - subtitle: 'Voici vos informations de connexion :', username: "Nom d'utilisateur :", user_id: "ID de l'utilisateur :", sign_out: "Se déconnecter de l'aperçu en direct", diff --git a/packages/phrases/src/locales/it/translation/demo-app.ts b/packages/phrases/src/locales/it/translation/demo-app.ts index 4007a098561..dd8abf5a1a5 100644 --- a/packages/phrases/src/locales/it/translation/demo-app.ts +++ b/packages/phrases/src/locales/it/translation/demo-app.ts @@ -1,6 +1,5 @@ const demo_app = { title: "Hai effettuato l'accesso anteprima live con successo!", - subtitle: 'Ecco le tue informazioni di accesso:', username: 'Nome utente: ', user_id: 'ID utente: ', sign_out: "Esci dall'anteprima live", diff --git a/packages/phrases/src/locales/ja/translation/demo-app.ts b/packages/phrases/src/locales/ja/translation/demo-app.ts index 53b2334679b..6166e0ef471 100644 --- a/packages/phrases/src/locales/ja/translation/demo-app.ts +++ b/packages/phrases/src/locales/ja/translation/demo-app.ts @@ -1,6 +1,5 @@ const demo_app = { title: 'ライブプレビューへのサインインに成功しました!', - subtitle: 'あなたのログイン情報は以下の通りです:', username: 'ユーザー名:', user_id: 'ユーザーID:', sign_out: 'ライブプレビューからサインアウトする', diff --git a/packages/phrases/src/locales/ko/translation/demo-app.ts b/packages/phrases/src/locales/ko/translation/demo-app.ts index 6e18e8ddeb2..2089c0d1863 100644 --- a/packages/phrases/src/locales/ko/translation/demo-app.ts +++ b/packages/phrases/src/locales/ko/translation/demo-app.ts @@ -1,6 +1,5 @@ const demo_app = { title: 'Live Preview에 성공적으로 로그인했습니다!', - subtitle: '여기 로그인 정보가 있어요:', username: '사용자 이름: ', user_id: '사용자 ID: ', sign_out: 'Live Preview에서 로그아웃', diff --git a/packages/phrases/src/locales/pl-pl/translation/demo-app.ts b/packages/phrases/src/locales/pl-pl/translation/demo-app.ts index 096780ff640..20c8e8b2e91 100644 --- a/packages/phrases/src/locales/pl-pl/translation/demo-app.ts +++ b/packages/phrases/src/locales/pl-pl/translation/demo-app.ts @@ -1,6 +1,5 @@ const demo_app = { title: 'Pomyślnie zalogowałeś się do podglądu na żywo!', - subtitle: 'Oto twoje informacje logowania:', username: 'Nazwa użytkownika: ', user_id: 'ID użytkownika: ', sign_out: 'Wyloguj się z podglądu na żywo', diff --git a/packages/phrases/src/locales/pt-br/translation/demo-app.ts b/packages/phrases/src/locales/pt-br/translation/demo-app.ts index f5fad17b702..511c5109e92 100644 --- a/packages/phrases/src/locales/pt-br/translation/demo-app.ts +++ b/packages/phrases/src/locales/pt-br/translation/demo-app.ts @@ -1,6 +1,5 @@ const demo_app = { title: "You've successfully signed in the live preview!", - subtitle: 'Aqui estão suas informações de login:', username: 'Nome de usuário: ', user_id: 'ID do usuário: ', sign_out: 'Sair da Visualização ao Vivo', diff --git a/packages/phrases/src/locales/pt-pt/translation/demo-app.ts b/packages/phrases/src/locales/pt-pt/translation/demo-app.ts index b80249292a7..013b1332948 100644 --- a/packages/phrases/src/locales/pt-pt/translation/demo-app.ts +++ b/packages/phrases/src/locales/pt-pt/translation/demo-app.ts @@ -1,6 +1,5 @@ const demo_app = { title: 'Iniciou sessão com sucesso na pré-visualização ao vivo!', - subtitle: 'Aqui estão as suas informações de login:', username: 'Utilizador: ', user_id: 'ID de utilizador: ', sign_out: 'Terminar sessão na visualização ao vivo', diff --git a/packages/phrases/src/locales/ru/translation/demo-app.ts b/packages/phrases/src/locales/ru/translation/demo-app.ts index b072bc3c948..65bcdec6282 100644 --- a/packages/phrases/src/locales/ru/translation/demo-app.ts +++ b/packages/phrases/src/locales/ru/translation/demo-app.ts @@ -1,6 +1,5 @@ const demo_app = { title: 'Вы успешно вошли в живой просмотр!', - subtitle: 'Вот ваши данные для входа:', username: 'Имя пользователя: ', user_id: 'Идентификатор пользователя: ', sign_out: 'Выйти из живого просмотра', diff --git a/packages/phrases/src/locales/tr-tr/translation/demo-app.ts b/packages/phrases/src/locales/tr-tr/translation/demo-app.ts index d22b9aa5ff2..ec595fd6b33 100644 --- a/packages/phrases/src/locales/tr-tr/translation/demo-app.ts +++ b/packages/phrases/src/locales/tr-tr/translation/demo-app.ts @@ -1,6 +1,5 @@ const demo_app = { title: 'Canlı önizlemede başarıyla oturum açtınız!', - subtitle: 'Sisteme giriş bilgileriniz:', username: 'Kullanıcı Adı: ', user_id: 'Kullanıcı Kimliği: ', sign_out: 'Canlı Önizlemeyi Kapat', diff --git a/packages/phrases/src/locales/zh-cn/translation/demo-app.ts b/packages/phrases/src/locales/zh-cn/translation/demo-app.ts index 97c736a9758..d95201960f9 100644 --- a/packages/phrases/src/locales/zh-cn/translation/demo-app.ts +++ b/packages/phrases/src/locales/zh-cn/translation/demo-app.ts @@ -1,6 +1,5 @@ const demo_app = { title: '你已成功登录实时预览!', - subtitle: '以下是本次登录的用户信息:', username: '用户名:', user_id: '用户 ID:', sign_out: '退出实时预览', diff --git a/packages/phrases/src/locales/zh-hk/translation/demo-app.ts b/packages/phrases/src/locales/zh-hk/translation/demo-app.ts index ad8e5f98077..23c5e617e7e 100644 --- a/packages/phrases/src/locales/zh-hk/translation/demo-app.ts +++ b/packages/phrases/src/locales/zh-hk/translation/demo-app.ts @@ -1,6 +1,5 @@ const demo_app = { title: '你已成功登錄實時預覽!', - subtitle: '以下是本次登錄的用戶信息:', username: '用戶名:', user_id: '用戶 ID:', sign_out: '退出實時預覽', diff --git a/packages/phrases/src/locales/zh-tw/translation/demo-app.ts b/packages/phrases/src/locales/zh-tw/translation/demo-app.ts index ad8e5f98077..23c5e617e7e 100644 --- a/packages/phrases/src/locales/zh-tw/translation/demo-app.ts +++ b/packages/phrases/src/locales/zh-tw/translation/demo-app.ts @@ -1,6 +1,5 @@ const demo_app = { title: '你已成功登錄實時預覽!', - subtitle: '以下是本次登錄的用戶信息:', username: '用戶名:', user_id: '用戶 ID:', sign_out: '退出實時預覽', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9f28f2d3481..5df5c7ecc1f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2876,8 +2876,8 @@ importers: specifier: workspace:^1.6.1 version: link:../phrases-experience '@logto/react': - specifier: ^3.0.8 - version: 3.0.8(react@18.2.0) + specifier: ^3.0.11 + version: 3.0.11(react@18.2.0) '@logto/schemas': specifier: workspace:^1.17.0 version: link:../schemas @@ -3418,7 +3418,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.10.4) + version: 29.7.0(@types/node@20.10.4)(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3)) jest-matcher-specific-error: specifier: ^1.0.0 version: 1.0.0 @@ -3468,8 +3468,8 @@ importers: specifier: workspace:^1.10.0 version: link:../phrases '@logto/react': - specifier: ^3.0.8 - version: 3.0.8(react@18.2.0) + specifier: ^3.0.11 + version: 3.0.11(react@18.2.0) '@logto/schemas': specifier: workspace:^1.15.0 version: link:../schemas @@ -3512,6 +3512,9 @@ importers: i18next-browser-languagedetector: specifier: ^8.0.0 version: 8.0.0 + jose: + specifier: ^5.0.0 + version: 5.2.4 lint-staged: specifier: ^15.0.0 version: 15.0.2 @@ -3670,7 +3673,7 @@ importers: version: 3.0.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.12.7) + version: 29.7.0(@types/node@20.12.7)(ts-node@10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3)) jest-environment-jsdom: specifier: ^29.0.0 version: 29.2.2 @@ -3679,7 +3682,7 @@ importers: version: 2.0.0 jest-transformer-svg: specifier: ^2.0.0 - version: 2.0.0(jest@29.7.0(@types/node@20.12.7))(react@18.2.0) + version: 2.0.0(jest@29.7.0(@types/node@20.12.7)(ts-node@10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3)))(react@18.2.0) js-base64: specifier: ^3.7.5 version: 3.7.5 @@ -3818,7 +3821,7 @@ importers: version: 10.0.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.10.4) + version: 29.7.0(@types/node@20.10.4)(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3)) jest-matcher-specific-error: specifier: ^1.0.0 version: 1.0.0 @@ -5260,12 +5263,15 @@ packages: resolution: {integrity: sha512-yDWSZMI2Qo/xoYU92tnwSP/gnSvq8+CLK5DqD/4brO42QJa7xjt7eA+HSyuMmSUrKffY2nP3riU81gs+nR8DkA==} engines: {node: ^18.12.0} - '@logto/browser@2.2.10': - resolution: {integrity: sha512-y6NauaxctqpfApccP6uFVmpg/vG1OhsDVLD4Pdpzbmj3whl63Nb17yxSTQHt4eYNKmSZJ2SzudAnMnVEYD91iQ==} + '@logto/browser@2.2.13': + resolution: {integrity: sha512-7fyenm6f2xSzZc8GHFpAL38rxAXf1hQH/ySSow8QHjgypF0pz9zy9bRSG1oVFgsMrFWYf73dPk7V2ACQ5Tujww==} '@logto/client@2.6.6': resolution: {integrity: sha512-QT7jMnzEIWHBNrf9/M8p1OErRBbbNZjoekXGji5aZCyUh975hh8+GEBL21HV71FT3H/5Cq4Gf1GzUbAIW3izMA==} + '@logto/client@2.7.0': + resolution: {integrity: sha512-8mj+757befwQJ4M0h4f3fQwUB1lruDkyLNTyRFOQxFfDMN1QeD70B4nMnz6iTX/Gi09HnIskmj9MHWrbvH6LSQ==} + '@logto/cloud@0.2.5-a7eedce': resolution: {integrity: sha512-FFjkGjqUgn9PCZnSuCODm2FcjqBm4JfPxfHCiXlOkUjeUhTJLrj7C0gjKzSQ/B6IaWri4EXN/meuqi5z/AMIPg==} engines: {node: ^20.9.0} @@ -5273,11 +5279,14 @@ packages: '@logto/js@4.1.1': resolution: {integrity: sha512-+RgthBvDw30UojirtAjZeHNfOwDQVURmpjcIBYTIf6afx5F5jJq8b1D/eaFbrCFrmXmatkT2iN7X8kYHui86WQ==} + '@logto/js@4.1.3': + resolution: {integrity: sha512-TIYrVSyD0c1mEt3fU9NKbWRTblujs3Ct/DYgNzBLzE/tmSVvwM6Z4JxnwZZ3xyfnL8dC4UfSQRlc2gjSMzKUGw==} + '@logto/node@2.4.7': resolution: {integrity: sha512-AlANeqY1NIt93EBcRzrTmyAVHXOHpszTJK+qe1ok50rmZlTmX2p7yQvrg0/Ehwf/+4Rla5vooAR+HIFMaOmPpQ==} - '@logto/react@3.0.8': - resolution: {integrity: sha512-p3pV4rX4g8ZwHQ159mxI+pP3Bwome47dNEmP1hI8/10WqdIPXGYTnfYn5c2l4Y2DyslYyK3ur2Sy4i4K6ept9A==} + '@logto/react@3.0.11': + resolution: {integrity: sha512-JyOOf7zZOEg7fTRldfi9SGwwbuk3qJTlIKld+GQ1yGWIXilI2JyyY2XQraZWpHQLW8KtQFgRWQ/fUKV0bideFQ==} peerDependencies: react: '>=16.8.0' @@ -14487,6 +14496,41 @@ snapshots: - supports-color - ts-node + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.12.7 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.8.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.12.7)(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.5 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + '@jest/create-cache-key-function@27.5.1': dependencies: '@jest/types': 27.5.1 @@ -14749,9 +14793,9 @@ snapshots: '@silverhand/essentials': 2.9.1 tiny-cookie: 2.4.1 - '@logto/browser@2.2.10': + '@logto/browser@2.2.13': dependencies: - '@logto/client': 2.6.6 + '@logto/client': 2.7.0 '@silverhand/essentials': 2.9.1 js-base64: 3.7.5 @@ -14762,6 +14806,13 @@ snapshots: camelcase-keys: 7.0.2 jose: 5.2.4 + '@logto/client@2.7.0': + dependencies: + '@logto/js': 4.1.3 + '@silverhand/essentials': 2.9.1 + camelcase-keys: 7.0.2 + jose: 5.2.4 + '@logto/cloud@0.2.5-a7eedce(zod@3.22.4)': dependencies: '@silverhand/essentials': 2.9.1 @@ -14774,15 +14825,20 @@ snapshots: '@silverhand/essentials': 2.9.1 camelcase-keys: 7.0.2 + '@logto/js@4.1.3': + dependencies: + '@silverhand/essentials': 2.9.1 + camelcase-keys: 7.0.2 + '@logto/node@2.4.7': dependencies: '@logto/client': 2.6.6 '@silverhand/essentials': 2.9.1 js-base64: 3.7.5 - '@logto/react@3.0.8(react@18.2.0)': + '@logto/react@3.0.11(react@18.2.0)': dependencies: - '@logto/browser': 2.2.10 + '@logto/browser': 2.2.13 '@silverhand/essentials': 2.9.1 react: 18.2.0 @@ -17857,13 +17913,13 @@ snapshots: dependencies: lodash.get: 4.4.2 - create-jest@29.7.0(@types/node@20.10.4): + create-jest@29.7.0(@types/node@20.10.4)(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.10.4) + jest-config: 29.7.0(@types/node@20.10.4)(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -19999,16 +20055,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.10.4): + jest-cli@29.7.0(@types/node@20.10.4)(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.10.4) + create-jest: 29.7.0(@types/node@20.10.4)(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3)) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.10.4) + jest-config: 29.7.0(@types/node@20.10.4)(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -20018,7 +20074,7 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@20.12.7): + jest-cli@29.7.0(@types/node@20.12.7)(ts-node@10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3)) '@jest/test-result': 29.7.0 @@ -20037,26 +20093,38 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@20.12.7)(ts-node@10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3)): + jest-config@29.7.0(@types/node@20.10.4)(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3)) - '@jest/test-result': 29.7.0 + '@babel/core': 7.24.4 + '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.24.4) chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.12.7)(ts-node@10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3)) - exit: 0.1.2 - import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.12.7)(ts-node@10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3)) + ci-info: 3.8.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 jest-util: 29.7.0 jest-validate: 29.7.0 - yargs: 17.7.2 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.10.4 + ts-node: 10.9.2(@types/node@20.10.4)(typescript@5.3.3) transitivePeerDependencies: - - '@types/node' - babel-plugin-macros - supports-color - - ts-node - jest-config@29.7.0(@types/node@20.10.4): + jest-config@29.7.0(@types/node@20.12.7)(ts-node@10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3)): dependencies: '@babel/core': 7.24.4 '@jest/test-sequencer': 29.7.0 @@ -20081,12 +20149,13 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.10.4 + '@types/node': 20.12.7 + ts-node: 10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.12.7)(ts-node@10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3)): + jest-config@29.7.0(@types/node@20.12.7)(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3)): dependencies: '@babel/core': 7.24.4 '@jest/test-sequencer': 29.7.0 @@ -20112,7 +20181,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.12.7 - ts-node: 10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3) + ts-node: 10.9.2(@types/node@20.10.4)(typescript@5.3.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -20391,11 +20460,6 @@ snapshots: jest: 29.7.0(@types/node@20.12.7)(ts-node@10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3)) react: 18.2.0 - jest-transformer-svg@2.0.0(jest@29.7.0(@types/node@20.12.7))(react@18.2.0): - dependencies: - jest: 29.7.0(@types/node@20.12.7) - react: 18.2.0 - jest-util@29.5.0: dependencies: '@jest/types': 29.6.3 @@ -20448,24 +20512,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.10.4): + jest@29.7.0(@types/node@20.10.4)(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3)) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.10.4) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - - jest@29.7.0(@types/node@20.12.7): - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.3.52(@swc/helpers@0.5.1))(@types/node@20.12.7)(typescript@5.3.3)) - '@jest/types': 29.6.3 - import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.12.7) + jest-cli: 29.7.0(@types/node@20.10.4)(ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -23685,6 +23737,25 @@ snapshots: optionalDependencies: '@swc/core': 1.3.52(@swc/helpers@0.5.1) + ts-node@10.9.2(@types/node@20.10.4)(typescript@5.3.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.10.4 + acorn: 8.10.0 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.3.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29