Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/weak-deer-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@clerk/clerk-js': minor
'@clerk/clerk-react': minor
'@clerk/types': minor
---

[Experimental] Add support for additional properties to Signal SignIn/SignUp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export function SignIn({ className, ...props }: React.ComponentProps<'div'>) {
</CardHeader>
<CardContent>
<div className='grid gap-6'>
{signIn.availableStrategies
{signIn.supportedFirstFactors
.filter(({ strategy }) => strategy !== 'reset_password_email_code')
.map(({ strategy }) => (
<Button
Expand Down
26 changes: 25 additions & 1 deletion packages/clerk-js/src/core/resources/SignIn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -608,15 +608,35 @@ class SignInFuture implements SignInFutureResource {

constructor(readonly resource: SignIn) {}

get id() {
return this.resource.id;
}

get identifier() {
return this.resource.identifier;
}

get createdSessionId() {
return this.resource.createdSessionId;
}

get userData() {
return this.resource.userData;
}
Comment on lines +611 to +625
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add explicit return types and JSDoc comments for new public getters.

These new getters lack explicit return type annotations and JSDoc documentation. Per coding guidelines, public APIs should have explicit return types and comprehensive JSDoc comments.

Apply this diff to add return types and documentation:

+  /**
+   * The unique identifier for the current sign-in attempt.
+   */
-  get id() {
+  get id(): string | undefined {
     return this.resource.id;
   }

+  /**
+   * The identifier for the current sign-in attempt.
+   */
-  get identifier() {
+  get identifier(): string | null {
     return this.resource.identifier;
   }

+  /**
+   * The created session ID for the current sign-in attempt.
+   */
-  get createdSessionId() {
+  get createdSessionId(): string | null {
     return this.resource.createdSessionId;
   }

+  /**
+   * The user data for the current sign-in attempt.
+   */
-  get userData() {
+  get userData(): UserData {
     return this.resource.userData;
   }

As per coding guidelines.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
get id() {
return this.resource.id;
}
get identifier() {
return this.resource.identifier;
}
get createdSessionId() {
return this.resource.createdSessionId;
}
get userData() {
return this.resource.userData;
}
/**
* The unique identifier for the current sign-in attempt.
*/
get id(): string | undefined {
return this.resource.id;
}
/**
* The identifier for the current sign-in attempt.
*/
get identifier(): string | null {
return this.resource.identifier;
}
/**
* The created session ID for the current sign-in attempt.
*/
get createdSessionId(): string | null {
return this.resource.createdSessionId;
}
/**
* The user data for the current sign-in attempt.
*/
get userData(): UserData {
return this.resource.userData;
}
🤖 Prompt for AI Agents
In packages/clerk-js/src/core/resources/SignIn.ts around lines 611 to 625, the
four new public getters lack explicit return type annotations and JSDoc; update
each getter to declare its explicit return type (use the exact types from the
SignIn resource/interface—e.g., id: string | undefined, identifier: string |
undefined, createdSessionId: string | undefined, userData: Record<string,
unknown> | undefined—or the precise types defined on the SignIn resource) and
add a brief JSDoc block above each getter describing what the property
represents and its return type; reference the existing SignIn resource/interface
for exact type names and keep wording consistent with other resource getters.


get status() {
// @TODO hooks-revamp: Consolidate this fallback val with stateProxy
return this.resource.status || 'needs_identifier';
}

get availableStrategies() {
get supportedFirstFactors() {
return this.resource.supportedFirstFactors ?? [];
}

get supportedSecondFactors() {
return this.resource.supportedSecondFactors ?? [];
}
Comment on lines +632 to +638
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add explicit return type and JSDoc for supportedSecondFactors getter.

The new supportedSecondFactors getter is missing an explicit return type annotation and JSDoc documentation.

Apply this diff:

-  get supportedFirstFactors() {
+  get supportedFirstFactors(): SignInFirstFactor[] {
     return this.resource.supportedFirstFactors ?? [];
   }

+  /**
+   * The list of second-factor strategies that are available for the current sign-in attempt.
+   */
-  get supportedSecondFactors() {
+  get supportedSecondFactors(): SignInSecondFactor[] {
     return this.resource.supportedSecondFactors ?? [];
   }

As per coding guidelines.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
get supportedFirstFactors() {
return this.resource.supportedFirstFactors ?? [];
}
get supportedSecondFactors() {
return this.resource.supportedSecondFactors ?? [];
}
get supportedFirstFactors(): SignInFirstFactor[] {
return this.resource.supportedFirstFactors ?? [];
}
/**
* The list of second-factor strategies that are available for the current sign-in attempt.
*/
get supportedSecondFactors(): SignInSecondFactor[] {
return this.resource.supportedSecondFactors ?? [];
}
🤖 Prompt for AI Agents
In packages/clerk-js/src/core/resources/SignIn.ts around lines 632 to 638, the
supportedSecondFactors getter lacks an explicit return type and JSDoc; add a
JSDoc block describing the getter and its return value and give the getter the
same explicit return type as supportedFirstFactors (e.g., the appropriate array
type used by supportedFirstFactors) so the signature becomes documented and
type-annotated consistently with supportedFirstFactors.


get isTransferable() {
return this.resource.firstFactorVerification.status === 'transferable';
}
Expand All @@ -637,6 +657,10 @@ class SignInFuture implements SignInFutureResource {
return this.resource.firstFactorVerification;
}

get secondFactorVerification() {
return this.resource.secondFactorVerification;
}
Comment on lines +660 to +662
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add explicit return type and JSDoc for secondFactorVerification getter.

Missing explicit return type and documentation for this public getter.

Apply this diff:

+  /**
+   * The second-factor verification for the current sign-in attempt.
+   */
-  get secondFactorVerification() {
+  get secondFactorVerification(): VerificationResource {
     return this.resource.secondFactorVerification;
   }

As per coding guidelines.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
get secondFactorVerification() {
return this.resource.secondFactorVerification;
}
/**
* The second-factor verification for the current sign-in attempt.
*/
get secondFactorVerification(): VerificationResource {
return this.resource.secondFactorVerification;
}
🤖 Prompt for AI Agents
In packages/clerk-js/src/core/resources/SignIn.ts around lines 660 to 662, the
public getter secondFactorVerification is missing an explicit return type and
JSDoc; add a JSDoc block above the getter describing its purpose and usage and
add an explicit return type that matches the type of
this.resource.secondFactorVerification (e.g., the existing
SecondFactorVerificationResource type or its optional variant) and include an
@returns tag describing the returned resource.


async sendResetPasswordEmailCode(): Promise<{ error: unknown }> {
return runAsyncResourceTask(this.resource, async () => {
if (!this.resource.id) {
Expand Down
64 changes: 64 additions & 0 deletions packages/clerk-js/src/core/resources/SignUp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,11 +551,75 @@ class SignUpFuture implements SignUpFutureResource {

constructor(readonly resource: SignUp) {}

get id() {
return this.resource.id;
}

get requiredFields() {
return this.resource.requiredFields;
}

get optionalFields() {
return this.resource.optionalFields;
}

get missingFields() {
return this.resource.missingFields;
}

get status() {
// @TODO hooks-revamp: Consolidate this fallback val with stateProxy
return this.resource.status || 'missing_requirements';
}

get username() {
return this.resource.username;
}

get firstName() {
return this.resource.firstName;
}

get lastName() {
return this.resource.lastName;
}

get emailAddress() {
return this.resource.emailAddress;
}

get phoneNumber() {
return this.resource.phoneNumber;
}

get web3Wallet() {
return this.resource.web3wallet;
}

get hasPassword() {
return this.resource.hasPassword;
}

get unsafeMetadata() {
return this.resource.unsafeMetadata;
}

get createdSessionId() {
return this.resource.createdSessionId;
}

get createdUserId() {
return this.resource.createdUserId;
}

get abandonAt() {
return this.resource.abandonAt;
}

get legalAcceptedAt() {
return this.resource.legalAcceptedAt;
}

get unverifiedFields() {
return this.resource.unverifiedFields;
}
Expand Down
87 changes: 87 additions & 0 deletions packages/react/src/stateProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,45 @@ export class StateProxy implements State {
status: 'needs_identifier' as const,
availableStrategies: [],
isTransferable: false,
get id() {
return gateProperty(target, 'id', undefined);
},
get supportedFirstFactors() {
return gateProperty(target, 'supportedFirstFactors', []);
},
get supportedSecondFactors() {
return gateProperty(target, 'supportedSecondFactors', []);
},
get secondFactorVerification() {
return gateProperty(target, 'secondFactorVerification', {
status: null,
error: null,
expireAt: null,
externalVerificationRedirectURL: null,
nonce: null,
attempts: null,
message: null,
strategy: null,
verifiedAtClient: null,
verifiedFromTheSameClient: () => false,
__internal_toSnapshot: () => {
throw new Error('__internal_toSnapshot called before Clerk is loaded');
},
pathRoot: '',
reload: () => {
throw new Error('__internal_toSnapshot called before Clerk is loaded');
},
});
Comment on lines +57 to +76
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix error messages in secondFactorVerification default object.

The error messages on lines 70 and 74 are incorrect. Line 70 throws for __internal_toSnapshot but line 74 throws the same message for reload.

Apply this diff:

            __internal_toSnapshot: () => {
              throw new Error('__internal_toSnapshot called before Clerk is loaded');
            },
            pathRoot: '',
            reload: () => {
-             throw new Error('__internal_toSnapshot called before Clerk is loaded');
+             throw new Error('reload called before Clerk is loaded');
            },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
get secondFactorVerification() {
return gateProperty(target, 'secondFactorVerification', {
status: null,
error: null,
expireAt: null,
externalVerificationRedirectURL: null,
nonce: null,
attempts: null,
message: null,
strategy: null,
verifiedAtClient: null,
verifiedFromTheSameClient: () => false,
__internal_toSnapshot: () => {
throw new Error('__internal_toSnapshot called before Clerk is loaded');
},
pathRoot: '',
reload: () => {
throw new Error('__internal_toSnapshot called before Clerk is loaded');
},
});
get secondFactorVerification() {
return gateProperty(target, 'secondFactorVerification', {
status: null,
error: null,
expireAt: null,
externalVerificationRedirectURL: null,
nonce: null,
attempts: null,
message: null,
strategy: null,
verifiedAtClient: null,
verifiedFromTheSameClient: () => false,
__internal_toSnapshot: () => {
throw new Error('__internal_toSnapshot called before Clerk is loaded');
},
pathRoot: '',
reload: () => {
throw new Error('reload called before Clerk is loaded');
},
});
}
🤖 Prompt for AI Agents
In packages/react/src/stateProxy.ts around lines 57 to 76, the default
secondFactorVerification object uses the same error message for both
__internal_toSnapshot and reload; update the reload throw to a descriptive
message (e.g., throw new Error('reload called before Clerk is loaded')) instead
of duplicating the __internal_toSnapshot message so each function reports the
correct error context.

},
get identifier() {
return gateProperty(target, 'identifier', null);
},
get createdSessionId() {
return gateProperty(target, 'createdSessionId', null);
},
get userData() {
return gateProperty(target, 'userData', {});
},
get firstFactorVerification() {
return gateProperty(target, 'firstFactorVerification', {
status: null,
Expand Down Expand Up @@ -107,6 +146,54 @@ export class StateProxy implements State {
errors: defaultErrors(),
fetchStatus: 'idle' as const,
signUp: {
get id() {
return gateProperty(target, 'id', undefined);
},
get requiredFields() {
return gateProperty(target, 'requiredFields', []);
},
get optionalFields() {
return gateProperty(target, 'optionalFields', []);
},
get missingFields() {
return gateProperty(target, 'missingFields', []);
},
get username() {
return gateProperty(target, 'username', null);
},
get firstName() {
return gateProperty(target, 'firstName', null);
},
get lastName() {
return gateProperty(target, 'lastName', null);
},
get emailAddress() {
return gateProperty(target, 'emailAddress', null);
},
get phoneNumber() {
return gateProperty(target, 'phoneNumber', null);
},
get web3Wallet() {
return gateProperty(target, 'web3Wallet', null);
},
get hasPassword() {
return gateProperty(target, 'hasPassword', false);
},
get unsafeMetadata() {
return gateProperty(target, 'unsafeMetadata', {});
},
get createdSessionId() {
return gateProperty(target, 'createdSessionId', null);
},
get createdUserId() {
return gateProperty(target, 'createdUserId', null);
},
get abandonAt() {
return gateProperty(target, 'abandonAt', null);
},
get legalAcceptedAt() {
return gateProperty(target, 'legalAcceptedAt', null);
},
get status() {
return gateProperty(target, 'status', 'missing_requirements');
},
Expand Down
34 changes: 32 additions & 2 deletions packages/types/src/signInFuture.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { SetActiveNavigate } from './clerk';
import type { PhoneCodeChannel } from './phoneCodeChannel';
import type { SignInFirstFactor, SignInStatus } from './signInCommon';
import type { SignInFirstFactor, SignInSecondFactor, SignInStatus, UserData } from './signInCommon';
import type { OAuthStrategy, Web3Strategy } from './strategies';
import type { VerificationResource } from './verification';

Expand Down Expand Up @@ -127,10 +127,20 @@ export interface SignInFutureFinalizeParams {
* The current active `SignIn` instance, for use in custom flows.
*/
export interface SignInFutureResource {
/**
* The unique identifier for the current sign-in attempt.
*/
readonly id?: string;

/**
* The list of first-factor strategies that are available for the current sign-in attempt.
*/
readonly availableStrategies: SignInFirstFactor[];
readonly supportedFirstFactors: SignInFirstFactor[];

/**
* The list of second-factor strategies that are available for the current sign-in attempt.
*/
readonly supportedSecondFactors: SignInSecondFactor[];

/**
* The status of the current sign-in attempt as a string (for example, `'needs_identifier'`, `'needs_first_factor'`,
Expand All @@ -148,6 +158,26 @@ export interface SignInFutureResource {

readonly firstFactorVerification: VerificationResource;

/**
* The second-factor verification for the current sign-in attempt.
*/
readonly secondFactorVerification: VerificationResource;

/**
* The identifier for the current sign-in attempt.
*/
readonly identifier: string | null;

/**
* The created session ID for the current sign-in attempt.
*/
readonly createdSessionId: string | null;

/**
* The user data for the current sign-in attempt.
*/
readonly userData: UserData;

/**
* Used to supply an identifier for the sign-in attempt. Calling this method will populate data on the sign-in
* attempt, such as `signIn.resource.supportedFirstFactors`.
Expand Down
46 changes: 45 additions & 1 deletion packages/types/src/signUpFuture.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { SetActiveNavigate } from './clerk';
import type { PhoneCodeChannel } from './phoneCodeChannel';
import type { SignUpIdentificationField, SignUpStatus } from './signUpCommon';
import type { SignUpField, SignUpIdentificationField, SignUpStatus } from './signUpCommon';
import type { Web3Strategy } from './strategies';

interface SignUpFutureAdditionalParams {
Expand Down Expand Up @@ -71,11 +71,31 @@ export interface SignUpFutureFinalizeParams {
* The current active `SignUp` instance, for use in custom flows.
*/
export interface SignUpFutureResource {
/**
* The unique identifier for the current sign-up attempt.
*/
readonly id?: string;

/**
* The status of the current sign-up attempt as a string (for example, `'missing_requirements'`, `'complete'`, `'abandoned'`, etc.)
*/
readonly status: SignUpStatus;

/**
* The list of required fields for the current sign-up attempt.
*/
readonly requiredFields: SignUpField[];

/**
* The list of optional fields for the current sign-up attempt.
*/
readonly optionalFields: SignUpField[];

/**
* The list of missing fields for the current sign-up attempt.
*/
readonly missingFields: SignUpField[];

/**
* An array of strings representing unverified fields such as `’email_address’`. Can be used to detect when verification is necessary.
*/
Expand All @@ -89,6 +109,30 @@ export interface SignUpFutureResource {

readonly existingSession?: { sessionId: string };

readonly username: string | null;

readonly firstName: string | null;

readonly lastName: string | null;

readonly emailAddress: string | null;

readonly phoneNumber: string | null;

readonly web3Wallet: string | null;

readonly hasPassword: boolean;

readonly unsafeMetadata: SignUpUnsafeMetadata;

readonly createdSessionId: string | null;

readonly createdUserId: string | null;

readonly abandonAt: number | null;

readonly legalAcceptedAt: number | null;

create: (params: SignUpFutureCreateParams) => Promise<{ error: unknown }>;

update: (params: SignUpFutureUpdateParams) => Promise<{ error: unknown }>;
Expand Down