Skip to content

Commit

Permalink
fix(clerk-js,types): Remove experimental from checkAuthorization
Browse files Browse the repository at this point in the history
  • Loading branch information
panteliselef committed Dec 11, 2023
1 parent a4aa0e7 commit 24efeec
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 73 deletions.
4 changes: 2 additions & 2 deletions packages/clerk-js/src/core/resources/Session.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('Session', () => {
updated_at: new Date().getTime(),
} as SessionJSON);

const isAuthorized = await session.experimental__checkAuthorization({ permission: 'org:sys_profile:delete' });
const isAuthorized = await session.checkAuthorization({ permission: 'org:sys_profile:delete' });

expect(isAuthorized).toBe(true);
});
Expand All @@ -93,7 +93,7 @@ describe('Session', () => {
updated_at: new Date().getTime(),
} as SessionJSON);

const isAuthorized = await session.experimental__checkAuthorization({ permission: 'org:sys_profile:delete' });
const isAuthorized = await session.checkAuthorization({ permission: 'org:sys_profile:delete' });

expect(isAuthorized).toBe(false);
});
Expand Down
17 changes: 1 addition & 16 deletions packages/clerk-js/src/core/resources/Session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,7 @@ export class Session extends BaseResource implements SessionResource {
});
};

/**
* @experimental The method is experimental and subject to change in future releases.
*/
experimental__checkAuthorization: CheckAuthorization = params => {
checkAuthorization: CheckAuthorization = params => {
// if there is no active organization user can not be authorized
if (!this.lastActiveOrganizationId || !this.user) {
return false;
Expand All @@ -103,18 +100,6 @@ export class Session extends BaseResource implements SessionResource {
return activeOrganizationRole === params.role;
}

if (params.some) {
return !!params.some.find(permObj => {
if (permObj.permission) {
return activeOrganizationPermissions.includes(permObj.permission);
}
if (permObj.role) {
return activeOrganizationRole === permObj.role;
}
return false;
});
}

return false;
};

Expand Down
42 changes: 37 additions & 5 deletions packages/clerk-js/src/ui.retheme/common/Gate.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
import { useSession } from '@clerk/shared/react';
import type { CheckAuthorization } from '@clerk/types';
import type { CheckAuthorization, MembershipRole, OrganizationPermissionKey } from '@clerk/types';
import type { ComponentType, PropsWithChildren, ReactNode } from 'react';
import React, { useEffect } from 'react';

import { useRouter } from '../router';

type GateParams = Parameters<CheckAuthorization>[0];
type GateParams = Parameters<CheckAuthorization>[0] | ((has: CheckAuthorization) => boolean);
type GateProps = PropsWithChildren<
GateParams & {
(
| {
condition?: never;
role: MembershipRole;
permission?: never;
}
| {
condition?: never;
role?: never;
permission: OrganizationPermissionKey;
}
| {
condition: (has: CheckAuthorization) => boolean;
role?: never;
permission?: never;
}
) & {
fallback?: ReactNode;
redirectTo?: string;
}
Expand All @@ -16,15 +32,31 @@ type GateProps = PropsWithChildren<
export const useGate = (params: GateParams) => {
const { session } = useSession();

if (!session?.id) {
return { isAuthorizedUser: false };
}

/**
* if a function is passed and returns false then throw not found
*/
if (typeof params === 'function') {
if (params(session.checkAuthorization)) {
return { isAuthorizedUser: true };
}
return { isAuthorizedUser: false };
}

return {
isAuthorizedUser: session?.experimental__checkAuthorization(params),
isAuthorizedUser: session?.checkAuthorization(params),
};
};

export const Gate = (gateProps: GateProps) => {
const { children, fallback, redirectTo, ...restAuthorizedParams } = gateProps;

const { isAuthorizedUser } = useGate(restAuthorizedParams);
const { isAuthorizedUser } = useGate(
typeof restAuthorizedParams.condition === 'function' ? restAuthorizedParams.condition : restAuthorizedParams,
);

const { navigate } = useRouter();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,12 @@ export const OrganizationProfileNavbar = (
const { organization } = useOrganization();
const { pages } = useOrganizationProfileContext();

const { isAuthorizedUser: allowMembersRoute } = useGate({
some: [
{
const { isAuthorizedUser: allowMembersRoute } = useGate(
has =>
has({
permission: 'org:sys_memberships:read',
},
{
permission: 'org:sys_memberships:manage',
},
],
});
}) || has({ permission: 'org:sys_memberships:manage' }),
);

if (!organization) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export const OrganizationProfileRoutes = (props: PropsOfComponent<typeof Profile
</Route>
<Route path=':id'>
<Gate
some={[{ permission: 'org:sys_domains:manage' }, { permission: 'org:sys_domains:delete' }]}
permission='org:sys_domains:manage'
redirectTo='../../'
>
<VerifiedDomainPage />
Expand Down Expand Up @@ -130,8 +130,10 @@ export const OrganizationProfileRoutes = (props: PropsOfComponent<typeof Profile
</Route>
<Route index>
<Gate
some={[{ permission: 'org:sys_memberships:read' }, { permission: 'org:sys_memberships:manage' }]}
redirectTo='./organization-settings'
condition={has =>
has({ permission: 'org:sys_memberships:read' }) || has({ permission: 'org:sys_memberships:manage' })
}
redirectTo={isSettingsPageRoot ? '../' : './organization-settings'}
>
<OrganizationMembers />
</Gate>
Expand Down
2 changes: 1 addition & 1 deletion packages/clerk-js/src/ui.retheme/utils/test/mockHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const mockClerkMethods = (clerk: LoadedClerk): DeepJestMocked<LoadedClerk
mockMethodsOf(clerk.client.signUp);
clerk.client.sessions.forEach(session => {
mockMethodsOf(session, {
exclude: ['experimental__checkAuthorization'],
exclude: ['checkAuthorization'],
});
mockMethodsOf(session.user);
session.user?.emailAddresses.forEach(m => mockMethodsOf(m));
Expand Down
42 changes: 37 additions & 5 deletions packages/clerk-js/src/ui/common/Gate.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
import { useSession } from '@clerk/shared/react';
import type { CheckAuthorization } from '@clerk/types';
import type { CheckAuthorization, MembershipRole, OrganizationPermissionKey } from '@clerk/types';
import type { ComponentType, PropsWithChildren, ReactNode } from 'react';
import React, { useEffect } from 'react';

import { useRouter } from '../router';

type GateParams = Parameters<CheckAuthorization>[0];
type GateParams = Parameters<CheckAuthorization>[0] | ((has: CheckAuthorization) => boolean);
type GateProps = PropsWithChildren<
GateParams & {
(
| {
condition?: never;
role: MembershipRole;
permission?: never;
}
| {
condition?: never;
role?: never;
permission: OrganizationPermissionKey;
}
| {
condition: (has: CheckAuthorization) => boolean;
role?: never;
permission?: never;
}
) & {
fallback?: ReactNode;
redirectTo?: string;
}
Expand All @@ -16,15 +32,31 @@ type GateProps = PropsWithChildren<
export const useGate = (params: GateParams) => {
const { session } = useSession();

if (!session?.id) {
return { isAuthorizedUser: false };
}

/**
* if a function is passed and returns false then throw not found
*/
if (typeof params === 'function') {
if (params(session.checkAuthorization)) {
return { isAuthorizedUser: true };
}
return { isAuthorizedUser: false };
}

return {
isAuthorizedUser: session?.experimental__checkAuthorization(params),
isAuthorizedUser: session?.checkAuthorization(params),
};
};

export const Gate = (gateProps: GateProps) => {
const { children, fallback, redirectTo, ...restAuthorizedParams } = gateProps;

const { isAuthorizedUser } = useGate(restAuthorizedParams);
const { isAuthorizedUser } = useGate(
typeof restAuthorizedParams.condition === 'function' ? restAuthorizedParams.condition : restAuthorizedParams,
);

const { navigate } = useRouter();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,12 @@ export const OrganizationProfileNavbar = (
const { organization } = useOrganization();
const { pages } = useOrganizationProfileContext();

const { isAuthorizedUser: allowMembersRoute } = useGate({
some: [
{
const { isAuthorizedUser: allowMembersRoute } = useGate(
has =>
has({
permission: 'org:sys_memberships:read',
},
{
permission: 'org:sys_memberships:manage',
},
],
});
}) || has({ permission: 'org:sys_memberships:manage' }),
);

if (!organization) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export const OrganizationProfileRoutes = (props: PropsOfComponent<typeof Profile
</Route>
<Route path=':id'>
<Gate
some={[{ permission: 'org:sys_domains:manage' }, { permission: 'org:sys_domains:delete' }]}
permission='org:sys_domains:manage'
redirectTo='../../'
>
<VerifiedDomainPage />
Expand Down Expand Up @@ -130,7 +130,9 @@ export const OrganizationProfileRoutes = (props: PropsOfComponent<typeof Profile
</Route>
<Route index>
<Gate
some={[{ permission: 'org:sys_memberships:read' }, { permission: 'org:sys_memberships:manage' }]}
condition={has =>
has({ permission: 'org:sys_memberships:read' }) || has({ permission: 'org:sys_memberships:manage' })
}
redirectTo={isSettingsPageRoot ? '../' : './organization-settings'}
>
<OrganizationMembers />
Expand Down
2 changes: 1 addition & 1 deletion packages/clerk-js/src/ui/utils/test/mockHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const mockClerkMethods = (clerk: LoadedClerk): DeepJestMocked<LoadedClerk
mockMethodsOf(clerk.client.signUp);
clerk.client.sessions.forEach(session => {
mockMethodsOf(session, {
exclude: ['experimental__checkAuthorization'],
exclude: ['checkAuthorization'],
});
mockMethodsOf(session.user);
session.user?.emailAddresses.forEach(m => mockMethodsOf(m));
Expand Down
21 changes: 1 addition & 20 deletions packages/types/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,10 @@ export type CheckAuthorization = CheckAuthorizationFn<CheckAuthorizationParams>;

type CheckAuthorizationParams =
| {
some: (
| {
role: MembershipRole;
permission?: never;
}
| {
role?: never;
permission: OrganizationPermissionKey;
}
)[];
role?: never;
permission?: never;
}
| {
some?: never;
role: MembershipRole;
permission?: never;
}
| {
some?: never;
role?: never;
permission: OrganizationPermissionKey;
};
Expand All @@ -67,10 +51,7 @@ export interface SessionResource extends ClerkResource {
remove: () => Promise<SessionResource>;
touch: () => Promise<SessionResource>;
getToken: GetToken;
/**
* @experimental The method is experimental and subject to change in future releases.
*/
experimental__checkAuthorization: CheckAuthorization;
checkAuthorization: CheckAuthorization;
clearCache: () => void;
createdAt: Date;
updatedAt: Date;
Expand Down

0 comments on commit 24efeec

Please sign in to comment.