Skip to content

Commit 5f49568

Browse files
authored
fix(clerk-js): Emit session when permissions or role of the active memberships change (#2073)
* fix(clerk-js): Emit session when permissions or role of the active memberships change * chore(clerk-js): Add changeset
1 parent 3bdee6e commit 5f49568

File tree

3 files changed

+72
-24
lines changed

3 files changed

+72
-24
lines changed

.changeset/dry-students-reflect.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
---
4+
5+
Emit session when permissions or role of the active memberships change.

packages/clerk-js/src/core/resources/Organization.ts

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
GetInvitationsParams,
99
GetMembershipRequestParams,
1010
GetMemberships,
11+
GetMembershipsParams,
1112
GetPendingInvitationsParams,
1213
GetRolesParams,
1314
InviteMemberParams,
@@ -26,7 +27,6 @@ import type {
2627
UpdateMembershipParams,
2728
UpdateOrganizationParams,
2829
} from '@clerk/types';
29-
import type { GetMembershipsParams } from '@clerk/types';
3030

3131
import { unixEpochToDate } from '../../utils/date';
3232
import { convertPageToOffset } from '../../utils/pagesToOffset';
@@ -109,11 +109,16 @@ export class Organization extends BaseResource implements OrganizationResource {
109109
};
110110

111111
getRoles = async (getRolesParams?: GetRolesParams) => {
112-
return await BaseResource._fetch({
113-
path: `/organizations/${this.id}/roles`,
114-
method: 'GET',
115-
search: convertPageToOffset(getRolesParams) as any,
116-
}).then(res => {
112+
return await BaseResource._fetch(
113+
{
114+
path: `/organizations/${this.id}/roles`,
115+
method: 'GET',
116+
search: convertPageToOffset(getRolesParams) as any,
117+
},
118+
{
119+
forceUpdateClient: true,
120+
},
121+
).then(res => {
117122
const { data: roles, total_count } = res?.response as unknown as ClerkPaginatedResponse<RoleJSON>;
118123

119124
return {
@@ -126,11 +131,16 @@ export class Organization extends BaseResource implements OrganizationResource {
126131
getDomains = async (
127132
getDomainParams?: GetDomainsParams,
128133
): Promise<ClerkPaginatedResponse<OrganizationDomainResource>> => {
129-
return await BaseResource._fetch({
130-
path: `/organizations/${this.id}/domains`,
131-
method: 'GET',
132-
search: convertPageToOffset(getDomainParams) as any,
133-
})
134+
return await BaseResource._fetch(
135+
{
136+
path: `/organizations/${this.id}/domains`,
137+
method: 'GET',
138+
search: convertPageToOffset(getDomainParams) as any,
139+
},
140+
{
141+
forceUpdateClient: true,
142+
},
143+
)
134144
.then(res => {
135145
const { data: invites, total_count } =
136146
res?.response as unknown as ClerkPaginatedResponse<OrganizationDomainJSON>;
@@ -197,13 +207,18 @@ export class Organization extends BaseResource implements OrganizationResource {
197207
deprecated('offset', 'Use `initialPage` instead in Organization.limit.', 'organization:getMemberships:offset');
198208
}
199209

200-
return await BaseResource._fetch({
201-
path: `/organizations/${this.id}/memberships`,
202-
method: 'GET',
203-
search: isDeprecatedParams
204-
? getMembershipsParams
205-
: (convertPageToOffset(getMembershipsParams as unknown as any) as any),
206-
})
210+
return await BaseResource._fetch(
211+
{
212+
path: `/organizations/${this.id}/memberships`,
213+
method: 'GET',
214+
search: isDeprecatedParams
215+
? getMembershipsParams
216+
: (convertPageToOffset(getMembershipsParams as unknown as any) as any),
217+
},
218+
{
219+
forceUpdateClient: true,
220+
},
221+
)
207222
.then(res => {
208223
if (isDeprecatedParams) {
209224
const organizationMembershipsJSON = res?.response as unknown as OrganizationMembershipJSON[];
@@ -248,11 +263,16 @@ export class Organization extends BaseResource implements OrganizationResource {
248263
getInvitations = async (
249264
getInvitationsParams?: GetInvitationsParams,
250265
): Promise<ClerkPaginatedResponse<OrganizationInvitationResource>> => {
251-
return await BaseResource._fetch({
252-
path: `/organizations/${this.id}/invitations`,
253-
method: 'GET',
254-
search: convertPageToOffset(getInvitationsParams) as any,
255-
})
266+
return await BaseResource._fetch(
267+
{
268+
path: `/organizations/${this.id}/invitations`,
269+
method: 'GET',
270+
search: convertPageToOffset(getInvitationsParams) as any,
271+
},
272+
{
273+
forceUpdateClient: true,
274+
},
275+
)
256276
.then(res => {
257277
const { data: requests, total_count } =
258278
res?.response as unknown as ClerkPaginatedResponse<OrganizationInvitationJSON>;

packages/clerk-js/src/utils/memoizeStateListenerCallback.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ function clientChanged(prev: ClientResource, next: ClientResource): boolean {
2828
}
2929

3030
function sessionChanged(prev: SessionResource, next: SessionResource): boolean {
31-
return prev.id !== next.id || prev.updatedAt.getTime() < next.updatedAt.getTime();
31+
return (
32+
prev.id !== next.id ||
33+
prev.updatedAt.getTime() < next.updatedAt.getTime() ||
34+
sessionUserMembershipPermissionsChanged(next, prev)
35+
);
3236
}
3337

3438
function userChanged(prev: UserResource, next: UserResource): boolean {
@@ -45,6 +49,25 @@ function userMembershipsChanged(prev: UserResource, next: UserResource): boolean
4549
);
4650
}
4751

52+
function sessionUserMembershipPermissionsChanged(prev: SessionResource, next: SessionResource): boolean {
53+
if (prev.lastActiveOrganizationId !== next.lastActiveOrganizationId) {
54+
return true;
55+
}
56+
57+
const prevActiveMembership = prev.user?.organizationMemberships?.find(
58+
mem => mem.organization.id === prev.lastActiveOrganizationId,
59+
);
60+
61+
const nextActiveMembership = next.user?.organizationMemberships?.find(
62+
mem => mem.organization.id === prev.lastActiveOrganizationId,
63+
);
64+
65+
return (
66+
prevActiveMembership?.role !== nextActiveMembership?.role ||
67+
prevActiveMembership?.permissions?.length !== nextActiveMembership?.permissions?.length
68+
);
69+
}
70+
4871
// TODO: Decide if this belongs in the resources
4972
function resourceChanged<T extends AcceptedResource | undefined | null>(prev: T, next: T): boolean {
5073
// support the setSession undefined intermediate state

0 commit comments

Comments
 (0)