@shipfox/client-auth 4.0.0 → 5.0.0

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.
Files changed (84) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +13 -0
  3. package/dist/components/email-code-verification.d.ts.map +1 -1
  4. package/dist/components/email-code-verification.js +1 -1
  5. package/dist/components/email-code-verification.js.map +1 -1
  6. package/dist/components/workspace-switcher.stories.d.ts +1 -1
  7. package/dist/continuation.d.ts +1 -1
  8. package/dist/continuation.d.ts.map +1 -1
  9. package/dist/continuation.js +1 -1
  10. package/dist/continuation.js.map +1 -1
  11. package/dist/hooks/api/auth-mapper.d.ts +21 -0
  12. package/dist/hooks/api/auth-mapper.d.ts.map +1 -0
  13. package/dist/hooks/api/auth-mapper.js +25 -0
  14. package/dist/hooks/api/auth-mapper.js.map +1 -0
  15. package/dist/hooks/api/login-auth.d.ts +3 -25
  16. package/dist/hooks/api/login-auth.d.ts.map +1 -1
  17. package/dist/hooks/api/login-auth.js +5 -2
  18. package/dist/hooks/api/login-auth.js.map +1 -1
  19. package/dist/hooks/api/password-reset-auth.d.ts +3 -25
  20. package/dist/hooks/api/password-reset-auth.d.ts.map +1 -1
  21. package/dist/hooks/api/password-reset-auth.js +5 -2
  22. package/dist/hooks/api/password-reset-auth.js.map +1 -1
  23. package/dist/hooks/api/signup-auth.d.ts +1 -25
  24. package/dist/hooks/api/signup-auth.d.ts.map +1 -1
  25. package/dist/hooks/api/signup-auth.js +5 -2
  26. package/dist/hooks/api/signup-auth.js.map +1 -1
  27. package/dist/hooks/api/verify-email-auth.d.ts +1 -12
  28. package/dist/hooks/api/verify-email-auth.d.ts.map +1 -1
  29. package/dist/hooks/api/verify-email-auth.js +6 -3
  30. package/dist/hooks/api/verify-email-auth.js.map +1 -1
  31. package/dist/hooks/api/workspace-auth.d.ts +3 -17
  32. package/dist/hooks/api/workspace-auth.d.ts.map +1 -1
  33. package/dist/hooks/api/workspace-auth.js +5 -2
  34. package/dist/hooks/api/workspace-auth.js.map +1 -1
  35. package/dist/hooks/api/workspace-mapper.d.ts +8 -0
  36. package/dist/hooks/api/workspace-mapper.d.ts.map +1 -0
  37. package/dist/hooks/api/workspace-mapper.js +9 -0
  38. package/dist/hooks/api/workspace-mapper.js.map +1 -0
  39. package/dist/index.d.ts +0 -1
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +0 -1
  42. package/dist/index.js.map +1 -1
  43. package/dist/pages/invitation-context.d.ts +9 -14
  44. package/dist/pages/invitation-context.d.ts.map +1 -1
  45. package/dist/pages/invitation-context.js +4 -27
  46. package/dist/pages/invitation-context.js.map +1 -1
  47. package/dist/pages/login-page.js +2 -2
  48. package/dist/pages/login-page.js.map +1 -1
  49. package/dist/pages/logout-page.js +1 -1
  50. package/dist/pages/logout-page.js.map +1 -1
  51. package/dist/pages/password-reset-page.d.ts.map +1 -1
  52. package/dist/pages/password-reset-page.js +1 -4
  53. package/dist/pages/password-reset-page.js.map +1 -1
  54. package/dist/pages/signup-page.js +9 -9
  55. package/dist/pages/signup-page.js.map +1 -1
  56. package/dist/tsconfig.test.tsbuildinfo +1 -1
  57. package/package.json +4 -3
  58. package/src/components/email-code-verification.tsx +1 -1
  59. package/src/continuation.ts +1 -1
  60. package/src/hooks/api/auth-mapper.test.ts +77 -0
  61. package/src/hooks/api/auth-mapper.ts +39 -0
  62. package/src/hooks/api/login-auth.test.ts +1 -1
  63. package/src/hooks/api/login-auth.ts +8 -3
  64. package/src/hooks/api/password-reset-auth.test.ts +1 -1
  65. package/src/hooks/api/password-reset-auth.ts +15 -9
  66. package/src/hooks/api/signup-auth.ts +8 -3
  67. package/src/hooks/api/verify-email-auth.ts +17 -11
  68. package/src/hooks/api/workspace-auth.ts +8 -3
  69. package/src/hooks/api/workspace-mapper.test.ts +21 -0
  70. package/src/hooks/api/workspace-mapper.ts +11 -0
  71. package/src/index.ts +0 -1
  72. package/src/pages/invitation-context.ts +8 -31
  73. package/src/pages/login-page.test.tsx +1 -1
  74. package/src/pages/login-page.tsx +2 -2
  75. package/src/pages/logout-page.tsx +1 -1
  76. package/src/pages/password-reset-page.tsx +1 -4
  77. package/src/pages/signup-page.test.tsx +1 -1
  78. package/src/pages/signup-page.tsx +9 -9
  79. package/tsconfig.build.tsbuildinfo +1 -1
  80. package/dist/components/auth-shell.d.ts +0 -13
  81. package/dist/components/auth-shell.d.ts.map +0 -1
  82. package/dist/components/auth-shell.js +0 -68
  83. package/dist/components/auth-shell.js.map +0 -1
  84. package/src/components/auth-shell.tsx +0 -68
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shipfox/client-auth",
3
3
  "license": "MIT",
4
- "version": "4.0.0",
4
+ "version": "5.0.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/ShipfoxHQ/shipfox.git",
@@ -36,9 +36,10 @@
36
36
  "@swc/helpers": "^0.5.17",
37
37
  "@tanstack/react-form": "^1.32.0",
38
38
  "@shipfox/api-auth-dto": "7.1.0",
39
- "@shipfox/api-workspaces-dto": "6.0.0",
40
39
  "@shipfox/client-api": "4.0.0",
41
- "@shipfox/client-shell": "4.0.0",
40
+ "@shipfox/api-workspaces-dto": "6.0.0",
41
+ "@shipfox/client-invitations": "5.0.0",
42
+ "@shipfox/client-shell": "5.0.0",
42
43
  "@shipfox/client-ui": "4.0.0",
43
44
  "@shipfox/react-ui": "0.3.5"
44
45
  },
@@ -1,10 +1,10 @@
1
+ import {AuthShell} from '@shipfox/client-shell/runtime';
1
2
  import {Button} from '@shipfox/react-ui/button';
2
3
  import {Callout} from '@shipfox/react-ui/callout';
3
4
  import {FormField, FormFieldInput} from '@shipfox/react-ui/form-field';
4
5
  import type {HeaderProps} from '@shipfox/react-ui/typography';
5
6
  import type {FormEvent, ReactNode, Ref} from 'react';
6
7
  import {useCallback, useEffect, useRef, useState} from 'react';
7
- import {AuthShell} from './auth-shell.js';
8
8
 
9
9
  const EIGHT_DIGIT_CODE_RE = /^\d{8}$/u;
10
10
 
@@ -1,4 +1,4 @@
1
- export {AuthActions, AuthShell, type AuthShellProps} from './components/auth-shell.js';
1
+ export {AuthActions, AuthShell, type AuthShellProps} from '@shipfox/client-shell/runtime';
2
2
  export {
3
3
  EmailCodeVerification,
4
4
  type EmailCodeVerificationProps,
@@ -0,0 +1,77 @@
1
+ import type {SignupResponseDto} from '@shipfox/api-auth-dto';
2
+ import {toSignupResult} from './auth-mapper.js';
3
+
4
+ const baseUser: SignupResponseDto['user'] = {
5
+ id: '11111111-1111-4111-8111-111111111111',
6
+ email: 'signup@example.com',
7
+ name: null,
8
+ email_verified_at: null,
9
+ status: 'active',
10
+ created_at: '2026-04-27T00:00:00.000Z',
11
+ updated_at: '2026-04-27T00:00:00.000Z',
12
+ };
13
+
14
+ describe('toSignupResult', () => {
15
+ test('maps only the user when no challenge, membership, or accept error is present', () => {
16
+ const result = toSignupResult({user: baseUser});
17
+
18
+ expect(result).toEqual({user: {id: baseUser.id, email: baseUser.email}});
19
+ });
20
+
21
+ test('maps the user name and email verification when present', () => {
22
+ const result = toSignupResult({
23
+ user: {...baseUser, name: 'Ada', email_verified_at: '2026-04-27T00:00:00.000Z'},
24
+ });
25
+
26
+ expect(result.user).toEqual({
27
+ id: baseUser.id,
28
+ email: baseUser.email,
29
+ name: 'Ada',
30
+ emailVerifiedAt: '2026-04-27T00:00:00.000Z',
31
+ });
32
+ });
33
+
34
+ test('maps the email challenge into camelCase fields', () => {
35
+ const result = toSignupResult({
36
+ user: baseUser,
37
+ email_challenge: {
38
+ id: '22222222-2222-4222-8222-222222222222',
39
+ next_resend_available_at: '2026-04-27T00:01:00.000Z',
40
+ },
41
+ });
42
+
43
+ expect(result.emailChallenge).toEqual({
44
+ id: '22222222-2222-4222-8222-222222222222',
45
+ nextResendAvailableAt: '2026-04-27T00:01:00.000Z',
46
+ });
47
+ });
48
+
49
+ test('maps the invitation membership into camelCase fields', () => {
50
+ const result = toSignupResult({
51
+ user: baseUser,
52
+ membership: {
53
+ id: '33333333-3333-4333-8333-333333333333',
54
+ user_id: baseUser.id,
55
+ workspace_id: '44444444-4444-4444-8444-444444444444',
56
+ },
57
+ });
58
+
59
+ expect(result.membership).toEqual({
60
+ id: '33333333-3333-4333-8333-333333333333',
61
+ userId: baseUser.id,
62
+ workspaceId: '44444444-4444-4444-8444-444444444444',
63
+ });
64
+ });
65
+
66
+ test('maps the invitation accept error as-is', () => {
67
+ const result = toSignupResult({
68
+ user: baseUser,
69
+ accept_error: {code: 'invitation-expired', message: 'This invitation has expired.'},
70
+ });
71
+
72
+ expect(result.acceptError).toEqual({
73
+ code: 'invitation-expired',
74
+ message: 'This invitation has expired.',
75
+ });
76
+ });
77
+ });
@@ -0,0 +1,39 @@
1
+ import type {SignupResponseDto} from '@shipfox/api-auth-dto';
2
+ import {
3
+ toAuthenticatedSession,
4
+ toUserIdentity,
5
+ type UserIdentity,
6
+ } from '@shipfox/client-shell/runtime';
7
+
8
+ export {toAuthenticatedSession};
9
+
10
+ export interface SignupResult {
11
+ user: UserIdentity;
12
+ emailChallenge?: {id: string; nextResendAvailableAt: string};
13
+ membership?: {id: string; userId: string; workspaceId: string};
14
+ acceptError?: {code: string; message: string};
15
+ }
16
+
17
+ export function toSignupResult(dto: SignupResponseDto): SignupResult {
18
+ return {
19
+ user: toUserIdentity(dto.user),
20
+ ...(dto.email_challenge
21
+ ? {
22
+ emailChallenge: {
23
+ id: dto.email_challenge.id,
24
+ nextResendAvailableAt: dto.email_challenge.next_resend_available_at,
25
+ },
26
+ }
27
+ : {}),
28
+ ...(dto.membership
29
+ ? {
30
+ membership: {
31
+ id: dto.membership.id,
32
+ userId: dto.membership.user_id,
33
+ workspaceId: dto.membership.workspace_id,
34
+ },
35
+ }
36
+ : {}),
37
+ ...(dto.accept_error ? {acceptError: dto.accept_error} : {}),
38
+ };
39
+ }
@@ -37,7 +37,7 @@ describe('loginAuth', () => {
37
37
  const result = await loginAuth(body);
38
38
 
39
39
  const request = fetchImpl.mock.calls[0]?.[0] as Request;
40
- expect(result.token).toBe('access-token');
40
+ expect(result.accessToken).toBe('access-token');
41
41
  expect(request.url).toBe('https://api.example.test/auth/login');
42
42
  expect(request.method).toBe('POST');
43
43
  expect(requestBody).toEqual(body);
@@ -1,10 +1,15 @@
1
- import type {LoginBodyDto, LoginResponseDto} from '@shipfox/api-auth-dto';
2
- import {apiRequest} from '@shipfox/client-api';
1
+ import {type LoginBodyDto, loginResponseSchema} from '@shipfox/api-auth-dto';
2
+ import {checkedApiRequest} from '@shipfox/client-api';
3
3
  import {useMutation} from '@tanstack/react-query';
4
4
  import {useAuthTransition} from '#state/auth.js';
5
+ import {toAuthenticatedSession} from './auth-mapper.js';
5
6
 
6
7
  export async function loginAuth(body: LoginBodyDto) {
7
- return await apiRequest<LoginResponseDto>('/auth/login', {method: 'POST', body});
8
+ const response = await checkedApiRequest(loginResponseSchema, '/auth/login', {
9
+ method: 'POST',
10
+ body,
11
+ });
12
+ return toAuthenticatedSession(response);
8
13
  }
9
14
 
10
15
  export function useLoginAuth() {
@@ -60,7 +60,7 @@ describe('confirmPasswordReset', () => {
60
60
  const result = await confirmPasswordReset(body);
61
61
 
62
62
  const request = fetchImpl.mock.calls[0]?.[0] as Request;
63
- expect(result.token).toBe('reset-access-token');
63
+ expect(result.accessToken).toBe('reset-access-token');
64
64
  expect(request.url).toBe('https://api.example.test/auth/password-reset/confirm');
65
65
  expect(request.method).toBe('POST');
66
66
  expect(requestBody).toEqual(body);
@@ -1,21 +1,27 @@
1
- import type {
2
- PasswordResetConfirmBodyDto,
3
- PasswordResetConfirmResponseDto,
4
- PasswordResetRequestBodyDto,
1
+ import {
2
+ type PasswordResetConfirmBodyDto,
3
+ type PasswordResetRequestBodyDto,
4
+ passwordResetConfirmResponseSchema,
5
5
  } from '@shipfox/api-auth-dto';
6
- import {apiRequest} from '@shipfox/client-api';
6
+ import {apiRequest, checkedApiRequest} from '@shipfox/client-api';
7
7
  import {useMutation} from '@tanstack/react-query';
8
8
  import {useAuthTransition} from '#state/auth.js';
9
+ import {toAuthenticatedSession} from './auth-mapper.js';
9
10
 
10
11
  export async function requestPasswordReset(body: PasswordResetRequestBodyDto) {
11
12
  await apiRequest<void>('/auth/password-reset', {method: 'POST', body});
12
13
  }
13
14
 
14
15
  export async function confirmPasswordReset(body: PasswordResetConfirmBodyDto) {
15
- return await apiRequest<PasswordResetConfirmResponseDto>('/auth/password-reset/confirm', {
16
- method: 'POST',
17
- body,
18
- });
16
+ const response = await checkedApiRequest(
17
+ passwordResetConfirmResponseSchema,
18
+ '/auth/password-reset/confirm',
19
+ {
20
+ method: 'POST',
21
+ body,
22
+ },
23
+ );
24
+ return toAuthenticatedSession(response);
19
25
  }
20
26
 
21
27
  export function useRequestPasswordResetAuth() {
@@ -1,9 +1,14 @@
1
- import type {SignupBodyDto, SignupResponseDto} from '@shipfox/api-auth-dto';
2
- import {apiRequest} from '@shipfox/client-api';
1
+ import {type SignupBodyDto, signupResponseSchema} from '@shipfox/api-auth-dto';
2
+ import {checkedApiRequest} from '@shipfox/client-api';
3
3
  import {useMutation} from '@tanstack/react-query';
4
+ import {toSignupResult} from './auth-mapper.js';
4
5
 
5
6
  async function signupAuth(body: SignupBodyDto) {
6
- return await apiRequest<SignupResponseDto>('/auth/signup', {method: 'POST', body});
7
+ const response = await checkedApiRequest(signupResponseSchema, '/auth/signup', {
8
+ method: 'POST',
9
+ body,
10
+ });
11
+ return toSignupResult(response);
7
12
  }
8
13
 
9
14
  export function useSignupAuth() {
@@ -1,22 +1,28 @@
1
- import type {
2
- VerifyEmailConfirmBodyDto,
3
- VerifyEmailConfirmResponseDto,
4
- VerifyEmailResendBodyDto,
5
- VerifyEmailResendResponseDto,
1
+ import {
2
+ type VerifyEmailConfirmBodyDto,
3
+ type VerifyEmailResendBodyDto,
4
+ verifyEmailConfirmResponseSchema,
5
+ verifyEmailResendResponseSchema,
6
6
  } from '@shipfox/api-auth-dto';
7
- import {apiRequest} from '@shipfox/client-api';
7
+ import {checkedApiRequest} from '@shipfox/client-api';
8
8
  import {useMutation} from '@tanstack/react-query';
9
9
  import {useAuthTransition} from '#state/auth.js';
10
+ import {toAuthenticatedSession} from './auth-mapper.js';
10
11
 
11
12
  async function verifyEmailAuth(body: VerifyEmailConfirmBodyDto) {
12
- return await apiRequest<VerifyEmailConfirmResponseDto>('/auth/verify-email/confirm', {
13
- method: 'POST',
14
- body,
15
- });
13
+ const response = await checkedApiRequest(
14
+ verifyEmailConfirmResponseSchema,
15
+ '/auth/verify-email/confirm',
16
+ {
17
+ method: 'POST',
18
+ body,
19
+ },
20
+ );
21
+ return toAuthenticatedSession(response);
16
22
  }
17
23
 
18
24
  async function resendEmailVerificationAuth(body: VerifyEmailResendBodyDto) {
19
- return await apiRequest<VerifyEmailResendResponseDto>('/auth/verify-email/resend', {
25
+ return await checkedApiRequest(verifyEmailResendResponseSchema, '/auth/verify-email/resend', {
20
26
  method: 'POST',
21
27
  body,
22
28
  });
@@ -1,11 +1,16 @@
1
- import type {CreateWorkspaceBodyDto, WorkspaceResponseDto} from '@shipfox/api-workspaces-dto';
2
- import {apiRequest} from '@shipfox/client-api';
1
+ import {type CreateWorkspaceBodyDto, workspaceResponseSchema} from '@shipfox/api-workspaces-dto';
2
+ import {checkedApiRequest} from '@shipfox/client-api';
3
3
  import {listUserWorkspaces, userWorkspacesQueryKey} from '@shipfox/client-shell/runtime';
4
4
  import {useMutation} from '@tanstack/react-query';
5
5
  import {useRefreshAuth} from './refresh-auth.js';
6
+ import {toWorkspace} from './workspace-mapper.js';
6
7
 
7
8
  export async function createWorkspace(body: CreateWorkspaceBodyDto) {
8
- return await apiRequest<WorkspaceResponseDto>('/workspaces', {method: 'POST', body});
9
+ const response = await checkedApiRequest(workspaceResponseSchema, '/workspaces', {
10
+ method: 'POST',
11
+ body,
12
+ });
13
+ return toWorkspace(response);
9
14
  }
10
15
 
11
16
  export {listUserWorkspaces, userWorkspacesQueryKey};
@@ -0,0 +1,21 @@
1
+ import type {WorkspaceResponseDto} from '@shipfox/api-workspaces-dto';
2
+ import {toWorkspace} from './workspace-mapper.js';
3
+
4
+ describe('toWorkspace', () => {
5
+ test.each([
6
+ 'active',
7
+ 'suspended',
8
+ 'deleted',
9
+ ] as const)('maps a %s workspace to its domain shape', (status) => {
10
+ const dto: WorkspaceResponseDto = {
11
+ id: '11111111-1111-4111-8111-111111111111',
12
+ name: 'Acme',
13
+ status,
14
+ settings: {},
15
+ created_at: '2026-04-27T00:00:00.000Z',
16
+ updated_at: '2026-04-27T00:00:00.000Z',
17
+ };
18
+
19
+ expect(toWorkspace(dto)).toEqual({id: dto.id, name: dto.name, status});
20
+ });
21
+ });
@@ -0,0 +1,11 @@
1
+ import type {WorkspaceResponseDto} from '@shipfox/api-workspaces-dto';
2
+
3
+ export interface Workspace {
4
+ id: string;
5
+ name: string;
6
+ status: 'active' | 'suspended' | 'deleted';
7
+ }
8
+
9
+ export function toWorkspace(dto: WorkspaceResponseDto): Workspace {
10
+ return {id: dto.id, name: dto.name, status: dto.status};
11
+ }
package/src/index.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from './components/auth-guard.js';
2
2
  export * from './components/auth-provider.js';
3
- export * from './components/auth-shell.js';
4
3
  export {WorkspaceCrumb, type WorkspaceCrumbProps} from './components/workspace-crumb.js';
5
4
  export {WorkspaceSwitcher, type WorkspaceSwitcherProps} from './components/workspace-switcher.js';
6
5
  export * from './hooks/index.js';
@@ -1,39 +1,16 @@
1
- import type {
2
- PreviewInvitationPendingDto,
3
- PreviewInvitationResponseDto,
4
- } from '@shipfox/api-workspaces-dto';
5
- import {apiRequest} from '@shipfox/client-api';
6
- import {useQuery} from '@tanstack/react-query';
1
+ import {
2
+ type InvitationPreview,
3
+ pendingInvitation,
4
+ usePreviewInvitation,
5
+ } from '@shipfox/client-invitations';
7
6
  import {parseRedirectContext} from '#/components/redirect-context.js';
8
7
 
9
8
  export function extractInvitationToken(redirect: unknown): string | undefined {
10
9
  return parseRedirectContext(redirect).invitationToken;
11
10
  }
12
11
 
13
- async function fetchPreview(token: string): Promise<PreviewInvitationResponseDto> {
14
- const params = new URLSearchParams({token});
15
- return await apiRequest<PreviewInvitationResponseDto>(
16
- `/invitations/preview?${params.toString()}`,
17
- );
18
- }
19
-
20
- export function pendingInvitation(
21
- data: PreviewInvitationResponseDto | undefined,
22
- ): PreviewInvitationPendingDto | undefined {
23
- return data?.status === 'pending' ? data : undefined;
24
- }
25
-
26
- /**
27
- * Mirrors the hook in `@shipfox/client-invitations` but lives in `client-auth`
28
- * to avoid a circular dependency. Signup/login pages call this to lock the
29
- * email field when arriving from an invitation link.
30
- */
31
12
  export function useInvitationContext(token: string | undefined) {
32
- return useQuery({
33
- queryKey: ['invitations', 'preview', token ?? ''] as const,
34
- queryFn: () => fetchPreview(token as string),
35
- enabled: Boolean(token),
36
- retry: false,
37
- staleTime: 30_000,
38
- });
13
+ return usePreviewInvitation(token);
39
14
  }
15
+
16
+ export {type InvitationPreview, pendingInvitation};
@@ -70,7 +70,7 @@ describe('LoginPage', () => {
70
70
  return Promise.resolve(
71
71
  jsonResponse({
72
72
  status: 'pending',
73
- workspace_id: 'workspace-1',
73
+ workspace_id: '11111111-1111-4111-8111-111111111111',
74
74
  workspace_name: 'Invite Workspace',
75
75
  email: 'invitee@example.com',
76
76
  invited_by_display: 'owner@example.com',
@@ -1,4 +1,5 @@
1
1
  import {loginBodySchema} from '@shipfox/api-auth-dto';
2
+ import {AuthShell} from '@shipfox/client-shell/runtime';
2
3
  import {Button, ButtonLink} from '@shipfox/react-ui/button';
3
4
  import {Callout} from '@shipfox/react-ui/callout';
4
5
  import {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';
@@ -8,7 +9,6 @@ import {useForm} from '@tanstack/react-form';
8
9
  import {Link, useSearch} from '@tanstack/react-router';
9
10
  import {useAtom} from 'jotai';
10
11
  import {useEffect, useRef, useState} from 'react';
11
- import {AuthShell} from '#/components/auth-shell.js';
12
12
  import {useLoginAuth} from '#hooks/api/login-auth.js';
13
13
  import {authFormDraftAtom, initialAuthFormDraft} from '#state/auth.js';
14
14
  import {loginErrorToFormError} from './form-errors.js';
@@ -81,7 +81,7 @@ export function LoginPage() {
81
81
  ? `/invitations/accept?token=${encodeURIComponent(invitationToken)}`
82
82
  : undefined;
83
83
  const headerTitle = invitationPending
84
- ? `Join ${invitationPending.workspace_name}`
84
+ ? `Join ${invitationPending.workspaceName}`
85
85
  : 'Connect to Shipfox';
86
86
  const headerDescription = invitationPending
87
87
  ? 'Log in to accept your invitation.'
@@ -1,7 +1,7 @@
1
+ import {AuthShell} from '@shipfox/client-shell/runtime';
1
2
  import {Text} from '@shipfox/react-ui/typography';
2
3
  import {useNavigate, useRouter, useSearch} from '@tanstack/react-router';
3
4
  import {useEffect} from 'react';
4
- import {AuthShell} from '#/components/auth-shell.js';
5
5
  import {sanitizeRedirectPath} from '#/components/redirect-target.js';
6
6
  import {useLogoutAuth} from '#hooks/api/logout-auth.js';
7
7
 
@@ -2,6 +2,7 @@ import {
2
2
  passwordResetConfirmBodySchema,
3
3
  passwordResetRequestBodySchema,
4
4
  } from '@shipfox/api-auth-dto';
5
+ import {AuthShell} from '@shipfox/client-shell/runtime';
5
6
  import {Button, ButtonLink} from '@shipfox/react-ui/button';
6
7
  import {Callout} from '@shipfox/react-ui/callout';
7
8
  import {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';
@@ -11,12 +12,10 @@ import {useForm} from '@tanstack/react-form';
11
12
  import {Link, useNavigate, useSearch} from '@tanstack/react-router';
12
13
  import {useAtom} from 'jotai';
13
14
  import {useEffect, useRef, useState} from 'react';
14
- import {AuthShell} from '#/components/auth-shell.js';
15
15
  import {
16
16
  useConfirmPasswordResetAuth,
17
17
  useRequestPasswordResetAuth,
18
18
  } from '#hooks/api/password-reset-auth.js';
19
- import {useRefreshAuth} from '#hooks/api/refresh-auth.js';
20
19
  import {authFormDraftAtom, initialAuthFormDraft} from '#state/auth.js';
21
20
  import {
22
21
  passwordResetConfirmErrorToFormError,
@@ -148,7 +147,6 @@ function PasswordResetRequest() {
148
147
 
149
148
  function PasswordResetConfirm({token}: {token: string}) {
150
149
  const confirmPasswordReset = useConfirmPasswordResetAuth();
151
- const refreshAuth = useRefreshAuth();
152
150
  const navigate = useNavigate();
153
151
  const [, setAuthFormDraft] = useAtom(authFormDraftAtom);
154
152
  const [formError, setFormError] = useState<string | undefined>();
@@ -163,7 +161,6 @@ function PasswordResetConfirm({token}: {token: string}) {
163
161
  new_password: value.new_password,
164
162
  });
165
163
  await confirmPasswordReset.mutateAsync(body);
166
- await refreshAuth();
167
164
  setAuthFormDraft(initialAuthFormDraft);
168
165
  toast.success('Your password has been changed. You are now logged in.');
169
166
  await navigate({to: '/', replace: true});
@@ -137,7 +137,7 @@ describe('SignupPage', () => {
137
137
  return Promise.resolve(
138
138
  jsonResponse({
139
139
  status: 'pending',
140
- workspace_id: 'workspace-1',
140
+ workspace_id: '11111111-1111-4111-8111-111111111111',
141
141
  workspace_name: 'Invite Workspace',
142
142
  email: 'invitee@example.com',
143
143
  invited_by_display: 'owner@example.com',
@@ -1,4 +1,5 @@
1
1
  import {signupBodySchema} from '@shipfox/api-auth-dto';
2
+ import {AuthShell} from '@shipfox/client-shell/runtime';
2
3
  import {displayNameFieldError} from '@shipfox/client-ui';
3
4
  import {Button, ButtonLink} from '@shipfox/react-ui/button';
4
5
  import {Callout} from '@shipfox/react-ui/callout';
@@ -10,7 +11,6 @@ import {useForm} from '@tanstack/react-form';
10
11
  import {Link, useNavigate, useSearch} from '@tanstack/react-router';
11
12
  import {useAtom} from 'jotai';
12
13
  import {useEffect, useRef, useState} from 'react';
13
- import {AuthShell} from '#/components/auth-shell.js';
14
14
  import {EmailCodeVerification} from '#/components/email-code-verification.js';
15
15
  import {useRefreshAuth} from '#hooks/api/refresh-auth.js';
16
16
  import {useSignupAuth} from '#hooks/api/signup-auth.js';
@@ -67,16 +67,16 @@ export function SignupPage() {
67
67
  // Refresh failures don't block the success message — the next API
68
68
  // call's 401 handling will re-route the user.
69
69
  }
70
- toast.success(`You joined ${invitationPending.workspace_name}.`);
70
+ toast.success(`You joined ${invitationPending.workspaceName}.`);
71
71
  await navigate({
72
72
  to: '/workspaces/$wid',
73
- params: {wid: result.membership.workspace_id},
73
+ params: {wid: result.membership.workspaceId},
74
74
  });
75
75
  return;
76
76
  }
77
77
 
78
- if (invitationToken && result.accept_error) {
79
- toast.error(result.accept_error.message);
78
+ if (invitationToken && result.acceptError) {
79
+ toast.error(result.acceptError.message);
80
80
  await navigate({
81
81
  to: '/invitations/accept',
82
82
  search: {token: invitationToken},
@@ -84,12 +84,12 @@ export function SignupPage() {
84
84
  return;
85
85
  }
86
86
 
87
- if (!result.email_challenge) {
87
+ if (!result.emailChallenge) {
88
88
  throw new Error('Signup did not return an email verification challenge');
89
89
  }
90
- setEmailChallenge({email: result.user.email, id: result.email_challenge.id});
90
+ setEmailChallenge({email: result.user.email, id: result.emailChallenge.id});
91
91
  setResendError(undefined);
92
- setNextResendAvailableAt(result.email_challenge.next_resend_available_at);
92
+ setNextResendAvailableAt(result.emailChallenge.nextResendAvailableAt);
93
93
  } catch (error) {
94
94
  const mapped = signupErrorToFormError(error);
95
95
  if (mapped.kind === 'field') {
@@ -181,7 +181,7 @@ export function SignupPage() {
181
181
  }
182
182
 
183
183
  const headerTitle = invitationPending
184
- ? `Join ${invitationPending.workspace_name}`
184
+ ? `Join ${invitationPending.workspaceName}`
185
185
  : 'Create your Shipfox account';
186
186
  const headerDescription = invitationPending
187
187
  ? `Create an account to accept your invitation.`