0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

chore: upgrade logto sdks (#5011)

* chore: upgrade logto sdks

* chore: fix tests

* fix(demo-app): fix hook infinite loop issue

* refactor(demo-app): use enum from sdk
This commit is contained in:
Gao Sun 2023-12-02 15:22:27 +08:00 committed by GitHub
parent e1a162eb56
commit fc9c9ea721
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 65 additions and 107 deletions

View file

@ -32,7 +32,7 @@
"@logto/language-kit": "workspace:^1.0.0", "@logto/language-kit": "workspace:^1.0.0",
"@logto/phrases": "workspace:^1.7.0", "@logto/phrases": "workspace:^1.7.0",
"@logto/phrases-experience": "workspace:^1.4.0", "@logto/phrases-experience": "workspace:^1.4.0",
"@logto/react": "^2.1.2", "@logto/react": "^2.2.0",
"@logto/schemas": "workspace:^1.11.0", "@logto/schemas": "workspace:^1.11.0",
"@logto/shared": "workspace:^3.0.0", "@logto/shared": "workspace:^3.0.0",
"@mdx-js/react": "^1.6.22", "@mdx-js/react": "^1.6.22",

View file

@ -22,7 +22,7 @@
"@logto/core-kit": "workspace:^2.0.0", "@logto/core-kit": "workspace:^2.0.0",
"@logto/language-kit": "workspace:^1.0.0", "@logto/language-kit": "workspace:^1.0.0",
"@logto/phrases": "workspace:^1.2.0", "@logto/phrases": "workspace:^1.2.0",
"@logto/react": "^2.1.0", "@logto/react": "^2.2.0",
"@logto/schemas": "workspace:^1.2.3", "@logto/schemas": "workspace:^1.2.3",
"@parcel/core": "2.9.3", "@parcel/core": "2.9.3",
"@parcel/transformer-sass": "2.9.3", "@parcel/transformer-sass": "2.9.3",

View file

@ -1,5 +1,5 @@
import type { IdTokenClaims } from '@logto/react'; import type { IdTokenClaims } from '@logto/react';
import { LogtoProvider, useLogto, Prompt } from '@logto/react'; import { LogtoProvider, useLogto, Prompt, UserScope } from '@logto/react';
import { demoAppApplicationId } from '@logto/schemas'; import { demoAppApplicationId } from '@logto/schemas';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -22,19 +22,25 @@ const Main = () => {
const [congratsIcon, setCongratsIcon] = useState<string>(isDarkMode ? congratsDark : congrats); const [congratsIcon, setCongratsIcon] = useState<string>(isDarkMode ? congratsDark : congrats);
useEffect(() => { useEffect(() => {
if (isInCallback) { if (isInCallback || isLoading) {
return; return;
} }
if (isAuthenticated) { const loadIdTokenClaims = async () => {
(async () => { const userInfo = await getIdTokenClaims();
const userInfo = await getIdTokenClaims(); setUser(userInfo ?? { sub: 'N/A', username: 'N/A' });
setUser(userInfo ?? { sub: 'N/A', username: 'N/A' }); };
})();
} else if (!isLoading) { // If user is authenticated but user info is not loaded yet, load it
if (isAuthenticated && !user) {
void loadIdTokenClaims();
}
// If user is not authenticated, redirect to sign-in page
if (!isAuthenticated) {
void signIn(window.location.href); void signIn(window.location.href);
} }
}, [getIdTokenClaims, isAuthenticated, isLoading, isInCallback, signIn, t]); }, [getIdTokenClaims, isAuthenticated, isInCallback, isLoading, signIn, user]);
useEffect(() => { useEffect(() => {
const onThemeChange = (event: MediaQueryListEvent) => { const onThemeChange = (event: MediaQueryListEvent) => {
@ -102,9 +108,7 @@ const App = () => {
endpoint: window.location.origin, endpoint: window.location.origin,
appId: demoAppApplicationId, appId: demoAppApplicationId,
prompt: Prompt.Login, prompt: Prompt.Login,
// TODO: Use enum values once JS SDK is updated scopes: [UserScope.Organizations, UserScope.OrganizationRoles],
scopes: ['urn:logto:scope:organizations', 'urn:logto:scope:organization_roles'],
resources: ['urn:logto:resource:organizations'],
}} }}
> >
<Main /> <Main />

View file

@ -25,8 +25,8 @@
"@jest/test-sequencer": "^29.5.0", "@jest/test-sequencer": "^29.5.0",
"@jest/types": "^29.1.2", "@jest/types": "^29.1.2",
"@logto/connector-kit": "workspace:^2.0.0", "@logto/connector-kit": "workspace:^2.0.0",
"@logto/js": "^2.1.1", "@logto/js": "^3.0.1",
"@logto/node": "^2.1.1", "@logto/node": "^2.2.0",
"@logto/schemas": "workspace:^1.10.1", "@logto/schemas": "workspace:^1.10.1",
"@logto/shared": "workspace:^3.0.0", "@logto/shared": "workspace:^3.0.0",
"@silverhand/eslint-config": "4.0.1", "@silverhand/eslint-config": "4.0.1",

View file

@ -1,23 +1,23 @@
import type { Storage, StorageKey } from '@logto/node'; import type { PersistKey, Storage } from '@logto/node';
import type { Nullable } from '@silverhand/essentials'; import type { Nullable } from '@silverhand/essentials';
export class MemoryStorage implements Storage { export class MemoryStorage implements Storage<PersistKey> {
private storage: { [key in StorageKey]: Nullable<string> } = { private storage: { [key in PersistKey]: Nullable<string> } = {
idToken: null, idToken: null,
refreshToken: null, refreshToken: null,
accessToken: null, accessToken: null,
signInSession: null, signInSession: null,
}; };
async getItem(key: StorageKey): Promise<Nullable<string>> { async getItem(key: PersistKey): Promise<Nullable<string>> {
return this.storage[key]; return this.storage[key];
} }
async setItem(key: StorageKey, value: string): Promise<void> { async setItem(key: PersistKey, value: string): Promise<void> {
this.storage[key] = value; this.storage[key] = value;
} }
async removeItem(key: StorageKey): Promise<void> { async removeItem(key: PersistKey): Promise<void> {
this.storage[key] = null; this.storage[key] = null;
} }
} }

View file

@ -77,20 +77,16 @@ describe('OpenID Connect ID token', () => {
await organizationApi.addUserRoles(org1.id, userId, [role.id]); await organizationApi.addUserRoles(org1.id, userId, [role.id]);
// Organizations claim // Organizations claim
const idToken = await fetchIdToken(['urn:logto:scope:organizations']); const { organizations } = await fetchIdToken(['urn:logto:scope:organizations']);
// @ts-expect-error type definition needs to be updated
const organizations = idToken.organizations as unknown;
expect(organizations).toHaveLength(2); expect(organizations).toHaveLength(2);
expect(organizations).toContainEqual(org1.id); expect(organizations).toContainEqual(org1.id);
expect(organizations).toContainEqual(org2.id); expect(organizations).toContainEqual(org2.id);
// Organization roles claim // Organization roles claim
const idToken2 = await fetchIdToken(['urn:logto:scope:organization_roles']); const { organization_roles: organizationRoles } = await fetchIdToken([
'urn:logto:scope:organization_roles',
// @ts-expect-error type definition needs to be updated ]);
const organizationRoles = idToken2.organization_roles as unknown;
expect(organizationRoles).toHaveLength(1); expect(organizationRoles).toHaveLength(1);
expect(organizationRoles).toContainEqual(`${org1.id}:${role.name}`); expect(organizationRoles).toContainEqual(`${org1.id}:${role.name}`);

View file

@ -1,7 +1,7 @@
import assert from 'node:assert'; import assert from 'node:assert';
import { decodeAccessToken } from '@logto/js'; import { decodeAccessToken } from '@logto/js';
import { type LogtoConfig, Prompt } from '@logto/node'; import { type LogtoConfig, Prompt, PersistKey } from '@logto/node';
import { GrantType, InteractionEvent, demoAppApplicationId } from '@logto/schemas'; import { GrantType, InteractionEvent, demoAppApplicationId } from '@logto/schemas';
import { isKeyInObject, removeUndefinedKeys } from '@silverhand/essentials'; import { isKeyInObject, removeUndefinedKeys } from '@silverhand/essentials';
import { HTTPError, got } from 'got'; import { HTTPError, got } from 'got';
@ -61,7 +61,7 @@ class MockOrganizationClient extends MockClient {
}) })
.json(); .json();
if (isKeyInObject(json, 'refresh_token')) { if (isKeyInObject(json, 'refresh_token')) {
await this.storage.setItem('refreshToken', String(json.refresh_token)); await this.storage.setItem(PersistKey.RefreshToken, String(json.refresh_token));
} }
return json; return json;
} catch (error) { } catch (error) {
@ -267,7 +267,7 @@ describe('`refresh_token` grant (for organization tokens)', () => {
await expect(client.fetchOrganizationToken(org.id)).rejects.toMatchError(accessDeniedError); await expect(client.fetchOrganizationToken(org.id)).rejects.toMatchError(accessDeniedError);
}); });
it('should not issue organization scopes when organization resource is not requested', async () => { it('should issue organization scopes even organization resource is not requested (handled by SDK)', async () => {
const { orgs } = await initOrganizations(); const { orgs } = await initOrganizations();
const client = await initClient({ const client = await initClient({
@ -276,11 +276,11 @@ describe('`refresh_token` grant (for organization tokens)', () => {
}); });
expectGrantResponse(await client.fetchOrganizationToken(orgs[0].id), { expectGrantResponse(await client.fetchOrganizationToken(orgs[0].id), {
organizationId: orgs[0].id, organizationId: orgs[0].id,
scopes: [], scopes: ['scope1', 'scope2'],
}); });
expectGrantResponse(await client.fetchOrganizationToken(orgs[1].id), { expectGrantResponse(await client.fetchOrganizationToken(orgs[1].id), {
organizationId: orgs[1].id, organizationId: orgs[1].id,
scopes: [], scopes: ['scope1', 'scope2'],
}); });
expectGrantResponse(await client.fetchOrganizationToken(orgs[2].id), { expectGrantResponse(await client.fetchOrganizationToken(orgs[2].id), {
organizationId: orgs[2].id, organizationId: orgs[2].id,

View file

@ -2858,8 +2858,8 @@ importers:
specifier: workspace:^1.4.0 specifier: workspace:^1.4.0
version: link:../phrases-experience version: link:../phrases-experience
'@logto/react': '@logto/react':
specifier: ^2.1.2 specifier: ^2.2.0
version: 2.1.2(react@18.2.0) version: 2.2.0(react@18.2.0)
'@logto/schemas': '@logto/schemas':
specifier: workspace:^1.11.0 specifier: workspace:^1.11.0
version: link:../schemas version: link:../schemas
@ -3435,8 +3435,8 @@ importers:
specifier: workspace:^1.2.0 specifier: workspace:^1.2.0
version: link:../phrases version: link:../phrases
'@logto/react': '@logto/react':
specifier: ^2.1.0 specifier: ^2.2.0
version: 2.1.0(react@18.2.0) version: 2.2.0(react@18.2.0)
'@logto/schemas': '@logto/schemas':
specifier: workspace:^1.2.3 specifier: workspace:^1.2.3
version: link:../schemas version: link:../schemas
@ -3745,11 +3745,11 @@ importers:
specifier: workspace:^2.0.0 specifier: workspace:^2.0.0
version: link:../toolkit/connector-kit version: link:../toolkit/connector-kit
'@logto/js': '@logto/js':
specifier: ^2.1.1 specifier: ^3.0.1
version: 2.1.1 version: 3.0.1
'@logto/node': '@logto/node':
specifier: ^2.1.1 specifier: ^2.2.0
version: 2.1.1 version: 2.2.0
'@logto/schemas': '@logto/schemas':
specifier: workspace:^1.10.1 specifier: workspace:^1.10.1
version: link:../schemas version: link:../schemas
@ -7479,47 +7479,21 @@ packages:
tiny-cookie: 2.4.1 tiny-cookie: 2.4.1
dev: false dev: false
/@logto/browser@2.1.0: /@logto/browser@2.2.0:
resolution: {integrity: sha512-4XsXlCC0uZHcfazV09/4YKo4koqvSzQlkPUAToTp/WHpb6h2XDOJh5/hi55LXL4zp0PCcgpErKRxFCtgXCc6WQ==} resolution: {integrity: sha512-8kKh1EcAm19smnEMvw0M51d2EQXEEH77G1JEKh1iLifUScmxD+c7HcN/5mLekaBz36MUVNiA2gE7s9L2GOpWrg==}
dependencies: dependencies:
'@logto/client': 2.2.0 '@logto/client': 2.3.0
'@silverhand/essentials': 2.8.4 '@silverhand/essentials': 2.8.5
js-base64: 3.7.5 js-base64: 3.7.5
dev: true dev: true
/@logto/browser@2.1.2: /@logto/client@2.3.0:
resolution: {integrity: sha512-LADZHT7LTyiWDwWmBwh3qAtOg+IVEjfaFKBTB/RQBc5T9xYO4q4JcyW1XgpMlkc0uLqOtW3uOGztUVs0ugi6/g==} resolution: {integrity: sha512-VrzsF+QtnrVXnDFbsdYTeGatjThlTFwtjTT/jJMaFdyRg0lno8vHxsjuyG8ba4wVSu22tSmJAr7okpAwRyhtcg==}
dependencies: dependencies:
'@logto/client': 2.2.3 '@logto/js': 3.0.1
'@silverhand/essentials': 2.8.4
js-base64: 3.7.5
dev: true
/@logto/client@2.1.0:
resolution: {integrity: sha512-vw8xDW8k38/58Q1r592z/9JdsmUh4+LMmoVm/Nu7LbWKlT32eD3H9hZDkFK9XEHpriifhI0hP7asGWEmhrEUuQ==}
dependencies:
'@logto/js': 2.1.1
'@silverhand/essentials': 2.8.4
camelcase-keys: 7.0.2
jose: 4.14.4
dev: true
/@logto/client@2.2.0:
resolution: {integrity: sha512-7I2ELo5UWIJsFCYK/gX465l0+QhXTdyYWkgb2CcdPu5KbaPBNpASedm+fEV2NREYe2svbNODFhog6UMA/xGQnQ==}
dependencies:
'@logto/js': 2.1.1
'@silverhand/essentials': 2.8.5 '@silverhand/essentials': 2.8.5
camelcase-keys: 7.0.2 camelcase-keys: 7.0.2
jose: 4.14.4 jose: 5.0.1
dev: true
/@logto/client@2.2.3:
resolution: {integrity: sha512-xq4LhQ6ItbukAHgsMDcgfspTpdpO5sSfSEugpOrGP/nLwzGTfBO78OSUfMdBQEDr5+3SRmONuSjUBBwssOLINA==}
dependencies:
'@logto/js': 2.1.3
'@silverhand/essentials': 2.8.5
camelcase-keys: 7.0.2
jose: 4.14.4
dev: true dev: true
/@logto/cloud@0.2.5-5a698db(zod@3.22.4): /@logto/cloud@0.2.5-5a698db(zod@3.22.4):
@ -7532,50 +7506,32 @@ packages:
- zod - zod
dev: true dev: true
/@logto/js@2.1.1: /@logto/js@3.0.1:
resolution: {integrity: sha512-PHikheavVK+l4ivgtzi14p184hEPgXjqQEAom1Gme1MZoopx+WlwxvHSEQBsmyvVqRtI0oiojhoU5tgYi1FKJw==} resolution: {integrity: sha512-vsU6mH5oiiW3k00pMyVA4V31K2Bd0rOT9qWch2l5e5o1yCQLJ3zUIOjGjChu3m2TRu1d920iiUpZU3Lzf6Pwdw==}
dependencies:
'@silverhand/essentials': 2.8.4
camelcase-keys: 7.0.2
jose: 4.14.4
dev: true
/@logto/js@2.1.3:
resolution: {integrity: sha512-TOuoC5gHx/SfY5gcGSBfw63x5TpM6Lm/9J5y0Jy003Z1DZARUlpz0KbzyCVAIC/+6qIefkmNPHKl1rq9MB/hog==}
dependencies: dependencies:
'@silverhand/essentials': 2.8.5 '@silverhand/essentials': 2.8.5
camelcase-keys: 7.0.2 camelcase-keys: 7.0.2
jose: 4.14.4 jose: 5.0.1
dev: true dev: true
/@logto/node@2.1.1: /@logto/node@2.2.0:
resolution: {integrity: sha512-joSzzAqaRKeEquRenoFrIXXkNxkJci5zSkk4afywz1P8tTcTysnV4eXaBmwXNpmDfQdtHBwRdSACZPLgeF8JiQ==} resolution: {integrity: sha512-xzVCnlrev/bqLtXOAw9I35h7njU1bed1jt6fL/VZfY4RUUJVZ36LG7fq2b7GsGg5xGRLchJ//+/VP1ac3+27YA==}
dependencies: dependencies:
'@logto/client': 2.1.0 '@logto/client': 2.3.0
'@silverhand/essentials': 2.8.4 '@silverhand/essentials': 2.8.5
js-base64: 3.7.5 js-base64: 3.7.5
node-fetch: 2.6.7 node-fetch: 2.7.0
transitivePeerDependencies: transitivePeerDependencies:
- encoding - encoding
dev: true dev: true
/@logto/react@2.1.0(react@18.2.0): /@logto/react@2.2.0(react@18.2.0):
resolution: {integrity: sha512-xP/EW/N7Fh/5yyogCavCf43U114hiuACGxWql8CTmCbSJEXKVU5kiHNQXi2upV7AvB+lNA1as7LT/KbR9wM/2Q==} resolution: {integrity: sha512-XSIptaw5o1mmflhG0eYD49aNBONfOIIjoyyam12qQOOfL2EFMZghIfaheh2SzemIT3LAawX2+yqAB/lo1rIGWA==}
peerDependencies: peerDependencies:
react: '>=16.8.0 || ^18.0.0' react: '>=16.8.0 || ^18.0.0'
dependencies: dependencies:
'@logto/browser': 2.1.0 '@logto/browser': 2.2.0
'@silverhand/essentials': 2.8.4 '@silverhand/essentials': 2.8.5
react: 18.2.0
dev: true
/@logto/react@2.1.2(react@18.2.0):
resolution: {integrity: sha512-4Fz5GG5N7y9ynYVutuLZgBornkVccaxG1vmAOxt233wfFPmNzESJ+TlYGe2FbngC7z9xfT6c7f9Q+1LZQmrzVg==}
peerDependencies:
react: '>=16.8.0 || ^18.0.0'
dependencies:
'@logto/browser': 2.1.2
'@silverhand/essentials': 2.8.4
react: 18.2.0 react: 18.2.0
dev: true dev: true
@ -15195,6 +15151,7 @@ packages:
/jose@4.14.4: /jose@4.14.4:
resolution: {integrity: sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==} resolution: {integrity: sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==}
dev: false
/jose@5.0.1: /jose@5.0.1:
resolution: {integrity: sha512-gRVzy7s3RRdGbXmcTdlOswJOjhwPLx1ijIgAqLY6ktzFpOJxxYn4l0fC2vHaHHi4YBX/5FOL3aY+6W0cvQgpug==} resolution: {integrity: sha512-gRVzy7s3RRdGbXmcTdlOswJOjhwPLx1ijIgAqLY6ktzFpOJxxYn4l0fC2vHaHHi4YBX/5FOL3aY+6W0cvQgpug==}
@ -16805,6 +16762,7 @@ packages:
optional: true optional: true
dependencies: dependencies:
whatwg-url: 5.0.0 whatwg-url: 5.0.0
dev: false
/node-fetch@2.7.0: /node-fetch@2.7.0:
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}