@robosystems/core 0.8.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,6 +17,20 @@ export interface SignInFormProps {
17
17
  * auth body) stays "Invalid email or password"; 5xx gets its own message.
18
18
  */
19
19
  export declare function loginErrorMessage(error: unknown): string;
20
+ /**
21
+ * Message for a login that verified the password but did not mint a session.
22
+ *
23
+ * The backend interposes a passkey step between password check and session
24
+ * (`mfa_required` for an enrolled user, `mfa_enrollment_required` for a
25
+ * privileged one under enforcement). This form implements no such step, so
26
+ * the flow ends here — and it must end *visibly*. Navigating on a sessionless
27
+ * response drops the user on a protected route that bounces them straight
28
+ * back to the login page, an unexplained loop.
29
+ *
30
+ * Deployments that enable passkeys need a login surface that carries the
31
+ * ceremony through; see the platform app's `MfaChallenge`.
32
+ */
33
+ export declare function mfaUnsupportedMessage(status?: string): string;
20
34
  /**
21
35
  * Messages for the `?reason=` a redirect into the login page can carry. The
22
36
  * producer is `AuthProvider`'s `logout(reason)`, which sends the user to
@@ -26,6 +26,25 @@ export function loginErrorMessage(error) {
26
26
  }
27
27
  return 'Invalid email or password';
28
28
  }
29
+ /**
30
+ * Message for a login that verified the password but did not mint a session.
31
+ *
32
+ * The backend interposes a passkey step between password check and session
33
+ * (`mfa_required` for an enrolled user, `mfa_enrollment_required` for a
34
+ * privileged one under enforcement). This form implements no such step, so
35
+ * the flow ends here — and it must end *visibly*. Navigating on a sessionless
36
+ * response drops the user on a protected route that bounces them straight
37
+ * back to the login page, an unexplained loop.
38
+ *
39
+ * Deployments that enable passkeys need a login surface that carries the
40
+ * ceremony through; see the platform app's `MfaChallenge`.
41
+ */
42
+ export function mfaUnsupportedMessage(status) {
43
+ if (status === 'mfa_enrollment_required') {
44
+ return 'This account must enroll a passkey before signing in, which this sign-in page cannot complete.';
45
+ }
46
+ return 'This account requires passkey verification to sign in, which this sign-in page cannot complete.';
47
+ }
29
48
  /**
30
49
  * Messages for the `?reason=` a redirect into the login page can carry. The
31
50
  * producer is `AuthProvider`'s `logout(reason)`, which sends the user to
@@ -125,6 +144,19 @@ export function SignInForm({ onSuccess, onRedirect, redirectTo = '/home', classN
125
144
  setError('');
126
145
  try {
127
146
  const result = await authClient.login(formData.email, formData.password);
147
+ // No session was minted — the backend is waiting on a passkey step this
148
+ // form cannot run. Stop here rather than redirecting into a route that
149
+ // will bounce straight back. `success` is false only for the MFA
150
+ // statuses; pre-MFA backends send no `status` and read as authenticated.
151
+ if (!result.success) {
152
+ if (process.env.NODE_ENV === 'development') {
153
+ console.error(`[SignInForm] login returned "${result.status}" — this component does not implement the passkey step. ` +
154
+ 'Use a sign-in surface that completes the MFA ceremony.');
155
+ }
156
+ setError(mfaUnsupportedMessage(result.status));
157
+ setLoading(false);
158
+ return;
159
+ }
128
160
  // Call onSuccess callback if provided
129
161
  if (onSuccess) {
130
162
  onSuccess(result.user);
@@ -579,8 +579,6 @@ export class RoboSystemsAuthClient {
579
579
  async getPasskeyRegistrationOptions(proof) {
580
580
  const response = await getPasskeyRegistrationOptions({
581
581
  client: this.client,
582
- // The proof fields land in client 1.11's generated request model;
583
- // until the regen they ride as extra JSON properties, hence the cast.
584
582
  body: {
585
583
  mfa_token: proof === null || proof === void 0 ? void 0 : proof.mfaToken,
586
584
  password: proof === null || proof === void 0 ? void 0 : proof.password,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robosystems/core",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "Shared RoboSystems frontend core library (auth, contexts, task monitoring, UI components) for the RoboSystems Next.js apps",
5
5
  "license": "MIT",
6
6
  "private": false,