@shipfox/client-auth 4.0.0 → 6.0.1

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 (141) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +56 -0
  3. package/dist/components/auth-guard.d.ts.map +1 -1
  4. package/dist/components/auth-guard.js +4 -4
  5. package/dist/components/auth-guard.js.map +1 -1
  6. package/dist/components/email-code-verification.d.ts.map +1 -1
  7. package/dist/components/email-code-verification.js +1 -1
  8. package/dist/components/email-code-verification.js.map +1 -1
  9. package/dist/components/redirect-target.d.ts +7 -0
  10. package/dist/components/redirect-target.d.ts.map +1 -1
  11. package/dist/components/redirect-target.js +35 -4
  12. package/dist/components/redirect-target.js.map +1 -1
  13. package/dist/components/workspace-switcher.stories.d.ts +1 -1
  14. package/dist/continuation.d.ts +1 -1
  15. package/dist/continuation.d.ts.map +1 -1
  16. package/dist/continuation.js +1 -1
  17. package/dist/continuation.js.map +1 -1
  18. package/dist/core/auth.d.ts +57 -0
  19. package/dist/core/auth.d.ts.map +1 -0
  20. package/dist/core/auth.js +3 -0
  21. package/dist/core/auth.js.map +1 -0
  22. package/dist/hooks/api/auth-mapper.d.ts +6 -0
  23. package/dist/hooks/api/auth-mapper.d.ts.map +1 -0
  24. package/dist/hooks/api/auth-mapper.js +25 -0
  25. package/dist/hooks/api/auth-mapper.js.map +1 -0
  26. package/dist/hooks/api/login-auth.d.ts +3 -28
  27. package/dist/hooks/api/login-auth.d.ts.map +1 -1
  28. package/dist/hooks/api/login-auth.js +7 -4
  29. package/dist/hooks/api/login-auth.js.map +1 -1
  30. package/dist/hooks/api/logout-auth.js +2 -2
  31. package/dist/hooks/api/logout-auth.js.map +1 -1
  32. package/dist/hooks/api/password-reset-auth.d.ts +5 -32
  33. package/dist/hooks/api/password-reset-auth.d.ts.map +1 -1
  34. package/dist/hooks/api/password-reset-auth.js +13 -7
  35. package/dist/hooks/api/password-reset-auth.js.map +1 -1
  36. package/dist/hooks/api/refresh-auth.d.ts +1 -1
  37. package/dist/hooks/api/refresh-auth.d.ts.map +1 -1
  38. package/dist/hooks/api/refresh-auth.js +1 -1
  39. package/dist/hooks/api/refresh-auth.js.map +1 -1
  40. package/dist/hooks/api/signup-auth.d.ts +2 -30
  41. package/dist/hooks/api/signup-auth.d.ts.map +1 -1
  42. package/dist/hooks/api/signup-auth.js +14 -4
  43. package/dist/hooks/api/signup-auth.js.map +1 -1
  44. package/dist/hooks/api/verify-email-auth.d.ts +4 -21
  45. package/dist/hooks/api/verify-email-auth.d.ts.map +1 -1
  46. package/dist/hooks/api/verify-email-auth.js +20 -7
  47. package/dist/hooks/api/verify-email-auth.js.map +1 -1
  48. package/dist/hooks/api/workspace-auth.d.ts +5 -21
  49. package/dist/hooks/api/workspace-auth.d.ts.map +1 -1
  50. package/dist/hooks/api/workspace-auth.js +11 -6
  51. package/dist/hooks/api/workspace-auth.js.map +1 -1
  52. package/dist/hooks/api/workspace-mapper.d.ts +4 -0
  53. package/dist/hooks/api/workspace-mapper.d.ts.map +1 -0
  54. package/dist/hooks/api/workspace-mapper.js +9 -0
  55. package/dist/hooks/api/workspace-mapper.js.map +1 -0
  56. package/dist/index.d.ts +0 -1
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +0 -1
  59. package/dist/index.js.map +1 -1
  60. package/dist/pages/invitation-context.d.ts +9 -14
  61. package/dist/pages/invitation-context.d.ts.map +1 -1
  62. package/dist/pages/invitation-context.js +4 -27
  63. package/dist/pages/invitation-context.js.map +1 -1
  64. package/dist/pages/login-page.d.ts.map +1 -1
  65. package/dist/pages/login-page.js +5 -6
  66. package/dist/pages/login-page.js.map +1 -1
  67. package/dist/pages/logout-page.d.ts.map +1 -1
  68. package/dist/pages/logout-page.js +8 -18
  69. package/dist/pages/logout-page.js.map +1 -1
  70. package/dist/pages/password-reset-page.d.ts.map +1 -1
  71. package/dist/pages/password-reset-page.js +8 -10
  72. package/dist/pages/password-reset-page.js.map +1 -1
  73. package/dist/pages/signup-page.d.ts.map +1 -1
  74. package/dist/pages/signup-page.js +24 -18
  75. package/dist/pages/signup-page.js.map +1 -1
  76. package/dist/pages/workspace-onboarding-page.js +2 -2
  77. package/dist/pages/workspace-onboarding-page.js.map +1 -1
  78. package/dist/routes/inputs.d.ts +9 -0
  79. package/dist/routes/inputs.d.ts.map +1 -0
  80. package/dist/routes/inputs.js +17 -0
  81. package/dist/routes/inputs.js.map +1 -0
  82. package/dist/routes/login.d.ts +2 -0
  83. package/dist/routes/login.d.ts.map +1 -1
  84. package/dist/routes/login.js +2 -0
  85. package/dist/routes/login.js.map +1 -1
  86. package/dist/routes/logout.d.ts +2 -0
  87. package/dist/routes/logout.d.ts.map +1 -1
  88. package/dist/routes/logout.js +2 -0
  89. package/dist/routes/logout.js.map +1 -1
  90. package/dist/routes/reset.d.ts +2 -0
  91. package/dist/routes/reset.d.ts.map +1 -1
  92. package/dist/routes/reset.js +2 -0
  93. package/dist/routes/reset.js.map +1 -1
  94. package/dist/routes/signup.d.ts +2 -0
  95. package/dist/routes/signup.d.ts.map +1 -1
  96. package/dist/routes/signup.js +2 -0
  97. package/dist/routes/signup.js.map +1 -1
  98. package/dist/tsconfig.test.tsbuildinfo +1 -1
  99. package/package.json +11 -11
  100. package/src/components/auth-guard.tsx +4 -2
  101. package/src/components/email-code-verification.tsx +1 -1
  102. package/src/components/redirect-target.test.ts +32 -1
  103. package/src/components/redirect-target.ts +41 -4
  104. package/src/continuation.ts +1 -1
  105. package/src/core/auth.ts +55 -0
  106. package/src/hooks/api/auth-mapper.test.ts +77 -0
  107. package/src/hooks/api/auth-mapper.ts +29 -0
  108. package/src/hooks/api/login-auth.test.ts +1 -1
  109. package/src/hooks/api/login-auth.ts +10 -4
  110. package/src/hooks/api/logout-auth.ts +2 -2
  111. package/src/hooks/api/password-reset-auth.test.ts +3 -3
  112. package/src/hooks/api/password-reset-auth.ts +19 -13
  113. package/src/hooks/api/refresh-auth.ts +1 -0
  114. package/src/hooks/api/signup-auth.ts +15 -4
  115. package/src/hooks/api/verify-email-auth.ts +32 -16
  116. package/src/hooks/api/workspace-auth.ts +16 -6
  117. package/src/hooks/api/workspace-mapper.test.ts +21 -0
  118. package/src/hooks/api/workspace-mapper.ts +6 -0
  119. package/src/index.ts +0 -1
  120. package/src/pages/invitation-context.ts +8 -31
  121. package/src/pages/login-page.test.tsx +1 -1
  122. package/src/pages/login-page.tsx +5 -4
  123. package/src/pages/logout-page.test.tsx +75 -0
  124. package/src/pages/logout-page.tsx +9 -13
  125. package/src/pages/password-reset-page.tsx +5 -8
  126. package/src/pages/signup-page.test.tsx +1 -1
  127. package/src/pages/signup-page.tsx +22 -16
  128. package/src/pages/workspace-onboarding-page.tsx +2 -2
  129. package/src/routes/inputs.test.ts +17 -0
  130. package/src/routes/inputs.ts +21 -0
  131. package/src/routes/login.tsx +2 -0
  132. package/src/routes/logout.tsx +2 -1
  133. package/src/routes/reset.tsx +2 -0
  134. package/src/routes/signup.tsx +2 -0
  135. package/tsconfig.build.tsbuildinfo +1 -1
  136. package/vercel.json +5 -0
  137. package/dist/components/auth-shell.d.ts +0 -13
  138. package/dist/components/auth-shell.d.ts.map +0 -1
  139. package/dist/components/auth-shell.js +0 -68
  140. package/dist/components/auth-shell.js.map +0 -1
  141. package/src/components/auth-shell.tsx +0 -68
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/api/password-reset-auth.ts"],"sourcesContent":["import type {\n PasswordResetConfirmBodyDto,\n PasswordResetConfirmResponseDto,\n PasswordResetRequestBodyDto,\n} from '@shipfox/api-auth-dto';\nimport {apiRequest} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport {useAuthTransition} from '#state/auth.js';\n\nexport async function requestPasswordReset(body: PasswordResetRequestBodyDto) {\n await apiRequest<void>('/auth/password-reset', {method: 'POST', body});\n}\n\nexport async function confirmPasswordReset(body: PasswordResetConfirmBodyDto) {\n return await apiRequest<PasswordResetConfirmResponseDto>('/auth/password-reset/confirm', {\n method: 'POST',\n body,\n });\n}\n\nexport function useRequestPasswordResetAuth() {\n return useMutation({mutationFn: requestPasswordReset});\n}\n\nexport function useConfirmPasswordResetAuth() {\n const {enterAuthenticated} = useAuthTransition();\n\n return useMutation({\n mutationFn: confirmPasswordReset,\n onSuccess: enterAuthenticated,\n });\n}\n"],"names":["apiRequest","useMutation","useAuthTransition","requestPasswordReset","body","method","confirmPasswordReset","useRequestPasswordResetAuth","mutationFn","useConfirmPasswordResetAuth","enterAuthenticated","onSuccess"],"mappings":"AAKA,SAAQA,UAAU,QAAO,sBAAsB;AAC/C,SAAQC,WAAW,QAAO,wBAAwB;AAClD,SAAQC,iBAAiB,QAAO,iBAAiB;AAEjD,OAAO,eAAeC,qBAAqBC,IAAiC;IAC1E,MAAMJ,WAAiB,wBAAwB;QAACK,QAAQ;QAAQD;IAAI;AACtE;AAEA,OAAO,eAAeE,qBAAqBF,IAAiC;IAC1E,OAAO,MAAMJ,WAA4C,gCAAgC;QACvFK,QAAQ;QACRD;IACF;AACF;AAEA,OAAO,SAASG;IACd,OAAON,YAAY;QAACO,YAAYL;IAAoB;AACtD;AAEA,OAAO,SAASM;IACd,MAAM,EAACC,kBAAkB,EAAC,GAAGR;IAE7B,OAAOD,YAAY;QACjBO,YAAYF;QACZK,WAAWD;IACb;AACF"}
1
+ {"version":3,"sources":["../../../src/hooks/api/password-reset-auth.ts"],"sourcesContent":["import {passwordResetConfirmResponseSchema} from '@shipfox/api-auth-dto';\nimport {checkedApiRequest, emptyResponseSchema} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport type {PasswordResetConfirmCommand, PasswordResetRequestCommand} from '#core/auth.js';\nimport {useAuthTransition} from '#state/auth.js';\nimport {toAuthenticatedSession} from './auth-mapper.js';\n\nexport async function requestPasswordReset(command: PasswordResetRequestCommand) {\n await checkedApiRequest(emptyResponseSchema, '/auth/password-reset', {\n method: 'POST',\n body: command,\n });\n}\n\nexport async function confirmPasswordReset(command: PasswordResetConfirmCommand) {\n const response = await checkedApiRequest(\n passwordResetConfirmResponseSchema,\n '/auth/password-reset/confirm',\n {\n method: 'POST',\n body: {token: command.token, new_password: command.newPassword},\n },\n );\n return toAuthenticatedSession(response);\n}\n\nexport function useRequestPasswordResetAuth() {\n return useMutation({mutationFn: requestPasswordReset});\n}\n\nexport function useConfirmPasswordResetAuth() {\n const {enterAuthenticated} = useAuthTransition();\n\n return useMutation({\n mutationFn: confirmPasswordReset,\n onSuccess: enterAuthenticated,\n });\n}\n"],"names":["passwordResetConfirmResponseSchema","checkedApiRequest","emptyResponseSchema","useMutation","useAuthTransition","toAuthenticatedSession","requestPasswordReset","command","method","body","confirmPasswordReset","response","token","new_password","newPassword","useRequestPasswordResetAuth","mutationFn","useConfirmPasswordResetAuth","enterAuthenticated","onSuccess"],"mappings":"AAAA,SAAQA,kCAAkC,QAAO,wBAAwB;AACzE,SAAQC,iBAAiB,EAAEC,mBAAmB,QAAO,sBAAsB;AAC3E,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,iBAAiB,QAAO,iBAAiB;AACjD,SAAQC,sBAAsB,QAAO,mBAAmB;AAExD,OAAO,eAAeC,qBAAqBC,OAAoC;IAC7E,MAAMN,kBAAkBC,qBAAqB,wBAAwB;QACnEM,QAAQ;QACRC,MAAMF;IACR;AACF;AAEA,OAAO,eAAeG,qBAAqBH,OAAoC;IAC7E,MAAMI,WAAW,MAAMV,kBACrBD,oCACA,gCACA;QACEQ,QAAQ;QACRC,MAAM;YAACG,OAAOL,QAAQK,KAAK;YAAEC,cAAcN,QAAQO,WAAW;QAAA;IAChE;IAEF,OAAOT,uBAAuBM;AAChC;AAEA,OAAO,SAASI;IACd,OAAOZ,YAAY;QAACa,YAAYV;IAAoB;AACtD;AAEA,OAAO,SAASW;IACd,MAAM,EAACC,kBAAkB,EAAC,GAAGd;IAE7B,OAAOD,YAAY;QACjBa,YAAYN;QACZS,WAAWD;IACb;AACF"}
@@ -1,2 +1,2 @@
1
- export { authRefreshQueryKey, getAuthRefreshDelayMs, useRefreshAuth, } from '@shipfox/client-shell/runtime';
1
+ export { authRefreshQueryKey, authRefreshQueryOptions, getAuthRefreshDelayMs, useRefreshAuth, } from '@shipfox/client-shell/runtime';
2
2
  //# sourceMappingURL=refresh-auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"refresh-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/refresh-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,GACf,MAAM,+BAA+B,CAAC"}
1
+ {"version":3,"file":"refresh-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/refresh-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,qBAAqB,EACrB,cAAc,GACf,MAAM,+BAA+B,CAAC"}
@@ -1,3 +1,3 @@
1
- export { authRefreshQueryKey, getAuthRefreshDelayMs, useRefreshAuth } from '@shipfox/client-shell/runtime';
1
+ export { authRefreshQueryKey, authRefreshQueryOptions, getAuthRefreshDelayMs, useRefreshAuth } from '@shipfox/client-shell/runtime';
2
2
 
3
3
  //# sourceMappingURL=refresh-auth.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/api/refresh-auth.ts"],"sourcesContent":["export {\n authRefreshQueryKey,\n getAuthRefreshDelayMs,\n useRefreshAuth,\n} from '@shipfox/client-shell/runtime';\n"],"names":["authRefreshQueryKey","getAuthRefreshDelayMs","useRefreshAuth"],"mappings":"AAAA,SACEA,mBAAmB,EACnBC,qBAAqB,EACrBC,cAAc,QACT,gCAAgC"}
1
+ {"version":3,"sources":["../../../src/hooks/api/refresh-auth.ts"],"sourcesContent":["export {\n authRefreshQueryKey,\n authRefreshQueryOptions,\n getAuthRefreshDelayMs,\n useRefreshAuth,\n} from '@shipfox/client-shell/runtime';\n"],"names":["authRefreshQueryKey","authRefreshQueryOptions","getAuthRefreshDelayMs","useRefreshAuth"],"mappings":"AAAA,SACEA,mBAAmB,EACnBC,uBAAuB,EACvBC,qBAAqB,EACrBC,cAAc,QACT,gCAAgC"}
@@ -1,31 +1,3 @@
1
- export declare function useSignupAuth(): import("@tanstack/react-query").UseMutationResult<{
2
- user: {
3
- id: string;
4
- email: string;
5
- name: string | null;
6
- email_verified_at: string | null;
7
- status: "active" | "suspended" | "deleted";
8
- created_at: string;
9
- updated_at: string;
10
- };
11
- email_challenge?: {
12
- id: string;
13
- next_resend_available_at: string;
14
- } | undefined;
15
- token?: string | undefined;
16
- membership?: {
17
- id: string;
18
- user_id: string;
19
- workspace_id: string;
20
- } | null | undefined;
21
- accept_error?: {
22
- code: string;
23
- message: string;
24
- } | undefined;
25
- }, Error, {
26
- email: string;
27
- password: string;
28
- name: string;
29
- invitation_token?: string | undefined;
30
- }, unknown>;
1
+ import type { SignupCommand } from '#core/auth.js';
2
+ export declare function useSignupAuth(): import("@tanstack/react-query").UseMutationResult<import("#core/auth.js").SignupResult, Error, SignupCommand, unknown>;
31
3
  //# sourceMappingURL=signup-auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"signup-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/signup-auth.ts"],"names":[],"mappings":"AAQA,wBAAgB,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAE5B"}
1
+ {"version":3,"file":"signup-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/signup-auth.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,eAAe,CAAC;AAgBjD,wBAAgB,aAAa,2HAE5B"}
@@ -1,10 +1,20 @@
1
- import { apiRequest } from '@shipfox/client-api';
1
+ import { signupResponseSchema } from '@shipfox/api-auth-dto';
2
+ import { checkedApiRequest } from '@shipfox/client-api';
2
3
  import { useMutation } from '@tanstack/react-query';
3
- async function signupAuth(body) {
4
- return await apiRequest('/auth/signup', {
4
+ import { toSignupResult } from './auth-mapper.js';
5
+ async function signupAuth(command) {
6
+ const response = await checkedApiRequest(signupResponseSchema, '/auth/signup', {
5
7
  method: 'POST',
6
- body
8
+ body: {
9
+ email: command.email,
10
+ password: command.password,
11
+ name: command.name,
12
+ ...command.invitationToken ? {
13
+ invitation_token: command.invitationToken
14
+ } : {}
15
+ }
7
16
  });
17
+ return toSignupResult(response);
8
18
  }
9
19
  export function useSignupAuth() {
10
20
  return useMutation({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/api/signup-auth.ts"],"sourcesContent":["import type {SignupBodyDto, SignupResponseDto} from '@shipfox/api-auth-dto';\nimport {apiRequest} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\n\nasync function signupAuth(body: SignupBodyDto) {\n return await apiRequest<SignupResponseDto>('/auth/signup', {method: 'POST', body});\n}\n\nexport function useSignupAuth() {\n return useMutation({mutationFn: signupAuth});\n}\n"],"names":["apiRequest","useMutation","signupAuth","body","method","useSignupAuth","mutationFn"],"mappings":"AACA,SAAQA,UAAU,QAAO,sBAAsB;AAC/C,SAAQC,WAAW,QAAO,wBAAwB;AAElD,eAAeC,WAAWC,IAAmB;IAC3C,OAAO,MAAMH,WAA8B,gBAAgB;QAACI,QAAQ;QAAQD;IAAI;AAClF;AAEA,OAAO,SAASE;IACd,OAAOJ,YAAY;QAACK,YAAYJ;IAAU;AAC5C"}
1
+ {"version":3,"sources":["../../../src/hooks/api/signup-auth.ts"],"sourcesContent":["import {signupResponseSchema} from '@shipfox/api-auth-dto';\nimport {checkedApiRequest} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport type {SignupCommand} from '#core/auth.js';\nimport {toSignupResult} from './auth-mapper.js';\n\nasync function signupAuth(command: SignupCommand) {\n const response = await checkedApiRequest(signupResponseSchema, '/auth/signup', {\n method: 'POST',\n body: {\n email: command.email,\n password: command.password,\n name: command.name,\n ...(command.invitationToken ? {invitation_token: command.invitationToken} : {}),\n },\n });\n return toSignupResult(response);\n}\n\nexport function useSignupAuth() {\n return useMutation({mutationFn: signupAuth});\n}\n"],"names":["signupResponseSchema","checkedApiRequest","useMutation","toSignupResult","signupAuth","command","response","method","body","email","password","name","invitationToken","invitation_token","useSignupAuth","mutationFn"],"mappings":"AAAA,SAAQA,oBAAoB,QAAO,wBAAwB;AAC3D,SAAQC,iBAAiB,QAAO,sBAAsB;AACtD,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,cAAc,QAAO,mBAAmB;AAEhD,eAAeC,WAAWC,OAAsB;IAC9C,MAAMC,WAAW,MAAML,kBAAkBD,sBAAsB,gBAAgB;QAC7EO,QAAQ;QACRC,MAAM;YACJC,OAAOJ,QAAQI,KAAK;YACpBC,UAAUL,QAAQK,QAAQ;YAC1BC,MAAMN,QAAQM,IAAI;YAClB,GAAIN,QAAQO,eAAe,GAAG;gBAACC,kBAAkBR,QAAQO,eAAe;YAAA,IAAI,CAAC,CAAC;QAChF;IACF;IACA,OAAOT,eAAeG;AACxB;AAEA,OAAO,SAASQ;IACd,OAAOZ,YAAY;QAACa,YAAYX;IAAU;AAC5C"}
@@ -1,23 +1,6 @@
1
+ import type { ResendEmailVerificationCommand, VerifyEmailCommand } from '#core/auth.js';
1
2
  export declare function useResendEmailVerificationAuth(): import("@tanstack/react-query").UseMutationResult<{
2
- next_resend_available_at: string;
3
- }, Error, {
4
- email: string;
5
- challenge_id: string;
6
- }, unknown>;
7
- export declare function useVerifyEmailAuth(): import("@tanstack/react-query").UseMutationResult<{
8
- token: string;
9
- user: {
10
- id: string;
11
- email: string;
12
- name: string | null;
13
- email_verified_at: string | null;
14
- status: "active" | "suspended" | "deleted";
15
- created_at: string;
16
- updated_at: string;
17
- };
18
- }, Error, {
19
- email: string;
20
- challenge_id: string;
21
- code: string;
22
- }, unknown>;
3
+ nextResendAvailableAt: string;
4
+ }, Error, ResendEmailVerificationCommand, unknown>;
5
+ export declare function useVerifyEmailAuth(): import("@tanstack/react-query").UseMutationResult<import("@shipfox/client-shell/runtime").AuthenticatedSession, Error, VerifyEmailCommand, unknown>;
23
6
  //# sourceMappingURL=verify-email-auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"verify-email-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/verify-email-auth.ts"],"names":[],"mappings":"AAwBA,wBAAgB,8BAA8B;;;;;YAE7C;AAED,wBAAgB,kBAAkB;;;;;;;;;;;;;;;YAOjC"}
1
+ {"version":3,"file":"verify-email-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/verify-email-auth.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,8BAA8B,EAC9B,kBAAkB,EACnB,MAAM,eAAe,CAAC;AA8BvB,wBAAgB,8BAA8B;;mDAE7C;AAED,wBAAgB,kBAAkB,wJAOjC"}
@@ -1,17 +1,30 @@
1
- import { apiRequest } from '@shipfox/client-api';
1
+ import { verifyEmailConfirmResponseSchema, verifyEmailResendResponseSchema } from '@shipfox/api-auth-dto';
2
+ import { checkedApiRequest } from '@shipfox/client-api';
2
3
  import { useMutation } from '@tanstack/react-query';
3
4
  import { useAuthTransition } from '#state/auth.js';
4
- async function verifyEmailAuth(body) {
5
- return await apiRequest('/auth/verify-email/confirm', {
5
+ import { toAuthenticatedSession } from './auth-mapper.js';
6
+ async function verifyEmailAuth(command) {
7
+ const response = await checkedApiRequest(verifyEmailConfirmResponseSchema, '/auth/verify-email/confirm', {
6
8
  method: 'POST',
7
- body
9
+ body: {
10
+ email: command.email,
11
+ challenge_id: command.challengeId,
12
+ code: command.code
13
+ }
8
14
  });
15
+ return toAuthenticatedSession(response);
9
16
  }
10
- async function resendEmailVerificationAuth(body) {
11
- return await apiRequest('/auth/verify-email/resend', {
17
+ async function resendEmailVerificationAuth(command) {
18
+ const response = await checkedApiRequest(verifyEmailResendResponseSchema, '/auth/verify-email/resend', {
12
19
  method: 'POST',
13
- body
20
+ body: {
21
+ email: command.email,
22
+ challenge_id: command.challengeId
23
+ }
14
24
  });
25
+ return {
26
+ nextResendAvailableAt: response.next_resend_available_at
27
+ };
15
28
  }
16
29
  export function useResendEmailVerificationAuth() {
17
30
  return useMutation({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/api/verify-email-auth.ts"],"sourcesContent":["import type {\n VerifyEmailConfirmBodyDto,\n VerifyEmailConfirmResponseDto,\n VerifyEmailResendBodyDto,\n VerifyEmailResendResponseDto,\n} from '@shipfox/api-auth-dto';\nimport {apiRequest} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport {useAuthTransition} from '#state/auth.js';\n\nasync function verifyEmailAuth(body: VerifyEmailConfirmBodyDto) {\n return await apiRequest<VerifyEmailConfirmResponseDto>('/auth/verify-email/confirm', {\n method: 'POST',\n body,\n });\n}\n\nasync function resendEmailVerificationAuth(body: VerifyEmailResendBodyDto) {\n return await apiRequest<VerifyEmailResendResponseDto>('/auth/verify-email/resend', {\n method: 'POST',\n body,\n });\n}\n\nexport function useResendEmailVerificationAuth() {\n return useMutation({mutationFn: resendEmailVerificationAuth});\n}\n\nexport function useVerifyEmailAuth() {\n const {enterAuthenticated} = useAuthTransition();\n\n return useMutation({\n mutationFn: verifyEmailAuth,\n onSuccess: enterAuthenticated,\n });\n}\n"],"names":["apiRequest","useMutation","useAuthTransition","verifyEmailAuth","body","method","resendEmailVerificationAuth","useResendEmailVerificationAuth","mutationFn","useVerifyEmailAuth","enterAuthenticated","onSuccess"],"mappings":"AAMA,SAAQA,UAAU,QAAO,sBAAsB;AAC/C,SAAQC,WAAW,QAAO,wBAAwB;AAClD,SAAQC,iBAAiB,QAAO,iBAAiB;AAEjD,eAAeC,gBAAgBC,IAA+B;IAC5D,OAAO,MAAMJ,WAA0C,8BAA8B;QACnFK,QAAQ;QACRD;IACF;AACF;AAEA,eAAeE,4BAA4BF,IAA8B;IACvE,OAAO,MAAMJ,WAAyC,6BAA6B;QACjFK,QAAQ;QACRD;IACF;AACF;AAEA,OAAO,SAASG;IACd,OAAON,YAAY;QAACO,YAAYF;IAA2B;AAC7D;AAEA,OAAO,SAASG;IACd,MAAM,EAACC,kBAAkB,EAAC,GAAGR;IAE7B,OAAOD,YAAY;QACjBO,YAAYL;QACZQ,WAAWD;IACb;AACF"}
1
+ {"version":3,"sources":["../../../src/hooks/api/verify-email-auth.ts"],"sourcesContent":["import {\n verifyEmailConfirmResponseSchema,\n verifyEmailResendResponseSchema,\n} from '@shipfox/api-auth-dto';\nimport {checkedApiRequest} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport type {\n EmailVerificationResendResult,\n ResendEmailVerificationCommand,\n VerifyEmailCommand,\n} from '#core/auth.js';\nimport {useAuthTransition} from '#state/auth.js';\nimport {toAuthenticatedSession} from './auth-mapper.js';\n\nasync function verifyEmailAuth(command: VerifyEmailCommand) {\n const response = await checkedApiRequest(\n verifyEmailConfirmResponseSchema,\n '/auth/verify-email/confirm',\n {\n method: 'POST',\n body: {email: command.email, challenge_id: command.challengeId, code: command.code},\n },\n );\n return toAuthenticatedSession(response);\n}\n\nasync function resendEmailVerificationAuth(command: ResendEmailVerificationCommand) {\n const response = await checkedApiRequest(\n verifyEmailResendResponseSchema,\n '/auth/verify-email/resend',\n {\n method: 'POST',\n body: {email: command.email, challenge_id: command.challengeId},\n },\n );\n return {\n nextResendAvailableAt: response.next_resend_available_at,\n } satisfies EmailVerificationResendResult;\n}\n\nexport function useResendEmailVerificationAuth() {\n return useMutation({mutationFn: resendEmailVerificationAuth});\n}\n\nexport function useVerifyEmailAuth() {\n const {enterAuthenticated} = useAuthTransition();\n\n return useMutation({\n mutationFn: verifyEmailAuth,\n onSuccess: enterAuthenticated,\n });\n}\n"],"names":["verifyEmailConfirmResponseSchema","verifyEmailResendResponseSchema","checkedApiRequest","useMutation","useAuthTransition","toAuthenticatedSession","verifyEmailAuth","command","response","method","body","email","challenge_id","challengeId","code","resendEmailVerificationAuth","nextResendAvailableAt","next_resend_available_at","useResendEmailVerificationAuth","mutationFn","useVerifyEmailAuth","enterAuthenticated","onSuccess"],"mappings":"AAAA,SACEA,gCAAgC,EAChCC,+BAA+B,QAC1B,wBAAwB;AAC/B,SAAQC,iBAAiB,QAAO,sBAAsB;AACtD,SAAQC,WAAW,QAAO,wBAAwB;AAMlD,SAAQC,iBAAiB,QAAO,iBAAiB;AACjD,SAAQC,sBAAsB,QAAO,mBAAmB;AAExD,eAAeC,gBAAgBC,OAA2B;IACxD,MAAMC,WAAW,MAAMN,kBACrBF,kCACA,8BACA;QACES,QAAQ;QACRC,MAAM;YAACC,OAAOJ,QAAQI,KAAK;YAAEC,cAAcL,QAAQM,WAAW;YAAEC,MAAMP,QAAQO,IAAI;QAAA;IACpF;IAEF,OAAOT,uBAAuBG;AAChC;AAEA,eAAeO,4BAA4BR,OAAuC;IAChF,MAAMC,WAAW,MAAMN,kBACrBD,iCACA,6BACA;QACEQ,QAAQ;QACRC,MAAM;YAACC,OAAOJ,QAAQI,KAAK;YAAEC,cAAcL,QAAQM,WAAW;QAAA;IAChE;IAEF,OAAO;QACLG,uBAAuBR,SAASS,wBAAwB;IAC1D;AACF;AAEA,OAAO,SAASC;IACd,OAAOf,YAAY;QAACgB,YAAYJ;IAA2B;AAC7D;AAEA,OAAO,SAASK;IACd,MAAM,EAACC,kBAAkB,EAAC,GAAGjB;IAE7B,OAAOD,YAAY;QACjBgB,YAAYb;QACZgB,WAAWD;IACb;AACF"}
@@ -1,22 +1,6 @@
1
- import type { CreateWorkspaceBodyDto } from '@shipfox/api-workspaces-dto';
2
- import { listUserWorkspaces, userWorkspacesQueryKey } from '@shipfox/client-shell/runtime';
3
- export declare function createWorkspace(body: CreateWorkspaceBodyDto): Promise<{
4
- id: string;
5
- name: string;
6
- status: "active" | "suspended" | "deleted";
7
- settings: Record<string, unknown>;
8
- created_at: string;
9
- updated_at: string;
10
- }>;
11
- export { listUserWorkspaces, userWorkspacesQueryKey };
12
- export declare function useCreateWorkspaceAuth(): import("@tanstack/react-query").UseMutationResult<{
13
- id: string;
14
- name: string;
15
- status: "active" | "suspended" | "deleted";
16
- settings: Record<string, unknown>;
17
- created_at: string;
18
- updated_at: string;
19
- }, Error, {
20
- name: string;
21
- }, unknown>;
1
+ import { listUserWorkspaces, userWorkspacesQueryKey, userWorkspacesQueryOptions } from '@shipfox/client-shell/runtime';
2
+ import type { WorkspaceCreateCommand } from '#core/auth.js';
3
+ export declare function createWorkspace(command: WorkspaceCreateCommand): Promise<import("#core/auth.js").Workspace>;
4
+ export { listUserWorkspaces, userWorkspacesQueryKey, userWorkspacesQueryOptions };
5
+ export declare function useCreateWorkspaceAuth(): import("@tanstack/react-query").UseMutationResult<import("#core/auth.js").Workspace, Error, WorkspaceCreateCommand, unknown>;
22
6
  //# sourceMappingURL=workspace-auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/workspace-auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,sBAAsB,EAAuB,MAAM,6BAA6B,CAAC;AAE9F,OAAO,EAAC,kBAAkB,EAAE,sBAAsB,EAAC,MAAM,+BAA+B,CAAC;AAIzF,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB;;;;;;;GAEjE;AAED,OAAO,EAAC,kBAAkB,EAAE,sBAAsB,EAAC,CAAC;AAEpD,wBAAgB,sBAAsB;;;;;;;;;YAYrC"}
1
+ {"version":3,"file":"workspace-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/workspace-auth.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC3B,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,eAAe,CAAC;AAI1D,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,8CAMpE;AAED,OAAO,EAAC,kBAAkB,EAAE,sBAAsB,EAAE,0BAA0B,EAAC,CAAC;AAEhF,wBAAgB,sBAAsB,iIAYrC"}
@@ -1,14 +1,19 @@
1
- import { apiRequest } from '@shipfox/client-api';
2
- import { listUserWorkspaces, userWorkspacesQueryKey } from '@shipfox/client-shell/runtime';
1
+ import { workspaceResponseSchema } from '@shipfox/api-workspaces-dto';
2
+ import { checkedApiRequest } from '@shipfox/client-api';
3
+ import { listUserWorkspaces, userWorkspacesQueryKey, userWorkspacesQueryOptions } from '@shipfox/client-shell/runtime';
3
4
  import { useMutation } from '@tanstack/react-query';
4
5
  import { useRefreshAuth } from './refresh-auth.js';
5
- export async function createWorkspace(body) {
6
- return await apiRequest('/workspaces', {
6
+ import { toWorkspace } from './workspace-mapper.js';
7
+ export async function createWorkspace(command) {
8
+ const response = await checkedApiRequest(workspaceResponseSchema, '/workspaces', {
7
9
  method: 'POST',
8
- body
10
+ body: {
11
+ name: command.name
12
+ }
9
13
  });
14
+ return toWorkspace(response);
10
15
  }
11
- export { listUserWorkspaces, userWorkspacesQueryKey };
16
+ export { listUserWorkspaces, userWorkspacesQueryKey, userWorkspacesQueryOptions };
12
17
  export function useCreateWorkspaceAuth() {
13
18
  const refreshAuth = useRefreshAuth();
14
19
  return useMutation({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/api/workspace-auth.ts"],"sourcesContent":["import type {CreateWorkspaceBodyDto, WorkspaceResponseDto} from '@shipfox/api-workspaces-dto';\nimport {apiRequest} from '@shipfox/client-api';\nimport {listUserWorkspaces, userWorkspacesQueryKey} from '@shipfox/client-shell/runtime';\nimport {useMutation} from '@tanstack/react-query';\nimport {useRefreshAuth} from './refresh-auth.js';\n\nexport async function createWorkspace(body: CreateWorkspaceBodyDto) {\n return await apiRequest<WorkspaceResponseDto>('/workspaces', {method: 'POST', body});\n}\n\nexport {listUserWorkspaces, userWorkspacesQueryKey};\n\nexport function useCreateWorkspaceAuth() {\n const refreshAuth = useRefreshAuth();\n\n return useMutation({\n mutationFn: createWorkspace,\n onSuccess: async () => {\n // The new workspace introduces a membership the existing access token\n // doesn't carry. Refresh so the next request includes it in the JWT\n // claim and passes the in-memory canAccess() check on the server.\n await refreshAuth();\n },\n });\n}\n"],"names":["apiRequest","listUserWorkspaces","userWorkspacesQueryKey","useMutation","useRefreshAuth","createWorkspace","body","method","useCreateWorkspaceAuth","refreshAuth","mutationFn","onSuccess"],"mappings":"AACA,SAAQA,UAAU,QAAO,sBAAsB;AAC/C,SAAQC,kBAAkB,EAAEC,sBAAsB,QAAO,gCAAgC;AACzF,SAAQC,WAAW,QAAO,wBAAwB;AAClD,SAAQC,cAAc,QAAO,oBAAoB;AAEjD,OAAO,eAAeC,gBAAgBC,IAA4B;IAChE,OAAO,MAAMN,WAAiC,eAAe;QAACO,QAAQ;QAAQD;IAAI;AACpF;AAEA,SAAQL,kBAAkB,EAAEC,sBAAsB,GAAE;AAEpD,OAAO,SAASM;IACd,MAAMC,cAAcL;IAEpB,OAAOD,YAAY;QACjBO,YAAYL;QACZM,WAAW;YACT,sEAAsE;YACtE,oEAAoE;YACpE,kEAAkE;YAClE,MAAMF;QACR;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/hooks/api/workspace-auth.ts"],"sourcesContent":["import {workspaceResponseSchema} from '@shipfox/api-workspaces-dto';\nimport {checkedApiRequest} from '@shipfox/client-api';\nimport {\n listUserWorkspaces,\n userWorkspacesQueryKey,\n userWorkspacesQueryOptions,\n} from '@shipfox/client-shell/runtime';\nimport {useMutation} from '@tanstack/react-query';\nimport type {WorkspaceCreateCommand} from '#core/auth.js';\nimport {useRefreshAuth} from './refresh-auth.js';\nimport {toWorkspace} from './workspace-mapper.js';\n\nexport async function createWorkspace(command: WorkspaceCreateCommand) {\n const response = await checkedApiRequest(workspaceResponseSchema, '/workspaces', {\n method: 'POST',\n body: {name: command.name},\n });\n return toWorkspace(response);\n}\n\nexport {listUserWorkspaces, userWorkspacesQueryKey, userWorkspacesQueryOptions};\n\nexport function useCreateWorkspaceAuth() {\n const refreshAuth = useRefreshAuth();\n\n return useMutation({\n mutationFn: createWorkspace,\n onSuccess: async () => {\n // The new workspace introduces a membership the existing access token\n // doesn't carry. Refresh so the next request includes it in the JWT\n // claim and passes the in-memory canAccess() check on the server.\n await refreshAuth();\n },\n });\n}\n"],"names":["workspaceResponseSchema","checkedApiRequest","listUserWorkspaces","userWorkspacesQueryKey","userWorkspacesQueryOptions","useMutation","useRefreshAuth","toWorkspace","createWorkspace","command","response","method","body","name","useCreateWorkspaceAuth","refreshAuth","mutationFn","onSuccess"],"mappings":"AAAA,SAAQA,uBAAuB,QAAO,8BAA8B;AACpE,SAAQC,iBAAiB,QAAO,sBAAsB;AACtD,SACEC,kBAAkB,EAClBC,sBAAsB,EACtBC,0BAA0B,QACrB,gCAAgC;AACvC,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,cAAc,QAAO,oBAAoB;AACjD,SAAQC,WAAW,QAAO,wBAAwB;AAElD,OAAO,eAAeC,gBAAgBC,OAA+B;IACnE,MAAMC,WAAW,MAAMT,kBAAkBD,yBAAyB,eAAe;QAC/EW,QAAQ;QACRC,MAAM;YAACC,MAAMJ,QAAQI,IAAI;QAAA;IAC3B;IACA,OAAON,YAAYG;AACrB;AAEA,SAAQR,kBAAkB,EAAEC,sBAAsB,EAAEC,0BAA0B,GAAE;AAEhF,OAAO,SAASU;IACd,MAAMC,cAAcT;IAEpB,OAAOD,YAAY;QACjBW,YAAYR;QACZS,WAAW;YACT,sEAAsE;YACtE,oEAAoE;YACpE,kEAAkE;YAClE,MAAMF;QACR;IACF;AACF"}
@@ -0,0 +1,4 @@
1
+ import type { WorkspaceResponseDto } from '@shipfox/api-workspaces-dto';
2
+ import type { Workspace } from '#core/auth.js';
3
+ export declare function toWorkspace(dto: WorkspaceResponseDto): Workspace;
4
+ //# sourceMappingURL=workspace-mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-mapper.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/workspace-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,6BAA6B,CAAC;AACtE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,eAAe,CAAC;AAE7C,wBAAgB,WAAW,CAAC,GAAG,EAAE,oBAAoB,GAAG,SAAS,CAEhE"}
@@ -0,0 +1,9 @@
1
+ export function toWorkspace(dto) {
2
+ return {
3
+ id: dto.id,
4
+ name: dto.name,
5
+ status: dto.status
6
+ };
7
+ }
8
+
9
+ //# sourceMappingURL=workspace-mapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hooks/api/workspace-mapper.ts"],"sourcesContent":["import type {WorkspaceResponseDto} from '@shipfox/api-workspaces-dto';\nimport type {Workspace} from '#core/auth.js';\n\nexport function toWorkspace(dto: WorkspaceResponseDto): Workspace {\n return {id: dto.id, name: dto.name, status: dto.status};\n}\n"],"names":["toWorkspace","dto","id","name","status"],"mappings":"AAGA,OAAO,SAASA,YAAYC,GAAyB;IACnD,OAAO;QAACC,IAAID,IAAIC,EAAE;QAAEC,MAAMF,IAAIE,IAAI;QAAEC,QAAQH,IAAIG,MAAM;IAAA;AACxD"}
package/dist/index.d.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 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAAC,cAAc,EAAE,KAAK,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzF,OAAO,EAAC,iBAAiB,EAAE,KAAK,sBAAsB,EAAC,MAAM,oCAAoC,CAAC;AAClG,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wBAAwB,CAAC;AACvC,cAAc,sCAAsC,CAAC;AACrD,cAAc,iBAAiB,CAAC;AAChC,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,+BAA+B,CAAC;AAC9C,OAAO,EAAC,cAAc,EAAE,KAAK,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzF,OAAO,EAAC,iBAAiB,EAAE,KAAK,sBAAsB,EAAC,MAAM,oCAAoC,CAAC;AAClG,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wBAAwB,CAAC;AACvC,cAAc,sCAAsC,CAAC;AACrD,cAAc,iBAAiB,CAAC;AAChC,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,2BAA2B,CAAC"}
package/dist/index.js 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 } from './components/workspace-crumb.js';
5
4
  export { WorkspaceSwitcher } from './components/workspace-switcher.js';
6
5
  export * from './hooks/index.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './components/auth-guard.js';\nexport * from './components/auth-provider.js';\nexport * from './components/auth-shell.js';\nexport {WorkspaceCrumb, type WorkspaceCrumbProps} from './components/workspace-crumb.js';\nexport {WorkspaceSwitcher, type WorkspaceSwitcherProps} from './components/workspace-switcher.js';\nexport * from './hooks/index.js';\nexport * from './pages/login-page.js';\nexport * from './pages/logout-page.js';\nexport * from './pages/password-reset-page.js';\nexport * from './pages/signup-page.js';\nexport * from './pages/workspace-onboarding-page.js';\nexport * from './state/auth.js';\nexport {\n getLastWorkspaceId,\n lastWorkspaceIdAtom,\n rememberLastWorkspaceId,\n} from './state/last-workspace.js';\n"],"names":["WorkspaceCrumb","WorkspaceSwitcher","getLastWorkspaceId","lastWorkspaceIdAtom","rememberLastWorkspaceId"],"mappings":"AAAA,cAAc,6BAA6B;AAC3C,cAAc,gCAAgC;AAC9C,cAAc,6BAA6B;AAC3C,SAAQA,cAAc,QAAiC,kCAAkC;AACzF,SAAQC,iBAAiB,QAAoC,qCAAqC;AAClG,cAAc,mBAAmB;AACjC,cAAc,wBAAwB;AACtC,cAAc,yBAAyB;AACvC,cAAc,iCAAiC;AAC/C,cAAc,yBAAyB;AACvC,cAAc,uCAAuC;AACrD,cAAc,kBAAkB;AAChC,SACEC,kBAAkB,EAClBC,mBAAmB,EACnBC,uBAAuB,QAClB,4BAA4B"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './components/auth-guard.js';\nexport * from './components/auth-provider.js';\nexport {WorkspaceCrumb, type WorkspaceCrumbProps} from './components/workspace-crumb.js';\nexport {WorkspaceSwitcher, type WorkspaceSwitcherProps} from './components/workspace-switcher.js';\nexport * from './hooks/index.js';\nexport * from './pages/login-page.js';\nexport * from './pages/logout-page.js';\nexport * from './pages/password-reset-page.js';\nexport * from './pages/signup-page.js';\nexport * from './pages/workspace-onboarding-page.js';\nexport * from './state/auth.js';\nexport {\n getLastWorkspaceId,\n lastWorkspaceIdAtom,\n rememberLastWorkspaceId,\n} from './state/last-workspace.js';\n"],"names":["WorkspaceCrumb","WorkspaceSwitcher","getLastWorkspaceId","lastWorkspaceIdAtom","rememberLastWorkspaceId"],"mappings":"AAAA,cAAc,6BAA6B;AAC3C,cAAc,gCAAgC;AAC9C,SAAQA,cAAc,QAAiC,kCAAkC;AACzF,SAAQC,iBAAiB,QAAoC,qCAAqC;AAClG,cAAc,mBAAmB;AACjC,cAAc,wBAAwB;AACtC,cAAc,yBAAyB;AACvC,cAAc,iCAAiC;AAC/C,cAAc,yBAAyB;AACvC,cAAc,uCAAuC;AACrD,cAAc,kBAAkB;AAChC,SACEC,kBAAkB,EAClBC,mBAAmB,EACnBC,uBAAuB,QAClB,4BAA4B"}
@@ -1,26 +1,21 @@
1
- import type { PreviewInvitationPendingDto, PreviewInvitationResponseDto } from '@shipfox/api-workspaces-dto';
1
+ import { type InvitationPreview, pendingInvitation } from '@shipfox/client-invitations';
2
2
  export declare function extractInvitationToken(redirect: unknown): string | undefined;
3
- export declare function pendingInvitation(data: PreviewInvitationResponseDto | undefined): PreviewInvitationPendingDto | undefined;
4
- /**
5
- * Mirrors the hook in `@shipfox/client-invitations` but lives in `client-auth`
6
- * to avoid a circular dependency. Signup/login pages call this to lock the
7
- * email field when arriving from an invitation link.
8
- */
9
3
  export declare function useInvitationContext(token: string | undefined): import("@tanstack/react-query").UseQueryResult<NoInfer<{
10
4
  status: "pending";
11
- workspace_id: string;
12
- workspace_name: string;
5
+ workspaceId: string;
6
+ workspaceName: string;
13
7
  email: string;
14
- invited_by_display: string | null;
15
- expires_at: string;
8
+ invitedByDisplay?: string;
9
+ expiresAt: string;
16
10
  } | {
17
11
  status: "expired";
18
- workspace_name: string;
19
- expires_at: string;
12
+ workspaceName: string;
13
+ expiresAt: string;
20
14
  } | {
21
15
  status: "already_used";
22
- workspace_name: string;
16
+ workspaceName: string;
23
17
  } | {
24
18
  status: "invalid";
25
19
  }>, Error>;
20
+ export { type InvitationPreview, pendingInvitation };
26
21
  //# sourceMappingURL=invitation-context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"invitation-context.d.ts","sourceRoot":"","sources":["../../src/pages/invitation-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,2BAA2B,EAC3B,4BAA4B,EAC7B,MAAM,6BAA6B,CAAC;AAKrC,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE5E;AASD,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,4BAA4B,GAAG,SAAS,GAC7C,2BAA2B,GAAG,SAAS,CAEzC;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS;;;;;;;;;;;;;;;;WAQ7D"}
1
+ {"version":3,"file":"invitation-context.d.ts","sourceRoot":"","sources":["../../src/pages/invitation-context.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EACtB,iBAAiB,EAElB,MAAM,6BAA6B,CAAC;AAGrC,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE5E;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS;;;;;;;;;;;;;;;;WAE7D;AAED,OAAO,EAAC,KAAK,iBAAiB,EAAE,iBAAiB,EAAC,CAAC"}
@@ -1,34 +1,11 @@
1
- import { apiRequest } from '@shipfox/client-api';
2
- import { useQuery } from '@tanstack/react-query';
1
+ import { pendingInvitation, usePreviewInvitation } from '@shipfox/client-invitations';
3
2
  import { parseRedirectContext } from '#/components/redirect-context.js';
4
3
  export function extractInvitationToken(redirect) {
5
4
  return parseRedirectContext(redirect).invitationToken;
6
5
  }
7
- async function fetchPreview(token) {
8
- const params = new URLSearchParams({
9
- token
10
- });
11
- return await apiRequest(`/invitations/preview?${params.toString()}`);
12
- }
13
- export function pendingInvitation(data) {
14
- return data?.status === 'pending' ? data : undefined;
15
- }
16
- /**
17
- * Mirrors the hook in `@shipfox/client-invitations` but lives in `client-auth`
18
- * to avoid a circular dependency. Signup/login pages call this to lock the
19
- * email field when arriving from an invitation link.
20
- */ export function useInvitationContext(token) {
21
- return useQuery({
22
- queryKey: [
23
- 'invitations',
24
- 'preview',
25
- token ?? ''
26
- ],
27
- queryFn: ()=>fetchPreview(token),
28
- enabled: Boolean(token),
29
- retry: false,
30
- staleTime: 30_000
31
- });
6
+ export function useInvitationContext(token) {
7
+ return usePreviewInvitation(token);
32
8
  }
9
+ export { pendingInvitation };
33
10
 
34
11
  //# sourceMappingURL=invitation-context.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pages/invitation-context.ts"],"sourcesContent":["import type {\n PreviewInvitationPendingDto,\n PreviewInvitationResponseDto,\n} from '@shipfox/api-workspaces-dto';\nimport {apiRequest} from '@shipfox/client-api';\nimport {useQuery} from '@tanstack/react-query';\nimport {parseRedirectContext} from '#/components/redirect-context.js';\n\nexport function extractInvitationToken(redirect: unknown): string | undefined {\n return parseRedirectContext(redirect).invitationToken;\n}\n\nasync function fetchPreview(token: string): Promise<PreviewInvitationResponseDto> {\n const params = new URLSearchParams({token});\n return await apiRequest<PreviewInvitationResponseDto>(\n `/invitations/preview?${params.toString()}`,\n );\n}\n\nexport function pendingInvitation(\n data: PreviewInvitationResponseDto | undefined,\n): PreviewInvitationPendingDto | undefined {\n return data?.status === 'pending' ? data : undefined;\n}\n\n/**\n * Mirrors the hook in `@shipfox/client-invitations` but lives in `client-auth`\n * to avoid a circular dependency. Signup/login pages call this to lock the\n * email field when arriving from an invitation link.\n */\nexport function useInvitationContext(token: string | undefined) {\n return useQuery({\n queryKey: ['invitations', 'preview', token ?? ''] as const,\n queryFn: () => fetchPreview(token as string),\n enabled: Boolean(token),\n retry: false,\n staleTime: 30_000,\n });\n}\n"],"names":["apiRequest","useQuery","parseRedirectContext","extractInvitationToken","redirect","invitationToken","fetchPreview","token","params","URLSearchParams","toString","pendingInvitation","data","status","undefined","useInvitationContext","queryKey","queryFn","enabled","Boolean","retry","staleTime"],"mappings":"AAIA,SAAQA,UAAU,QAAO,sBAAsB;AAC/C,SAAQC,QAAQ,QAAO,wBAAwB;AAC/C,SAAQC,oBAAoB,QAAO,mCAAmC;AAEtE,OAAO,SAASC,uBAAuBC,QAAiB;IACtD,OAAOF,qBAAqBE,UAAUC,eAAe;AACvD;AAEA,eAAeC,aAAaC,KAAa;IACvC,MAAMC,SAAS,IAAIC,gBAAgB;QAACF;IAAK;IACzC,OAAO,MAAMP,WACX,CAAC,qBAAqB,EAAEQ,OAAOE,QAAQ,IAAI;AAE/C;AAEA,OAAO,SAASC,kBACdC,IAA8C;IAE9C,OAAOA,MAAMC,WAAW,YAAYD,OAAOE;AAC7C;AAEA;;;;CAIC,GACD,OAAO,SAASC,qBAAqBR,KAAyB;IAC5D,OAAON,SAAS;QACde,UAAU;YAAC;YAAe;YAAWT,SAAS;SAAG;QACjDU,SAAS,IAAMX,aAAaC;QAC5BW,SAASC,QAAQZ;QACjBa,OAAO;QACPC,WAAW;IACb;AACF"}
1
+ {"version":3,"sources":["../../src/pages/invitation-context.ts"],"sourcesContent":["import {\n type InvitationPreview,\n pendingInvitation,\n usePreviewInvitation,\n} from '@shipfox/client-invitations';\nimport {parseRedirectContext} from '#/components/redirect-context.js';\n\nexport function extractInvitationToken(redirect: unknown): string | undefined {\n return parseRedirectContext(redirect).invitationToken;\n}\n\nexport function useInvitationContext(token: string | undefined) {\n return usePreviewInvitation(token);\n}\n\nexport {type InvitationPreview, pendingInvitation};\n"],"names":["pendingInvitation","usePreviewInvitation","parseRedirectContext","extractInvitationToken","redirect","invitationToken","useInvitationContext","token"],"mappings":"AAAA,SAEEA,iBAAiB,EACjBC,oBAAoB,QACf,8BAA8B;AACrC,SAAQC,oBAAoB,QAAO,mCAAmC;AAEtE,OAAO,SAASC,uBAAuBC,QAAiB;IACtD,OAAOF,qBAAqBE,UAAUC,eAAe;AACvD;AAEA,OAAO,SAASC,qBAAqBC,KAAyB;IAC5D,OAAON,qBAAqBM;AAC9B;AAEA,SAAgCP,iBAAiB,GAAE"}
@@ -1 +1 @@
1
- {"version":3,"file":"login-page.d.ts","sourceRoot":"","sources":["../../src/pages/login-page.tsx"],"names":[],"mappings":"AAoBA,wBAAgB,SAAS,gCAmKxB"}
1
+ {"version":3,"file":"login-page.d.ts","sourceRoot":"","sources":["../../src/pages/login-page.tsx"],"names":[],"mappings":"AAqBA,wBAAgB,SAAS,gCAmKxB"}
@@ -1,24 +1,23 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { loginBodySchema } from '@shipfox/api-auth-dto';
3
+ import { AuthShell, useRouteSearch } from '@shipfox/client-shell/runtime';
3
4
  import { Button, ButtonLink } from '@shipfox/react-ui/button';
4
5
  import { Callout } from '@shipfox/react-ui/callout';
5
6
  import { FormField, FormFieldInput, fieldError } from '@shipfox/react-ui/form-field';
6
7
  import { Icon } from '@shipfox/react-ui/icon';
7
8
  import { Text } from '@shipfox/react-ui/typography';
8
9
  import { useForm } from '@tanstack/react-form';
9
- import { Link, useSearch } from '@tanstack/react-router';
10
+ import { Link } from '@tanstack/react-router';
10
11
  import { useAtom } from 'jotai';
11
12
  import { useEffect, useRef, useState } from 'react';
12
- import { AuthShell } from '#/components/auth-shell.js';
13
13
  import { useLoginAuth } from '#hooks/api/login-auth.js';
14
14
  import { authFormDraftAtom, initialAuthFormDraft } from '#state/auth.js';
15
+ import { validateRedirectSearch } from '../routes/inputs.js';
15
16
  import { loginErrorToFormError } from './form-errors.js';
16
17
  import { extractInvitationToken, pendingInvitation, useInvitationContext } from './invitation-context.js';
17
18
  export function LoginPage() {
18
19
  const login = useLoginAuth();
19
- const search = useSearch({
20
- strict: false
21
- });
20
+ const search = useRouteSearch(validateRedirectSearch);
22
21
  const invitationToken = extractInvitationToken(search.redirect);
23
22
  const invitationPreview = useInvitationContext(invitationToken);
24
23
  const invitationPending = pendingInvitation(invitationPreview.data);
@@ -91,7 +90,7 @@ export function LoginPage() {
91
90
  ]);
92
91
  const isInvitationEmailLocked = Boolean(invitationPending);
93
92
  const invitationRedirect = invitationToken ? `/invitations/accept?token=${encodeURIComponent(invitationToken)}` : undefined;
94
- const headerTitle = invitationPending ? `Join ${invitationPending.workspace_name}` : 'Connect to Shipfox';
93
+ const headerTitle = invitationPending ? `Join ${invitationPending.workspaceName}` : 'Connect to Shipfox';
95
94
  const headerDescription = invitationPending ? 'Log in to accept your invitation.' : 'Log in to access Shipfox.';
96
95
  function persistDraft() {
97
96
  const { email, password } = form.state.values;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pages/login-page.tsx"],"sourcesContent":["import {loginBodySchema} from '@shipfox/api-auth-dto';\nimport {Button, ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useForm} from '@tanstack/react-form';\nimport {Link, useSearch} from '@tanstack/react-router';\nimport {useAtom} from 'jotai';\nimport {useEffect, useRef, useState} from 'react';\nimport {AuthShell} from '#/components/auth-shell.js';\nimport {useLoginAuth} from '#hooks/api/login-auth.js';\nimport {authFormDraftAtom, initialAuthFormDraft} from '#state/auth.js';\nimport {loginErrorToFormError} from './form-errors.js';\nimport {\n extractInvitationToken,\n pendingInvitation,\n useInvitationContext,\n} from './invitation-context.js';\n\nexport function LoginPage() {\n const login = useLoginAuth();\n const search = useSearch({strict: false}) as {redirect?: unknown};\n const invitationToken = extractInvitationToken(search.redirect);\n const invitationPreview = useInvitationContext(invitationToken);\n const invitationPending = pendingInvitation(invitationPreview.data);\n const [authFormDraft, setAuthFormDraft] = useAtom(authFormDraftAtom);\n const [formError, setFormError] = useState<string | undefined>();\n const draftRef = useRef(authFormDraft);\n draftRef.current = authFormDraft;\n // Set just before clearing the draft on success so the unmount cleanup\n // below does not repersist the just-submitted credentials.\n const skipDraftPersistRef = useRef(false);\n\n const form = useForm({\n defaultValues: {email: authFormDraft.email, password: authFormDraft.password},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n await login.mutateAsync(value);\n skipDraftPersistRef.current = true;\n setAuthFormDraft(initialAuthFormDraft);\n } catch (error) {\n const mapped = loginErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n // Lock the email field when arriving from an invitation link so the user\n // can't log in as a different account than the one the invitation targets.\n useEffect(() => {\n if (invitationPending && form.state.values.email !== invitationPending.email) {\n form.setFieldValue('email', invitationPending.email);\n setAuthFormDraft((current) => ({...current, email: invitationPending.email}));\n }\n }, [invitationPending, form, setAuthFormDraft]);\n\n // Sync TanStack Form values back into the Jotai draft on unmount so a\n // navigation to /signup or /reset preserves what the user typed. Skipped\n // after a successful login because we just intentionally cleared the draft.\n useEffect(() => {\n return () => {\n if (skipDraftPersistRef.current) return;\n const {email, password} = form.state.values;\n if (email !== draftRef.current.email || password !== draftRef.current.password) {\n setAuthFormDraft({email, password});\n }\n };\n }, [form, setAuthFormDraft]);\n\n const isInvitationEmailLocked = Boolean(invitationPending);\n const invitationRedirect = invitationToken\n ? `/invitations/accept?token=${encodeURIComponent(invitationToken)}`\n : undefined;\n const headerTitle = invitationPending\n ? `Join ${invitationPending.workspace_name}`\n : 'Connect to Shipfox';\n const headerDescription = invitationPending\n ? 'Log in to accept your invitation.'\n : 'Log in to access Shipfox.';\n\n function persistDraft() {\n const {email, password} = form.state.values;\n setAuthFormDraft({email, password});\n }\n\n return (\n <AuthShell title={headerTitle} description={headerDescription}>\n <form\n className=\"flex flex-col gap-18\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n {formError}\n </Callout>\n ) : null}\n <form.Field\n name=\"email\"\n validators={{onBlur: loginBodySchema.shape.email, onSubmit: loginBodySchema.shape.email}}\n >\n {(field) => (\n <FormField label=\"Email\" id=\"email\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"email\"\n name=\"email\"\n type=\"email\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={() => {\n field.handleBlur();\n persistDraft();\n }}\n readOnly={isInvitationEmailLocked}\n iconRight={\n isInvitationEmailLocked ? (\n <Icon\n aria-hidden=\"true\"\n className=\"size-16 text-foreground-neutral-disabled\"\n name=\"lockLine\"\n />\n ) : undefined\n }\n />\n </FormField>\n )}\n </form.Field>\n <form.Field\n name=\"password\"\n validators={{\n onBlur: loginBodySchema.shape.password,\n onSubmit: loginBodySchema.shape.password,\n }}\n >\n {(field) => (\n <FormField label=\"Password\" id=\"password\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"current-password\"\n name=\"password\"\n type=\"password\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={() => {\n field.handleBlur();\n persistDraft();\n }}\n />\n </FormField>\n )}\n </form.Field>\n <ButtonLink asChild variant=\"subtle\" className=\"-mt-8 self-end\">\n <Link to=\"/auth/reset\">Forgot password?</Link>\n </ButtonLink>\n <Button className=\"w-full\" isLoading={login.isPending} type=\"submit\">\n {login.isPending ? 'Logging in...' : 'Log in'}\n </Button>\n </form>\n <Text size=\"sm\" className=\"text-center text-foreground-neutral-subtle\">\n New to Shipfox?{' '}\n <ButtonLink asChild variant=\"interactive\" underline>\n <Link\n to=\"/auth/signup\"\n search={invitationRedirect ? {redirect: invitationRedirect} : undefined}\n >\n Create an account\n </Link>\n </ButtonLink>\n </Text>\n </AuthShell>\n );\n}\n"],"names":["loginBodySchema","Button","ButtonLink","Callout","FormField","FormFieldInput","fieldError","Icon","Text","useForm","Link","useSearch","useAtom","useEffect","useRef","useState","AuthShell","useLoginAuth","authFormDraftAtom","initialAuthFormDraft","loginErrorToFormError","extractInvitationToken","pendingInvitation","useInvitationContext","LoginPage","login","search","strict","invitationToken","redirect","invitationPreview","invitationPending","data","authFormDraft","setAuthFormDraft","formError","setFormError","draftRef","current","skipDraftPersistRef","form","defaultValues","email","password","onSubmit","value","undefined","mutateAsync","error","mapped","kind","setFieldMeta","field","prev","errorMap","onServer","message","state","values","setFieldValue","isInvitationEmailLocked","Boolean","invitationRedirect","encodeURIComponent","headerTitle","workspace_name","headerDescription","persistDraft","title","description","className","noValidate","event","preventDefault","stopPropagation","handleSubmit","role","type","Field","name","validators","onBlur","shape","label","id","autoComplete","onChange","handleChange","target","handleBlur","readOnly","iconRight","aria-hidden","asChild","variant","to","isLoading","isPending","size","underline"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/pages/login-page.tsx"],"sourcesContent":["import {loginBodySchema} from '@shipfox/api-auth-dto';\nimport {AuthShell, useRouteSearch} from '@shipfox/client-shell/runtime';\nimport {Button, ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useForm} from '@tanstack/react-form';\nimport {Link} from '@tanstack/react-router';\nimport {useAtom} from 'jotai';\nimport {useEffect, useRef, useState} from 'react';\nimport {useLoginAuth} from '#hooks/api/login-auth.js';\nimport {authFormDraftAtom, initialAuthFormDraft} from '#state/auth.js';\nimport {validateRedirectSearch} from '../routes/inputs.js';\nimport {loginErrorToFormError} from './form-errors.js';\nimport {\n extractInvitationToken,\n pendingInvitation,\n useInvitationContext,\n} from './invitation-context.js';\n\nexport function LoginPage() {\n const login = useLoginAuth();\n const search = useRouteSearch(validateRedirectSearch);\n const invitationToken = extractInvitationToken(search.redirect);\n const invitationPreview = useInvitationContext(invitationToken);\n const invitationPending = pendingInvitation(invitationPreview.data);\n const [authFormDraft, setAuthFormDraft] = useAtom(authFormDraftAtom);\n const [formError, setFormError] = useState<string | undefined>();\n const draftRef = useRef(authFormDraft);\n draftRef.current = authFormDraft;\n // Set just before clearing the draft on success so the unmount cleanup\n // below does not repersist the just-submitted credentials.\n const skipDraftPersistRef = useRef(false);\n\n const form = useForm({\n defaultValues: {email: authFormDraft.email, password: authFormDraft.password},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n await login.mutateAsync(value);\n skipDraftPersistRef.current = true;\n setAuthFormDraft(initialAuthFormDraft);\n } catch (error) {\n const mapped = loginErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n // Lock the email field when arriving from an invitation link so the user\n // can't log in as a different account than the one the invitation targets.\n useEffect(() => {\n if (invitationPending && form.state.values.email !== invitationPending.email) {\n form.setFieldValue('email', invitationPending.email);\n setAuthFormDraft((current) => ({...current, email: invitationPending.email}));\n }\n }, [invitationPending, form, setAuthFormDraft]);\n\n // Sync TanStack Form values back into the Jotai draft on unmount so a\n // navigation to /signup or /reset preserves what the user typed. Skipped\n // after a successful login because we just intentionally cleared the draft.\n useEffect(() => {\n return () => {\n if (skipDraftPersistRef.current) return;\n const {email, password} = form.state.values;\n if (email !== draftRef.current.email || password !== draftRef.current.password) {\n setAuthFormDraft({email, password});\n }\n };\n }, [form, setAuthFormDraft]);\n\n const isInvitationEmailLocked = Boolean(invitationPending);\n const invitationRedirect = invitationToken\n ? `/invitations/accept?token=${encodeURIComponent(invitationToken)}`\n : undefined;\n const headerTitle = invitationPending\n ? `Join ${invitationPending.workspaceName}`\n : 'Connect to Shipfox';\n const headerDescription = invitationPending\n ? 'Log in to accept your invitation.'\n : 'Log in to access Shipfox.';\n\n function persistDraft() {\n const {email, password} = form.state.values;\n setAuthFormDraft({email, password});\n }\n\n return (\n <AuthShell title={headerTitle} description={headerDescription}>\n <form\n className=\"flex flex-col gap-18\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n {formError}\n </Callout>\n ) : null}\n <form.Field\n name=\"email\"\n validators={{onBlur: loginBodySchema.shape.email, onSubmit: loginBodySchema.shape.email}}\n >\n {(field) => (\n <FormField label=\"Email\" id=\"email\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"email\"\n name=\"email\"\n type=\"email\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={() => {\n field.handleBlur();\n persistDraft();\n }}\n readOnly={isInvitationEmailLocked}\n iconRight={\n isInvitationEmailLocked ? (\n <Icon\n aria-hidden=\"true\"\n className=\"size-16 text-foreground-neutral-disabled\"\n name=\"lockLine\"\n />\n ) : undefined\n }\n />\n </FormField>\n )}\n </form.Field>\n <form.Field\n name=\"password\"\n validators={{\n onBlur: loginBodySchema.shape.password,\n onSubmit: loginBodySchema.shape.password,\n }}\n >\n {(field) => (\n <FormField label=\"Password\" id=\"password\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"current-password\"\n name=\"password\"\n type=\"password\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={() => {\n field.handleBlur();\n persistDraft();\n }}\n />\n </FormField>\n )}\n </form.Field>\n <ButtonLink asChild variant=\"subtle\" className=\"-mt-8 self-end\">\n <Link to=\"/auth/reset\">Forgot password?</Link>\n </ButtonLink>\n <Button className=\"w-full\" isLoading={login.isPending} type=\"submit\">\n {login.isPending ? 'Logging in...' : 'Log in'}\n </Button>\n </form>\n <Text size=\"sm\" className=\"text-center text-foreground-neutral-subtle\">\n New to Shipfox?{' '}\n <ButtonLink asChild variant=\"interactive\" underline>\n <Link\n to=\"/auth/signup\"\n search={invitationRedirect ? {redirect: invitationRedirect} : undefined}\n >\n Create an account\n </Link>\n </ButtonLink>\n </Text>\n </AuthShell>\n );\n}\n"],"names":["loginBodySchema","AuthShell","useRouteSearch","Button","ButtonLink","Callout","FormField","FormFieldInput","fieldError","Icon","Text","useForm","Link","useAtom","useEffect","useRef","useState","useLoginAuth","authFormDraftAtom","initialAuthFormDraft","validateRedirectSearch","loginErrorToFormError","extractInvitationToken","pendingInvitation","useInvitationContext","LoginPage","login","search","invitationToken","redirect","invitationPreview","invitationPending","data","authFormDraft","setAuthFormDraft","formError","setFormError","draftRef","current","skipDraftPersistRef","form","defaultValues","email","password","onSubmit","value","undefined","mutateAsync","error","mapped","kind","setFieldMeta","field","prev","errorMap","onServer","message","state","values","setFieldValue","isInvitationEmailLocked","Boolean","invitationRedirect","encodeURIComponent","headerTitle","workspaceName","headerDescription","persistDraft","title","description","className","noValidate","event","preventDefault","stopPropagation","handleSubmit","role","type","Field","name","validators","onBlur","shape","label","id","autoComplete","onChange","handleChange","target","handleBlur","readOnly","iconRight","aria-hidden","asChild","variant","to","isLoading","isPending","size","underline"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"logout-page.d.ts","sourceRoot":"","sources":["../../src/pages/logout-page.tsx"],"names":[],"mappings":"AAOA,wBAAgB,UAAU,gCAyBzB"}
1
+ {"version":3,"file":"logout-page.d.ts","sourceRoot":"","sources":["../../src/pages/logout-page.tsx"],"names":[],"mappings":"AAQA,wBAAgB,UAAU,gCAoBzB"}
@@ -1,33 +1,23 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { AuthShell, useRouteSearch } from '@shipfox/client-shell/runtime';
2
3
  import { Text } from '@shipfox/react-ui/typography';
3
- import { useNavigate, useRouter, useSearch } from '@tanstack/react-router';
4
+ import { useRouter } from '@tanstack/react-router';
4
5
  import { useEffect } from 'react';
5
- import { AuthShell } from '#/components/auth-shell.js';
6
- import { sanitizeRedirectPath } from '#/components/redirect-target.js';
6
+ import { sanitizeLogoutRedirectPath } from '#/components/redirect-target.js';
7
7
  import { useLogoutAuth } from '#hooks/api/logout-auth.js';
8
+ import { validateRedirectSearch } from '../routes/inputs.js';
8
9
  export function LogoutPage() {
9
10
  const logout = useLogoutAuth();
10
- const navigate = useNavigate();
11
11
  const router = useRouter();
12
- const search = useSearch({
13
- strict: false
14
- });
15
- const target = sanitizeRedirectPath(search.redirect);
12
+ const search = useRouteSearch(validateRedirectSearch);
13
+ const target = sanitizeLogoutRedirectPath(search.redirect);
16
14
  useEffect(()=>{
17
15
  logout.mutateAsync().finally(()=>{
18
- if (target !== undefined) {
19
- // Same-origin runtime path; let history drive route resolution.
20
- router.history.replace(target);
21
- } else {
22
- navigate({
23
- to: '/auth/login',
24
- replace: true
25
- });
26
- }
16
+ // Same-origin runtime path; let history drive route resolution.
17
+ router.history.replace(target);
27
18
  });
28
19
  }, [
29
20
  logout.mutateAsync,
30
- navigate,
31
21
  router,
32
22
  target
33
23
  ]);