Skip to content

Commit 1878085

Browse files
authored
fix(clerk-js,types): Add hasBeenFinalized to prevent null updates (#7118)
1 parent c08f08a commit 1878085

File tree

7 files changed

+54
-0
lines changed

7 files changed

+54
-0
lines changed

.changeset/shaky-books-occur.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,8 @@ class SignInFuture implements SignInFutureResource {
612612
verifyBackupCode: this.verifyBackupCode.bind(this),
613613
};
614614

615+
#hasBeenFinalized = false;
616+
615617
constructor(readonly resource: SignIn) {}
616618

617619
get id() {
@@ -667,6 +669,10 @@ class SignInFuture implements SignInFutureResource {
667669
return this.resource.secondFactorVerification;
668670
}
669671

672+
get hasBeenFinalized() {
673+
return this.#hasBeenFinalized;
674+
}
675+
670676
async sendResetPasswordEmailCode(): Promise<{ error: unknown }> {
671677
return runAsyncResourceTask(this.resource, async () => {
672678
if (!this.resource.id) {
@@ -1123,6 +1129,7 @@ class SignInFuture implements SignInFutureResource {
11231129
await SignIn.clerk.client.reload();
11241130
}
11251131

1132+
this.#hasBeenFinalized = true;
11261133
await SignIn.clerk.setActive({ session: this.resource.createdSessionId, navigate });
11271134
});
11281135
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,8 @@ class SignUpFuture implements SignUpFutureResource {
576576
verifyPhoneCode: this.verifyPhoneCode.bind(this),
577577
};
578578

579+
#hasBeenFinalized = false;
580+
579581
constructor(readonly resource: SignUp) {}
580582

581583
get id() {
@@ -676,6 +678,10 @@ class SignUpFuture implements SignUpFutureResource {
676678
return undefined;
677679
}
678680

681+
get hasBeenFinalized() {
682+
return this.#hasBeenFinalized;
683+
}
684+
679685
private async getCaptchaToken(): Promise<{
680686
captchaToken?: string;
681687
captchaWidgetType?: CaptchaWidgetType;
@@ -900,6 +906,7 @@ class SignUpFuture implements SignUpFutureResource {
900906
throw new Error('Cannot finalize sign-up without a created session.');
901907
}
902908

909+
this.#hasBeenFinalized = true;
903910
await SignUp.clerk.setActive({ session: this.resource.createdSessionId, navigate });
904911
});
905912
}

packages/clerk-js/src/core/state.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,18 @@ export class State implements StateInterface {
4848

4949
private onResourceUpdated = (payload: { resource: BaseResource }) => {
5050
if (payload.resource instanceof SignIn) {
51+
const previousResource = this.signInResourceSignal().resource;
52+
if (shouldIgnoreNullUpdate(previousResource, payload.resource)) {
53+
return;
54+
}
5155
this.signInResourceSignal({ resource: payload.resource });
5256
}
5357

5458
if (payload.resource instanceof SignUp) {
59+
const previousResource = this.signUpResourceSignal().resource;
60+
if (shouldIgnoreNullUpdate(previousResource, payload.resource)) {
61+
return;
62+
}
5563
this.signUpResourceSignal({ resource: payload.resource });
5664
}
5765
};
@@ -66,3 +74,13 @@ export class State implements StateInterface {
6674
}
6775
};
6876
}
77+
78+
/**
79+
* Returns true if the new resource is null and the previous resource has not been finalized. This is used to prevent
80+
* nullifying the resource after it's been completed.
81+
*/
82+
function shouldIgnoreNullUpdate(previousResource: SignIn | null, newResource: SignIn | null): boolean;
83+
function shouldIgnoreNullUpdate(previousResource: SignUp | null, newResource: SignUp | null): boolean;
84+
function shouldIgnoreNullUpdate(previousResource: SignIn | SignUp | null, newResource: SignIn | SignUp | null) {
85+
return !newResource?.id && previousResource && previousResource.__internal_future?.hasBeenFinalized === false;
86+
}

packages/react/src/stateProxy.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ export class StateProxy implements State {
105105
},
106106
});
107107
},
108+
get hasBeenFinalized() {
109+
return gateProperty(target, 'hasBeenFinalized', false);
110+
},
108111

109112
create: this.gateMethod(target, 'create'),
110113
password: this.gateMethod(target, 'password'),
@@ -207,6 +210,9 @@ export class StateProxy implements State {
207210
get isTransferable() {
208211
return gateProperty(target, 'isTransferable', false);
209212
},
213+
get hasBeenFinalized() {
214+
return gateProperty(target, 'hasBeenFinalized', false);
215+
},
210216

211217
create: gateMethod(target, 'create'),
212218
update: gateMethod(target, 'update'),

packages/shared/src/types/signInFuture.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,13 @@ export interface SignInFutureResource {
296296
*/
297297
readonly userData: UserData;
298298

299+
/**
300+
* Indicates that the sign-in has been finalized.
301+
*
302+
* @internal
303+
*/
304+
readonly hasBeenFinalized: boolean;
305+
299306
/**
300307
* Creates a new `SignIn` instance initialized with the provided parameters. The instance maintains the sign-in
301308
* lifecycle state through its `status` property, which updates as the authentication flow progresses.

packages/shared/src/types/signUpFuture.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,13 @@ export interface SignUpFutureResource {
354354
*/
355355
readonly locale: string | null;
356356

357+
/**
358+
* Indicates that the sign-up has been finalized.
359+
*
360+
* @internal
361+
*/
362+
readonly hasBeenFinalized: boolean;
363+
357364
/**
358365
* Creates a new `SignUp` instance initialized with the provided parameters. The instance maintains the sign-up
359366
* lifecycle state through its `status` property, which updates as the authentication flow progresses. Will also

0 commit comments

Comments
 (0)