@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,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 38 files with swc (507ms)
2
+ Successfully compiled: 41 files with swc (135.57ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,61 @@
1
1
  # @shipfox/client-auth
2
2
 
3
+ ## 6.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 475ce59: Republishes all public packages after restoring release authorization.
8
+ - 3f8f1cb: Enforces typed route-input and browser-storage boundaries across client features.
9
+ - Updated dependencies [475ce59]
10
+ - Updated dependencies [3f8f1cb]
11
+ - @shipfox/api-auth-dto@9.0.1
12
+ - @shipfox/api-workspaces-dto@9.0.1
13
+ - @shipfox/client-api@6.0.1
14
+ - @shipfox/client-invitations@6.0.1
15
+ - @shipfox/client-shell@6.0.1
16
+ - @shipfox/client-ui@6.0.1
17
+ - @shipfox/react-ui@0.3.6
18
+
19
+ ## 6.0.0
20
+
21
+ ### Minor Changes
22
+
23
+ - cd90c19: Enforces package-owned query policies and explicit cache-operation ownership across client resources.
24
+
25
+ ### Patch Changes
26
+
27
+ - d784a07: Enforces checked client API responses and removes stale transport compatibility helpers.
28
+ - 891e469: Adds a sanitized logout redirect that clears local and server auth state before returning to a safe same-origin destination.
29
+ - c56c124: Converges auth sessions and invitation responses on checked domain boundaries.
30
+ - Updated dependencies [401b583]
31
+ - Updated dependencies [82eda45]
32
+ - Updated dependencies [9c9d266]
33
+ - Updated dependencies [cd90c19]
34
+ - Updated dependencies [24be269]
35
+ - Updated dependencies [c56c124]
36
+ - Updated dependencies [4a6d124]
37
+ - Updated dependencies [c02ac42]
38
+ - @shipfox/client-shell@6.0.0
39
+ - @shipfox/api-workspaces-dto@9.0.0
40
+ - @shipfox/client-api@6.0.0
41
+ - @shipfox/client-invitations@6.0.0
42
+ - @shipfox/api-auth-dto@7.1.0
43
+ - @shipfox/client-ui@6.0.0
44
+ - @shipfox/react-ui@0.3.5
45
+
46
+ ## 5.0.0
47
+
48
+ ### Major Changes
49
+
50
+ - ffd727b: Converges auth session and invitation state onto shared camelCase domain types validated at the API boundary, replacing the raw snake_case DTOs previously returned by login, signup, password reset, email verification, workspace creation, and invitation preview. `AuthState.user`, `useRefreshAuth()`, and `usePreviewInvitation()` now resolve to `UserIdentity`/`AuthenticatedSession`/`InvitationPreview` shapes (for example `accessToken` instead of `token`, `workspaceName` instead of `workspace_name`). Also moves the shared `AuthShell` component and session mapping helpers into `@shipfox/client-shell`, breaking the former `client-auth` ↔ `client-invitations` circular dependency.
51
+
52
+ ### Patch Changes
53
+
54
+ - Updated dependencies [ffd727b]
55
+ - Updated dependencies [79df9d1]
56
+ - @shipfox/client-shell@5.0.0
57
+ - @shipfox/client-invitations@5.0.0
58
+
3
59
  ## 4.0.0
4
60
 
5
61
  ### Minor Changes
@@ -1 +1 @@
1
- {"version":3,"file":"auth-guard.d.ts","sourceRoot":"","sources":["../../src/components/auth-guard.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAC,KAAK,iBAAiB,EAAY,MAAM,OAAO,CAAC;AAKxD,wBAAgB,SAAS,CAAC,EAAC,QAAQ,EAAC,EAAE,iBAAiB,+VAYtD;AAED,wBAAgB,UAAU,CAAC,EAAC,QAAQ,EAAC,EAAE,iBAAiB,+VA0BvD;AAED,wBAAgB,cAAc,CAAC,EAAC,QAAQ,EAAC,EAAE,iBAAiB,+VAQ3D"}
1
+ {"version":3,"file":"auth-guard.d.ts","sourceRoot":"","sources":["../../src/components/auth-guard.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAC,KAAK,iBAAiB,EAAY,MAAM,OAAO,CAAC;AAMxD,wBAAgB,SAAS,CAAC,EAAC,QAAQ,EAAC,EAAE,iBAAiB,+VAYtD;AAED,wBAAgB,UAAU,CAAC,EAAC,QAAQ,EAAC,EAAE,iBAAiB,+VA0BvD;AAED,wBAAgB,cAAc,CAAC,EAAC,QAAQ,EAAC,EAAE,iBAAiB,+VAQ3D"}
@@ -1,9 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useRouteSearch } from '@shipfox/client-shell/runtime';
2
3
  import { FullPageLoader } from '@shipfox/react-ui/loader';
3
- import { Navigate, useRouter, useSearch } from '@tanstack/react-router';
4
+ import { Navigate, useRouter } from '@tanstack/react-router';
4
5
  import { useEffect } from 'react';
5
6
  import { useAuthState } from '#hooks/use-auth-state.js';
6
7
  import { WorkspaceOnboardingPage } from '#pages/workspace-onboarding-page.js';
8
+ import { validateRedirectSearch } from '../routes/inputs.js';
7
9
  import { sanitizeRedirectPath } from './redirect-target.js';
8
10
  export function AuthGuard({ children }) {
9
11
  const auth = useAuthState();
@@ -20,9 +22,7 @@ export function AuthGuard({ children }) {
20
22
  }
21
23
  export function GuestGuard({ children }) {
22
24
  const auth = useAuthState();
23
- const search = useSearch({
24
- strict: false
25
- });
25
+ const search = useRouteSearch(validateRedirectSearch);
26
26
  const router = useRouter();
27
27
  const target = sanitizeRedirectPath(search.redirect);
28
28
  useEffect(()=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/auth-guard.tsx"],"sourcesContent":["import {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {Navigate, useRouter, useSearch} from '@tanstack/react-router';\nimport {type PropsWithChildren, useEffect} from 'react';\nimport {useAuthState} from '#hooks/use-auth-state.js';\nimport {WorkspaceOnboardingPage} from '#pages/workspace-onboarding-page.js';\nimport {sanitizeRedirectPath} from './redirect-target.js';\n\nexport function AuthGuard({children}: PropsWithChildren) {\n const auth = useAuthState();\n\n if (auth.isLoading) {\n return <FullPageLoader />;\n }\n\n if (!auth.isAuthenticated) {\n return <Navigate to=\"/auth/login\" replace />;\n }\n\n return children;\n}\n\nexport function GuestGuard({children}: PropsWithChildren) {\n const auth = useAuthState();\n const search = useSearch({strict: false}) as {redirect?: unknown};\n const router = useRouter();\n const target = sanitizeRedirectPath(search.redirect);\n\n useEffect(() => {\n if (auth.isAuthenticated && target !== undefined) {\n // Bypass the typed route matcher — `target` is an arbitrary same-origin\n // path resolved at runtime, so we let the URL change drive route resolution.\n router.history.replace(target);\n }\n }, [auth.isAuthenticated, target, router]);\n\n if (auth.isLoading) {\n return <FullPageLoader />;\n }\n\n if (auth.isAuthenticated) {\n if (target !== undefined) {\n return <FullPageLoader />;\n }\n return <Navigate to=\"/\" replace />;\n }\n\n return children;\n}\n\nexport function WorkspaceGuard({children}: PropsWithChildren) {\n const auth = useAuthState();\n\n if (auth.isAuthenticated && !auth.hasWorkspace) {\n return <WorkspaceOnboardingPage />;\n }\n\n return children;\n}\n"],"names":["FullPageLoader","Navigate","useRouter","useSearch","useEffect","useAuthState","WorkspaceOnboardingPage","sanitizeRedirectPath","AuthGuard","children","auth","isLoading","isAuthenticated","to","replace","GuestGuard","search","strict","router","target","redirect","undefined","history","WorkspaceGuard","hasWorkspace"],"mappings":";AAAA,SAAQA,cAAc,QAAO,2BAA2B;AACxD,SAAQC,QAAQ,EAAEC,SAAS,EAAEC,SAAS,QAAO,yBAAyB;AACtE,SAAgCC,SAAS,QAAO,QAAQ;AACxD,SAAQC,YAAY,QAAO,2BAA2B;AACtD,SAAQC,uBAAuB,QAAO,sCAAsC;AAC5E,SAAQC,oBAAoB,QAAO,uBAAuB;AAE1D,OAAO,SAASC,UAAU,EAACC,QAAQ,EAAoB;IACrD,MAAMC,OAAOL;IAEb,IAAIK,KAAKC,SAAS,EAAE;QAClB,qBAAO,KAACX;IACV;IAEA,IAAI,CAACU,KAAKE,eAAe,EAAE;QACzB,qBAAO,KAACX;YAASY,IAAG;YAAcC,OAAO;;IAC3C;IAEA,OAAOL;AACT;AAEA,OAAO,SAASM,WAAW,EAACN,QAAQ,EAAoB;IACtD,MAAMC,OAAOL;IACb,MAAMW,SAASb,UAAU;QAACc,QAAQ;IAAK;IACvC,MAAMC,SAAShB;IACf,MAAMiB,SAASZ,qBAAqBS,OAAOI,QAAQ;IAEnDhB,UAAU;QACR,IAAIM,KAAKE,eAAe,IAAIO,WAAWE,WAAW;YAChD,wEAAwE;YACxE,6EAA6E;YAC7EH,OAAOI,OAAO,CAACR,OAAO,CAACK;QACzB;IACF,GAAG;QAACT,KAAKE,eAAe;QAAEO;QAAQD;KAAO;IAEzC,IAAIR,KAAKC,SAAS,EAAE;QAClB,qBAAO,KAACX;IACV;IAEA,IAAIU,KAAKE,eAAe,EAAE;QACxB,IAAIO,WAAWE,WAAW;YACxB,qBAAO,KAACrB;QACV;QACA,qBAAO,KAACC;YAASY,IAAG;YAAIC,OAAO;;IACjC;IAEA,OAAOL;AACT;AAEA,OAAO,SAASc,eAAe,EAACd,QAAQ,EAAoB;IAC1D,MAAMC,OAAOL;IAEb,IAAIK,KAAKE,eAAe,IAAI,CAACF,KAAKc,YAAY,EAAE;QAC9C,qBAAO,KAAClB;IACV;IAEA,OAAOG;AACT"}
1
+ {"version":3,"sources":["../../src/components/auth-guard.tsx"],"sourcesContent":["import {useRouteSearch} from '@shipfox/client-shell/runtime';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {Navigate, useRouter} from '@tanstack/react-router';\nimport {type PropsWithChildren, useEffect} from 'react';\nimport {useAuthState} from '#hooks/use-auth-state.js';\nimport {WorkspaceOnboardingPage} from '#pages/workspace-onboarding-page.js';\nimport {validateRedirectSearch} from '../routes/inputs.js';\nimport {sanitizeRedirectPath} from './redirect-target.js';\n\nexport function AuthGuard({children}: PropsWithChildren) {\n const auth = useAuthState();\n\n if (auth.isLoading) {\n return <FullPageLoader />;\n }\n\n if (!auth.isAuthenticated) {\n return <Navigate to=\"/auth/login\" replace />;\n }\n\n return children;\n}\n\nexport function GuestGuard({children}: PropsWithChildren) {\n const auth = useAuthState();\n const search = useRouteSearch(validateRedirectSearch);\n const router = useRouter();\n const target = sanitizeRedirectPath(search.redirect);\n\n useEffect(() => {\n if (auth.isAuthenticated && target !== undefined) {\n // Bypass the typed route matcher — `target` is an arbitrary same-origin\n // path resolved at runtime, so we let the URL change drive route resolution.\n router.history.replace(target);\n }\n }, [auth.isAuthenticated, target, router]);\n\n if (auth.isLoading) {\n return <FullPageLoader />;\n }\n\n if (auth.isAuthenticated) {\n if (target !== undefined) {\n return <FullPageLoader />;\n }\n return <Navigate to=\"/\" replace />;\n }\n\n return children;\n}\n\nexport function WorkspaceGuard({children}: PropsWithChildren) {\n const auth = useAuthState();\n\n if (auth.isAuthenticated && !auth.hasWorkspace) {\n return <WorkspaceOnboardingPage />;\n }\n\n return children;\n}\n"],"names":["useRouteSearch","FullPageLoader","Navigate","useRouter","useEffect","useAuthState","WorkspaceOnboardingPage","validateRedirectSearch","sanitizeRedirectPath","AuthGuard","children","auth","isLoading","isAuthenticated","to","replace","GuestGuard","search","router","target","redirect","undefined","history","WorkspaceGuard","hasWorkspace"],"mappings":";AAAA,SAAQA,cAAc,QAAO,gCAAgC;AAC7D,SAAQC,cAAc,QAAO,2BAA2B;AACxD,SAAQC,QAAQ,EAAEC,SAAS,QAAO,yBAAyB;AAC3D,SAAgCC,SAAS,QAAO,QAAQ;AACxD,SAAQC,YAAY,QAAO,2BAA2B;AACtD,SAAQC,uBAAuB,QAAO,sCAAsC;AAC5E,SAAQC,sBAAsB,QAAO,sBAAsB;AAC3D,SAAQC,oBAAoB,QAAO,uBAAuB;AAE1D,OAAO,SAASC,UAAU,EAACC,QAAQ,EAAoB;IACrD,MAAMC,OAAON;IAEb,IAAIM,KAAKC,SAAS,EAAE;QAClB,qBAAO,KAACX;IACV;IAEA,IAAI,CAACU,KAAKE,eAAe,EAAE;QACzB,qBAAO,KAACX;YAASY,IAAG;YAAcC,OAAO;;IAC3C;IAEA,OAAOL;AACT;AAEA,OAAO,SAASM,WAAW,EAACN,QAAQ,EAAoB;IACtD,MAAMC,OAAON;IACb,MAAMY,SAASjB,eAAeO;IAC9B,MAAMW,SAASf;IACf,MAAMgB,SAASX,qBAAqBS,OAAOG,QAAQ;IAEnDhB,UAAU;QACR,IAAIO,KAAKE,eAAe,IAAIM,WAAWE,WAAW;YAChD,wEAAwE;YACxE,6EAA6E;YAC7EH,OAAOI,OAAO,CAACP,OAAO,CAACI;QACzB;IACF,GAAG;QAACR,KAAKE,eAAe;QAAEM;QAAQD;KAAO;IAEzC,IAAIP,KAAKC,SAAS,EAAE;QAClB,qBAAO,KAACX;IACV;IAEA,IAAIU,KAAKE,eAAe,EAAE;QACxB,IAAIM,WAAWE,WAAW;YACxB,qBAAO,KAACpB;QACV;QACA,qBAAO,KAACC;YAASY,IAAG;YAAIC,OAAO;;IACjC;IAEA,OAAOL;AACT;AAEA,OAAO,SAASa,eAAe,EAACb,QAAQ,EAAoB;IAC1D,MAAMC,OAAON;IAEb,IAAIM,KAAKE,eAAe,IAAI,CAACF,KAAKa,YAAY,EAAE;QAC9C,qBAAO,KAAClB;IACV;IAEA,OAAOI;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"email-code-verification.d.ts","sourceRoot":"","sources":["../../src/components/email-code-verification.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAY,SAAS,EAAE,GAAG,EAAC,MAAM,OAAO,CAAC;AAMrD,MAAM,WAAW,0BAA0B;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,YAAY,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC;IAChE,UAAU,CAAC,EAAE,GAAG,CAAC,kBAAkB,CAAC,GAAG,SAAS,CAAC;IACjD,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClD;AAQD,wBAAgB,qBAAqB,CAAC,EACpC,WAAW,EACX,SAAS,EACT,qBAAqB,EACrB,WAAmB,EACnB,WAAmB,EACnB,KAAK,EACL,KAA0B,EAC1B,WAA2E,EAC3E,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,iBAAiB,EACjB,QAAQ,GACT,EAAE,0BAA0B,+BAgI5B"}
1
+ {"version":3,"file":"email-code-verification.d.ts","sourceRoot":"","sources":["../../src/components/email-code-verification.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAY,SAAS,EAAE,GAAG,EAAC,MAAM,OAAO,CAAC;AAKrD,MAAM,WAAW,0BAA0B;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,YAAY,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC;IAChE,UAAU,CAAC,EAAE,GAAG,CAAC,kBAAkB,CAAC,GAAG,SAAS,CAAC;IACjD,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClD;AAQD,wBAAgB,qBAAqB,CAAC,EACpC,WAAW,EACX,SAAS,EACT,qBAAqB,EACrB,WAAmB,EACnB,WAAmB,EACnB,KAAK,EACL,KAA0B,EAC1B,WAA2E,EAC3E,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,iBAAiB,EACjB,QAAQ,GACT,EAAE,0BAA0B,+BAgI5B"}
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { AuthShell } from '@shipfox/client-shell/runtime';
2
3
  import { Button } from '@shipfox/react-ui/button';
3
4
  import { Callout } from '@shipfox/react-ui/callout';
4
5
  import { FormField, FormFieldInput } from '@shipfox/react-ui/form-field';
5
6
  import { useCallback, useEffect, useRef, useState } from 'react';
6
- import { AuthShell } from './auth-shell.js';
7
7
  const EIGHT_DIGIT_CODE_RE = /^\d{8}$/u;
8
8
  function timestamp(value) {
9
9
  if (!value) return undefined;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/email-code-verification.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FormField, FormFieldInput} from '@shipfox/react-ui/form-field';\nimport type {HeaderProps} from '@shipfox/react-ui/typography';\nimport type {FormEvent, ReactNode, Ref} from 'react';\nimport {useCallback, useEffect, useRef, useState} from 'react';\nimport {AuthShell} from './auth-shell.js';\n\nconst EIGHT_DIGIT_CODE_RE = /^\\d{8}$/u;\n\nexport interface EmailCodeVerificationProps {\n destination: string;\n expiresAt?: string | undefined;\n nextResendAvailableAt?: string | undefined;\n isResending?: boolean;\n isVerifying?: boolean;\n error?: string | undefined;\n title?: string;\n description?: string;\n children?: ReactNode;\n headingProps?: Omit<HeaderProps, 'children' | 'id'> | undefined;\n headingRef?: Ref<HTMLHeadingElement> | undefined;\n onResend: () => void | Promise<void>;\n onUseAnotherEmail: () => void;\n onVerify: (code: string) => void | Promise<void>;\n}\n\nfunction timestamp(value: string | undefined): number | undefined {\n if (!value) return undefined;\n const parsed = Date.parse(value);\n return Number.isNaN(parsed) ? undefined : parsed;\n}\n\nexport function EmailCodeVerification({\n destination,\n expiresAt,\n nextResendAvailableAt,\n isResending = false,\n isVerifying = false,\n error,\n title = 'Check your email',\n description = `We sent an eight-digit verification code to ${destination}.`,\n children,\n headingProps,\n headingRef,\n onResend,\n onUseAnotherEmail,\n onVerify,\n}: EmailCodeVerificationProps) {\n const [code, setCode] = useState('');\n const [now, setNow] = useState(() => Date.now());\n const [codeError, setCodeError] = useState<string>();\n const localHeadingRef = useRef<HTMLHeadingElement>(null);\n const resendAvailableAt = timestamp(nextResendAvailableAt);\n const expiration = timestamp(expiresAt);\n const resendRemainingSeconds = resendAvailableAt\n ? Math.max(0, Math.ceil((resendAvailableAt - now) / 1_000))\n : 0;\n const isResendCoolingDown = resendRemainingSeconds > 0;\n const isExpired = expiration !== undefined && expiration <= now;\n const isPending = isResending || isVerifying;\n\n useEffect(() => {\n const isPending = (tickNow: number) =>\n (resendAvailableAt !== undefined && resendAvailableAt > tickNow) ||\n (expiration !== undefined && expiration > tickNow);\n\n const tickNow = Date.now();\n setNow(tickNow);\n if (!isPending(tickNow)) return;\n\n const interval = window.setInterval(() => {\n const nextTick = Date.now();\n setNow(nextTick);\n if (!isPending(nextTick)) {\n window.clearInterval(interval);\n }\n }, 1_000);\n return () => window.clearInterval(interval);\n }, [expiration, resendAvailableAt]);\n\n useEffect(() => {\n localHeadingRef.current?.focus();\n }, []);\n\n const setHeadingRef = useCallback(\n (heading: HTMLHeadingElement | null) => {\n localHeadingRef.current = heading;\n if (typeof headingRef === 'function') {\n headingRef(heading);\n } else if (headingRef) {\n headingRef.current = heading;\n }\n },\n [headingRef],\n );\n\n function submit(event: FormEvent<HTMLFormElement>) {\n event.preventDefault();\n if (isExpired || isVerifying) return;\n if (!validateCode()) return;\n void onVerify(code);\n }\n\n function validateCode() {\n const error = EIGHT_DIGIT_CODE_RE.test(code)\n ? undefined\n : 'Enter the eight-digit verification code.';\n setCodeError(error);\n return error === undefined;\n }\n\n return (\n <AuthShell\n title={title}\n description={description}\n headingProps={headingProps}\n headingRef={setHeadingRef}\n >\n {error ? (\n <Callout role=\"alert\" type=\"error\">\n {error}\n </Callout>\n ) : null}\n {isExpired ? (\n <Callout role=\"alert\" type=\"error\">\n This verification code has expired. Use another email to try again.\n </Callout>\n ) : null}\n <form className=\"flex flex-col gap-8\" noValidate onSubmit={submit}>\n <FormField label=\"Verification code\" id=\"verification-code\" error={codeError}>\n <FormFieldInput\n autoComplete=\"one-time-code\"\n inputMode=\"numeric\"\n maxLength={8}\n pattern=\"[0-9]{8}\"\n value={code}\n onChange={(event) => {\n setCode(event.target.value.replace(/\\D/gu, '').slice(0, 8));\n setCodeError(undefined);\n }}\n onBlur={validateCode}\n />\n </FormField>\n <Button className=\"w-full\" type=\"submit\" disabled={isExpired} isLoading={isVerifying}>\n Verify email\n </Button>\n <Button\n aria-disabled={isResendCoolingDown ? true : undefined}\n className=\"w-full aria-disabled:cursor-not-allowed aria-disabled:opacity-70\"\n variant=\"secondary\"\n type=\"button\"\n isLoading={isResending}\n onClick={() => {\n if (!isResendCoolingDown && !isResending) void onResend();\n }}\n >\n {isResending\n ? 'Sending email...'\n : isResendCoolingDown\n ? `Resend in ${resendRemainingSeconds}s`\n : 'Resend verification email'}\n </Button>\n </form>\n <Button\n className=\"w-full\"\n variant=\"transparent\"\n type=\"button\"\n disabled={isPending}\n onClick={onUseAnotherEmail}\n >\n Use another email\n </Button>\n {children}\n </AuthShell>\n );\n}\n"],"names":["Button","Callout","FormField","FormFieldInput","useCallback","useEffect","useRef","useState","AuthShell","EIGHT_DIGIT_CODE_RE","timestamp","value","undefined","parsed","Date","parse","Number","isNaN","EmailCodeVerification","destination","expiresAt","nextResendAvailableAt","isResending","isVerifying","error","title","description","children","headingProps","headingRef","onResend","onUseAnotherEmail","onVerify","code","setCode","now","setNow","codeError","setCodeError","localHeadingRef","resendAvailableAt","expiration","resendRemainingSeconds","Math","max","ceil","isResendCoolingDown","isExpired","isPending","tickNow","interval","window","setInterval","nextTick","clearInterval","current","focus","setHeadingRef","heading","submit","event","preventDefault","validateCode","test","role","type","form","className","noValidate","onSubmit","label","id","autoComplete","inputMode","maxLength","pattern","onChange","target","replace","slice","onBlur","disabled","isLoading","aria-disabled","variant","onClick"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/components/email-code-verification.tsx"],"sourcesContent":["import {AuthShell} from '@shipfox/client-shell/runtime';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FormField, FormFieldInput} from '@shipfox/react-ui/form-field';\nimport type {HeaderProps} from '@shipfox/react-ui/typography';\nimport type {FormEvent, ReactNode, Ref} from 'react';\nimport {useCallback, useEffect, useRef, useState} from 'react';\n\nconst EIGHT_DIGIT_CODE_RE = /^\\d{8}$/u;\n\nexport interface EmailCodeVerificationProps {\n destination: string;\n expiresAt?: string | undefined;\n nextResendAvailableAt?: string | undefined;\n isResending?: boolean;\n isVerifying?: boolean;\n error?: string | undefined;\n title?: string;\n description?: string;\n children?: ReactNode;\n headingProps?: Omit<HeaderProps, 'children' | 'id'> | undefined;\n headingRef?: Ref<HTMLHeadingElement> | undefined;\n onResend: () => void | Promise<void>;\n onUseAnotherEmail: () => void;\n onVerify: (code: string) => void | Promise<void>;\n}\n\nfunction timestamp(value: string | undefined): number | undefined {\n if (!value) return undefined;\n const parsed = Date.parse(value);\n return Number.isNaN(parsed) ? undefined : parsed;\n}\n\nexport function EmailCodeVerification({\n destination,\n expiresAt,\n nextResendAvailableAt,\n isResending = false,\n isVerifying = false,\n error,\n title = 'Check your email',\n description = `We sent an eight-digit verification code to ${destination}.`,\n children,\n headingProps,\n headingRef,\n onResend,\n onUseAnotherEmail,\n onVerify,\n}: EmailCodeVerificationProps) {\n const [code, setCode] = useState('');\n const [now, setNow] = useState(() => Date.now());\n const [codeError, setCodeError] = useState<string>();\n const localHeadingRef = useRef<HTMLHeadingElement>(null);\n const resendAvailableAt = timestamp(nextResendAvailableAt);\n const expiration = timestamp(expiresAt);\n const resendRemainingSeconds = resendAvailableAt\n ? Math.max(0, Math.ceil((resendAvailableAt - now) / 1_000))\n : 0;\n const isResendCoolingDown = resendRemainingSeconds > 0;\n const isExpired = expiration !== undefined && expiration <= now;\n const isPending = isResending || isVerifying;\n\n useEffect(() => {\n const isPending = (tickNow: number) =>\n (resendAvailableAt !== undefined && resendAvailableAt > tickNow) ||\n (expiration !== undefined && expiration > tickNow);\n\n const tickNow = Date.now();\n setNow(tickNow);\n if (!isPending(tickNow)) return;\n\n const interval = window.setInterval(() => {\n const nextTick = Date.now();\n setNow(nextTick);\n if (!isPending(nextTick)) {\n window.clearInterval(interval);\n }\n }, 1_000);\n return () => window.clearInterval(interval);\n }, [expiration, resendAvailableAt]);\n\n useEffect(() => {\n localHeadingRef.current?.focus();\n }, []);\n\n const setHeadingRef = useCallback(\n (heading: HTMLHeadingElement | null) => {\n localHeadingRef.current = heading;\n if (typeof headingRef === 'function') {\n headingRef(heading);\n } else if (headingRef) {\n headingRef.current = heading;\n }\n },\n [headingRef],\n );\n\n function submit(event: FormEvent<HTMLFormElement>) {\n event.preventDefault();\n if (isExpired || isVerifying) return;\n if (!validateCode()) return;\n void onVerify(code);\n }\n\n function validateCode() {\n const error = EIGHT_DIGIT_CODE_RE.test(code)\n ? undefined\n : 'Enter the eight-digit verification code.';\n setCodeError(error);\n return error === undefined;\n }\n\n return (\n <AuthShell\n title={title}\n description={description}\n headingProps={headingProps}\n headingRef={setHeadingRef}\n >\n {error ? (\n <Callout role=\"alert\" type=\"error\">\n {error}\n </Callout>\n ) : null}\n {isExpired ? (\n <Callout role=\"alert\" type=\"error\">\n This verification code has expired. Use another email to try again.\n </Callout>\n ) : null}\n <form className=\"flex flex-col gap-8\" noValidate onSubmit={submit}>\n <FormField label=\"Verification code\" id=\"verification-code\" error={codeError}>\n <FormFieldInput\n autoComplete=\"one-time-code\"\n inputMode=\"numeric\"\n maxLength={8}\n pattern=\"[0-9]{8}\"\n value={code}\n onChange={(event) => {\n setCode(event.target.value.replace(/\\D/gu, '').slice(0, 8));\n setCodeError(undefined);\n }}\n onBlur={validateCode}\n />\n </FormField>\n <Button className=\"w-full\" type=\"submit\" disabled={isExpired} isLoading={isVerifying}>\n Verify email\n </Button>\n <Button\n aria-disabled={isResendCoolingDown ? true : undefined}\n className=\"w-full aria-disabled:cursor-not-allowed aria-disabled:opacity-70\"\n variant=\"secondary\"\n type=\"button\"\n isLoading={isResending}\n onClick={() => {\n if (!isResendCoolingDown && !isResending) void onResend();\n }}\n >\n {isResending\n ? 'Sending email...'\n : isResendCoolingDown\n ? `Resend in ${resendRemainingSeconds}s`\n : 'Resend verification email'}\n </Button>\n </form>\n <Button\n className=\"w-full\"\n variant=\"transparent\"\n type=\"button\"\n disabled={isPending}\n onClick={onUseAnotherEmail}\n >\n Use another email\n </Button>\n {children}\n </AuthShell>\n );\n}\n"],"names":["AuthShell","Button","Callout","FormField","FormFieldInput","useCallback","useEffect","useRef","useState","EIGHT_DIGIT_CODE_RE","timestamp","value","undefined","parsed","Date","parse","Number","isNaN","EmailCodeVerification","destination","expiresAt","nextResendAvailableAt","isResending","isVerifying","error","title","description","children","headingProps","headingRef","onResend","onUseAnotherEmail","onVerify","code","setCode","now","setNow","codeError","setCodeError","localHeadingRef","resendAvailableAt","expiration","resendRemainingSeconds","Math","max","ceil","isResendCoolingDown","isExpired","isPending","tickNow","interval","window","setInterval","nextTick","clearInterval","current","focus","setHeadingRef","heading","submit","event","preventDefault","validateCode","test","role","type","form","className","noValidate","onSubmit","label","id","autoComplete","inputMode","maxLength","pattern","onChange","target","replace","slice","onBlur","disabled","isLoading","aria-disabled","variant","onClick"],"mappings":"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"}
@@ -1,2 +1,9 @@
1
1
  export declare function sanitizeRedirectPath(value: unknown): string | undefined;
2
+ /**
3
+ * Returns the destination used by the shared logout route.
4
+ *
5
+ * Login is the only auth destination allowed, and invitation tokens never
6
+ * survive this boundary. Invalid values fail closed to login.
7
+ */
8
+ export declare function sanitizeLogoutRedirectPath(value: unknown): string;
2
9
  //# sourceMappingURL=redirect-target.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"redirect-target.d.ts","sourceRoot":"","sources":["../../src/components/redirect-target.ts"],"names":[],"mappings":"AAIA,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAiBvE"}
1
+ {"version":3,"file":"redirect-target.d.ts","sourceRoot":"","sources":["../../src/components/redirect-target.ts"],"names":[],"mappings":"AAkCA,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAIvE;AAOD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAOjE"}
@@ -1,7 +1,9 @@
1
1
  const REDIRECT_ORIGIN = 'https://shipfox-redirect.invalid';
2
- // Resolves and canonicalizes an internal path before returning it, so browser URL
3
- // parsing cannot turn a seemingly safe path into an external or auth route.
4
- export function sanitizeRedirectPath(value) {
2
+ const LOGIN_PATH = '/auth/login';
3
+ const INVITATION_ACCEPT_PATH = '/invitations/accept';
4
+ const DEFAULT_LOGOUT_REDIRECT = LOGIN_PATH;
5
+ const TRAILING_SLASHES = /\/+$/;
6
+ function resolveRedirectPath(value) {
5
7
  if (typeof value !== 'string' || !value.startsWith('/')) return undefined;
6
8
  let decoded;
7
9
  try {
@@ -16,8 +18,37 @@ export function sanitizeRedirectPath(value) {
16
18
  return undefined;
17
19
  }
18
20
  if (target.origin !== REDIRECT_ORIGIN) return undefined;
19
- if (target.pathname === '/auth' || target.pathname.startsWith('/auth/')) return undefined;
21
+ return target;
22
+ }
23
+ function formatRedirectPath(target) {
20
24
  return `${target.pathname}${target.search}${target.hash}`;
21
25
  }
26
+ function isAuthPath(pathname) {
27
+ return pathname === '/auth' || pathname.startsWith('/auth/');
28
+ }
29
+ // Resolves and canonicalizes an internal path before returning it, so browser URL
30
+ // parsing cannot turn a seemingly safe path into an external or auth route.
31
+ export function sanitizeRedirectPath(value) {
32
+ const target = resolveRedirectPath(value);
33
+ if (!target || isAuthPath(target.pathname)) return undefined;
34
+ return formatRedirectPath(target);
35
+ }
36
+ function containsInvitationToken(target) {
37
+ const normalizedPathname = target.pathname.replace(TRAILING_SLASHES, '') || '/';
38
+ return normalizedPathname === INVITATION_ACCEPT_PATH && target.searchParams.has('token');
39
+ }
40
+ /**
41
+ * Returns the destination used by the shared logout route.
42
+ *
43
+ * Login is the only auth destination allowed, and invitation tokens never
44
+ * survive this boundary. Invalid values fail closed to login.
45
+ */ export function sanitizeLogoutRedirectPath(value) {
46
+ const target = resolveRedirectPath(value);
47
+ if (!target) return DEFAULT_LOGOUT_REDIRECT;
48
+ if (isAuthPath(target.pathname) || containsInvitationToken(target)) {
49
+ return DEFAULT_LOGOUT_REDIRECT;
50
+ }
51
+ return formatRedirectPath(target);
52
+ }
22
53
 
23
54
  //# sourceMappingURL=redirect-target.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/redirect-target.ts"],"sourcesContent":["const REDIRECT_ORIGIN = 'https://shipfox-redirect.invalid';\n\n// Resolves and canonicalizes an internal path before returning it, so browser URL\n// parsing cannot turn a seemingly safe path into an external or auth route.\nexport function sanitizeRedirectPath(value: unknown): string | undefined {\n if (typeof value !== 'string' || !value.startsWith('/')) return undefined;\n let decoded: string;\n try {\n decoded = decodeURIComponent(value);\n } catch {\n return undefined;\n }\n let target: URL;\n try {\n target = new URL(decoded, REDIRECT_ORIGIN);\n } catch {\n return undefined;\n }\n if (target.origin !== REDIRECT_ORIGIN) return undefined;\n if (target.pathname === '/auth' || target.pathname.startsWith('/auth/')) return undefined;\n return `${target.pathname}${target.search}${target.hash}`;\n}\n"],"names":["REDIRECT_ORIGIN","sanitizeRedirectPath","value","startsWith","undefined","decoded","decodeURIComponent","target","URL","origin","pathname","search","hash"],"mappings":"AAAA,MAAMA,kBAAkB;AAExB,kFAAkF;AAClF,4EAA4E;AAC5E,OAAO,SAASC,qBAAqBC,KAAc;IACjD,IAAI,OAAOA,UAAU,YAAY,CAACA,MAAMC,UAAU,CAAC,MAAM,OAAOC;IAChE,IAAIC;IACJ,IAAI;QACFA,UAAUC,mBAAmBJ;IAC/B,EAAE,OAAM;QACN,OAAOE;IACT;IACA,IAAIG;IACJ,IAAI;QACFA,SAAS,IAAIC,IAAIH,SAASL;IAC5B,EAAE,OAAM;QACN,OAAOI;IACT;IACA,IAAIG,OAAOE,MAAM,KAAKT,iBAAiB,OAAOI;IAC9C,IAAIG,OAAOG,QAAQ,KAAK,WAAWH,OAAOG,QAAQ,CAACP,UAAU,CAAC,WAAW,OAAOC;IAChF,OAAO,GAAGG,OAAOG,QAAQ,GAAGH,OAAOI,MAAM,GAAGJ,OAAOK,IAAI,EAAE;AAC3D"}
1
+ {"version":3,"sources":["../../src/components/redirect-target.ts"],"sourcesContent":["const REDIRECT_ORIGIN = 'https://shipfox-redirect.invalid';\nconst LOGIN_PATH = '/auth/login';\nconst INVITATION_ACCEPT_PATH = '/invitations/accept';\nconst DEFAULT_LOGOUT_REDIRECT = LOGIN_PATH;\nconst TRAILING_SLASHES = /\\/+$/;\n\nfunction resolveRedirectPath(value: unknown): URL | undefined {\n if (typeof value !== 'string' || !value.startsWith('/')) return undefined;\n let decoded: string;\n try {\n decoded = decodeURIComponent(value);\n } catch {\n return undefined;\n }\n let target: URL;\n try {\n target = new URL(decoded, REDIRECT_ORIGIN);\n } catch {\n return undefined;\n }\n if (target.origin !== REDIRECT_ORIGIN) return undefined;\n return target;\n}\n\nfunction formatRedirectPath(target: URL): string {\n return `${target.pathname}${target.search}${target.hash}`;\n}\n\nfunction isAuthPath(pathname: string): boolean {\n return pathname === '/auth' || pathname.startsWith('/auth/');\n}\n\n// Resolves and canonicalizes an internal path before returning it, so browser URL\n// parsing cannot turn a seemingly safe path into an external or auth route.\nexport function sanitizeRedirectPath(value: unknown): string | undefined {\n const target = resolveRedirectPath(value);\n if (!target || isAuthPath(target.pathname)) return undefined;\n return formatRedirectPath(target);\n}\n\nfunction containsInvitationToken(target: URL): boolean {\n const normalizedPathname = target.pathname.replace(TRAILING_SLASHES, '') || '/';\n return normalizedPathname === INVITATION_ACCEPT_PATH && target.searchParams.has('token');\n}\n\n/**\n * Returns the destination used by the shared logout route.\n *\n * Login is the only auth destination allowed, and invitation tokens never\n * survive this boundary. Invalid values fail closed to login.\n */\nexport function sanitizeLogoutRedirectPath(value: unknown): string {\n const target = resolveRedirectPath(value);\n if (!target) return DEFAULT_LOGOUT_REDIRECT;\n if (isAuthPath(target.pathname) || containsInvitationToken(target)) {\n return DEFAULT_LOGOUT_REDIRECT;\n }\n return formatRedirectPath(target);\n}\n"],"names":["REDIRECT_ORIGIN","LOGIN_PATH","INVITATION_ACCEPT_PATH","DEFAULT_LOGOUT_REDIRECT","TRAILING_SLASHES","resolveRedirectPath","value","startsWith","undefined","decoded","decodeURIComponent","target","URL","origin","formatRedirectPath","pathname","search","hash","isAuthPath","sanitizeRedirectPath","containsInvitationToken","normalizedPathname","replace","searchParams","has","sanitizeLogoutRedirectPath"],"mappings":"AAAA,MAAMA,kBAAkB;AACxB,MAAMC,aAAa;AACnB,MAAMC,yBAAyB;AAC/B,MAAMC,0BAA0BF;AAChC,MAAMG,mBAAmB;AAEzB,SAASC,oBAAoBC,KAAc;IACzC,IAAI,OAAOA,UAAU,YAAY,CAACA,MAAMC,UAAU,CAAC,MAAM,OAAOC;IAChE,IAAIC;IACJ,IAAI;QACFA,UAAUC,mBAAmBJ;IAC/B,EAAE,OAAM;QACN,OAAOE;IACT;IACA,IAAIG;IACJ,IAAI;QACFA,SAAS,IAAIC,IAAIH,SAAST;IAC5B,EAAE,OAAM;QACN,OAAOQ;IACT;IACA,IAAIG,OAAOE,MAAM,KAAKb,iBAAiB,OAAOQ;IAC9C,OAAOG;AACT;AAEA,SAASG,mBAAmBH,MAAW;IACrC,OAAO,GAAGA,OAAOI,QAAQ,GAAGJ,OAAOK,MAAM,GAAGL,OAAOM,IAAI,EAAE;AAC3D;AAEA,SAASC,WAAWH,QAAgB;IAClC,OAAOA,aAAa,WAAWA,SAASR,UAAU,CAAC;AACrD;AAEA,kFAAkF;AAClF,4EAA4E;AAC5E,OAAO,SAASY,qBAAqBb,KAAc;IACjD,MAAMK,SAASN,oBAAoBC;IACnC,IAAI,CAACK,UAAUO,WAAWP,OAAOI,QAAQ,GAAG,OAAOP;IACnD,OAAOM,mBAAmBH;AAC5B;AAEA,SAASS,wBAAwBT,MAAW;IAC1C,MAAMU,qBAAqBV,OAAOI,QAAQ,CAACO,OAAO,CAAClB,kBAAkB,OAAO;IAC5E,OAAOiB,uBAAuBnB,0BAA0BS,OAAOY,YAAY,CAACC,GAAG,CAAC;AAClF;AAEA;;;;;CAKC,GACD,OAAO,SAASC,2BAA2BnB,KAAc;IACvD,MAAMK,SAASN,oBAAoBC;IACnC,IAAI,CAACK,QAAQ,OAAOR;IACpB,IAAIe,WAAWP,OAAOI,QAAQ,KAAKK,wBAAwBT,SAAS;QAClE,OAAOR;IACT;IACA,OAAOW,mBAAmBH;AAC5B"}
@@ -13,7 +13,7 @@ declare const meta: {
13
13
  };
14
14
  args: {
15
15
  activeWorkspaceId: string;
16
- workspaces: Workspace[];
16
+ workspaces: import("@shipfox/client-shell/runtime").WorkspaceSummary[];
17
17
  };
18
18
  };
19
19
  export default meta;
@@ -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 { EmailCodeVerification, type EmailCodeVerificationProps, } from './components/email-code-verification.js';
3
3
  export { parseRedirectContext, type RedirectContext } from './components/redirect-context.js';
4
4
  //# sourceMappingURL=continuation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"continuation.d.ts","sourceRoot":"","sources":["../src/continuation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAE,SAAS,EAAE,KAAK,cAAc,EAAC,MAAM,4BAA4B,CAAC;AACvF,OAAO,EACL,qBAAqB,EACrB,KAAK,0BAA0B,GAChC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAC,oBAAoB,EAAE,KAAK,eAAe,EAAC,MAAM,kCAAkC,CAAC"}
1
+ {"version":3,"file":"continuation.d.ts","sourceRoot":"","sources":["../src/continuation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAE,SAAS,EAAE,KAAK,cAAc,EAAC,MAAM,+BAA+B,CAAC;AAC1F,OAAO,EACL,qBAAqB,EACrB,KAAK,0BAA0B,GAChC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAC,oBAAoB,EAAE,KAAK,eAAe,EAAC,MAAM,kCAAkC,CAAC"}
@@ -1,4 +1,4 @@
1
- export { AuthActions, AuthShell } from './components/auth-shell.js';
1
+ export { AuthActions, AuthShell } from '@shipfox/client-shell/runtime';
2
2
  export { EmailCodeVerification } from './components/email-code-verification.js';
3
3
  export { parseRedirectContext } from './components/redirect-context.js';
4
4
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/continuation.ts"],"sourcesContent":["export {AuthActions, AuthShell, type AuthShellProps} from './components/auth-shell.js';\nexport {\n EmailCodeVerification,\n type EmailCodeVerificationProps,\n} from './components/email-code-verification.js';\nexport {parseRedirectContext, type RedirectContext} from './components/redirect-context.js';\n"],"names":["AuthActions","AuthShell","EmailCodeVerification","parseRedirectContext"],"mappings":"AAAA,SAAQA,WAAW,EAAEC,SAAS,QAA4B,6BAA6B;AACvF,SACEC,qBAAqB,QAEhB,0CAA0C;AACjD,SAAQC,oBAAoB,QAA6B,mCAAmC"}
1
+ {"version":3,"sources":["../src/continuation.ts"],"sourcesContent":["export {AuthActions, AuthShell, type AuthShellProps} from '@shipfox/client-shell/runtime';\nexport {\n EmailCodeVerification,\n type EmailCodeVerificationProps,\n} from './components/email-code-verification.js';\nexport {parseRedirectContext, type RedirectContext} from './components/redirect-context.js';\n"],"names":["AuthActions","AuthShell","EmailCodeVerification","parseRedirectContext"],"mappings":"AAAA,SAAQA,WAAW,EAAEC,SAAS,QAA4B,gCAAgC;AAC1F,SACEC,qBAAqB,QAEhB,0CAA0C;AACjD,SAAQC,oBAAoB,QAA6B,mCAAmC"}
@@ -0,0 +1,57 @@
1
+ export interface LoginCommand {
2
+ email: string;
3
+ password: string;
4
+ }
5
+ export interface SignupCommand extends LoginCommand {
6
+ name: string;
7
+ invitationToken?: string;
8
+ }
9
+ export interface PasswordResetRequestCommand {
10
+ email: string;
11
+ }
12
+ export interface PasswordResetConfirmCommand {
13
+ token: string;
14
+ newPassword: string;
15
+ }
16
+ export interface VerifyEmailCommand {
17
+ email: string;
18
+ challengeId: string;
19
+ code: string;
20
+ }
21
+ export interface ResendEmailVerificationCommand {
22
+ email: string;
23
+ challengeId: string;
24
+ }
25
+ export interface WorkspaceCreateCommand {
26
+ name: string;
27
+ }
28
+ export interface Workspace {
29
+ id: string;
30
+ name: string;
31
+ status: 'active' | 'suspended' | 'deleted';
32
+ }
33
+ export interface SignupResult {
34
+ user: {
35
+ id: string;
36
+ email: string;
37
+ name?: string;
38
+ emailVerifiedAt?: string;
39
+ };
40
+ emailChallenge?: {
41
+ id: string;
42
+ nextResendAvailableAt: string;
43
+ };
44
+ membership?: {
45
+ id: string;
46
+ userId: string;
47
+ workspaceId: string;
48
+ };
49
+ acceptError?: {
50
+ code: string;
51
+ message: string;
52
+ };
53
+ }
54
+ export interface EmailVerificationResendResult {
55
+ nextResendAvailableAt: string;
56
+ }
57
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/core/auth.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,8BAA8B;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;CAC5C;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,cAAc,CAAC,EAAE;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,qBAAqB,EAAE,MAAM,CAAA;KAAC,CAAC;IAC7D,UAAU,CAAC,EAAE;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAC,CAAC;IAC/D,WAAW,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC;CAC/C;AAED,MAAM,WAAW,6BAA6B;IAC5C,qBAAqB,EAAE,MAAM,CAAC;CAC/B"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/auth.ts"],"sourcesContent":["export interface LoginCommand {\n email: string;\n password: string;\n}\n\nexport interface SignupCommand extends LoginCommand {\n name: string;\n invitationToken?: string;\n}\n\nexport interface PasswordResetRequestCommand {\n email: string;\n}\n\nexport interface PasswordResetConfirmCommand {\n token: string;\n newPassword: string;\n}\n\nexport interface VerifyEmailCommand {\n email: string;\n challengeId: string;\n code: string;\n}\n\nexport interface ResendEmailVerificationCommand {\n email: string;\n challengeId: string;\n}\n\nexport interface WorkspaceCreateCommand {\n name: string;\n}\n\nexport interface Workspace {\n id: string;\n name: string;\n status: 'active' | 'suspended' | 'deleted';\n}\n\nexport interface SignupResult {\n user: {\n id: string;\n email: string;\n name?: string;\n emailVerifiedAt?: string;\n };\n emailChallenge?: {id: string; nextResendAvailableAt: string};\n membership?: {id: string; userId: string; workspaceId: string};\n acceptError?: {code: string; message: string};\n}\n\nexport interface EmailVerificationResendResult {\n nextResendAvailableAt: string;\n}\n"],"names":[],"mappings":"AAoDA,WAEC"}
@@ -0,0 +1,6 @@
1
+ import type { SignupResponseDto } from '@shipfox/api-auth-dto';
2
+ import { toAuthenticatedSession } from '@shipfox/client-shell/runtime';
3
+ import type { SignupResult } from '#core/auth.js';
4
+ export { toAuthenticatedSession };
5
+ export declare function toSignupResult(dto: SignupResponseDto): SignupResult;
6
+ //# sourceMappingURL=auth-mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-mapper.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/auth-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAC,sBAAsB,EAAiB,MAAM,+BAA+B,CAAC;AACrF,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAC,sBAAsB,EAAC,CAAC;AAEhC,wBAAgB,cAAc,CAAC,GAAG,EAAE,iBAAiB,GAAG,YAAY,CAsBnE"}
@@ -0,0 +1,25 @@
1
+ import { toAuthenticatedSession, toUserIdentity } from '@shipfox/client-shell/runtime';
2
+ export { toAuthenticatedSession };
3
+ export function toSignupResult(dto) {
4
+ return {
5
+ user: toUserIdentity(dto.user),
6
+ ...dto.email_challenge ? {
7
+ emailChallenge: {
8
+ id: dto.email_challenge.id,
9
+ nextResendAvailableAt: dto.email_challenge.next_resend_available_at
10
+ }
11
+ } : {},
12
+ ...dto.membership ? {
13
+ membership: {
14
+ id: dto.membership.id,
15
+ userId: dto.membership.user_id,
16
+ workspaceId: dto.membership.workspace_id
17
+ }
18
+ } : {},
19
+ ...dto.accept_error ? {
20
+ acceptError: dto.accept_error
21
+ } : {}
22
+ };
23
+ }
24
+
25
+ //# sourceMappingURL=auth-mapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hooks/api/auth-mapper.ts"],"sourcesContent":["import type {SignupResponseDto} from '@shipfox/api-auth-dto';\nimport {toAuthenticatedSession, toUserIdentity} from '@shipfox/client-shell/runtime';\nimport type {SignupResult} from '#core/auth.js';\n\nexport {toAuthenticatedSession};\n\nexport function toSignupResult(dto: SignupResponseDto): SignupResult {\n return {\n user: toUserIdentity(dto.user),\n ...(dto.email_challenge\n ? {\n emailChallenge: {\n id: dto.email_challenge.id,\n nextResendAvailableAt: dto.email_challenge.next_resend_available_at,\n },\n }\n : {}),\n ...(dto.membership\n ? {\n membership: {\n id: dto.membership.id,\n userId: dto.membership.user_id,\n workspaceId: dto.membership.workspace_id,\n },\n }\n : {}),\n ...(dto.accept_error ? {acceptError: dto.accept_error} : {}),\n };\n}\n"],"names":["toAuthenticatedSession","toUserIdentity","toSignupResult","dto","user","email_challenge","emailChallenge","id","nextResendAvailableAt","next_resend_available_at","membership","userId","user_id","workspaceId","workspace_id","accept_error","acceptError"],"mappings":"AACA,SAAQA,sBAAsB,EAAEC,cAAc,QAAO,gCAAgC;AAGrF,SAAQD,sBAAsB,GAAE;AAEhC,OAAO,SAASE,eAAeC,GAAsB;IACnD,OAAO;QACLC,MAAMH,eAAeE,IAAIC,IAAI;QAC7B,GAAID,IAAIE,eAAe,GACnB;YACEC,gBAAgB;gBACdC,IAAIJ,IAAIE,eAAe,CAACE,EAAE;gBAC1BC,uBAAuBL,IAAIE,eAAe,CAACI,wBAAwB;YACrE;QACF,IACA,CAAC,CAAC;QACN,GAAIN,IAAIO,UAAU,GACd;YACEA,YAAY;gBACVH,IAAIJ,IAAIO,UAAU,CAACH,EAAE;gBACrBI,QAAQR,IAAIO,UAAU,CAACE,OAAO;gBAC9BC,aAAaV,IAAIO,UAAU,CAACI,YAAY;YAC1C;QACF,IACA,CAAC,CAAC;QACN,GAAIX,IAAIY,YAAY,GAAG;YAACC,aAAab,IAAIY,YAAY;QAAA,IAAI,CAAC,CAAC;IAC7D;AACF"}
@@ -1,29 +1,4 @@
1
- import type { LoginBodyDto } from '@shipfox/api-auth-dto';
2
- export declare function loginAuth(body: LoginBodyDto): Promise<{
3
- token: string;
4
- user: {
5
- id: string;
6
- email: string;
7
- name: string | null;
8
- email_verified_at: string | null;
9
- status: "active" | "suspended" | "deleted";
10
- created_at: string;
11
- updated_at: string;
12
- };
13
- }>;
14
- export declare function useLoginAuth(): import("@tanstack/react-query").UseMutationResult<{
15
- token: string;
16
- user: {
17
- id: string;
18
- email: string;
19
- name: string | null;
20
- email_verified_at: string | null;
21
- status: "active" | "suspended" | "deleted";
22
- created_at: string;
23
- updated_at: string;
24
- };
25
- }, Error, {
26
- email: string;
27
- password: string;
28
- }, unknown>;
1
+ import type { LoginCommand } from '#core/auth.js';
2
+ export declare function loginAuth(command: LoginCommand): Promise<import("@shipfox/client-shell/runtime").AuthenticatedSession>;
3
+ export declare function useLoginAuth(): import("@tanstack/react-query").UseMutationResult<import("@shipfox/client-shell/runtime").AuthenticatedSession, Error, LoginCommand, unknown>;
29
4
  //# sourceMappingURL=login-auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"login-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/login-auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAmB,MAAM,uBAAuB,CAAC;AAK1E,wBAAsB,SAAS,CAAC,IAAI,EAAE,YAAY;;;;;;;;;;;GAEjD;AAED,wBAAgB,YAAY;;;;;;;;;;;;;;YAO3B"}
1
+ {"version":3,"file":"login-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/login-auth.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,eAAe,CAAC;AAIhD,wBAAsB,SAAS,CAAC,OAAO,EAAE,YAAY,yEAMpD;AAED,wBAAgB,YAAY,kJAO3B"}
@@ -1,11 +1,14 @@
1
- import { apiRequest } from '@shipfox/client-api';
1
+ import { loginResponseSchema } 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
- export async function loginAuth(body) {
5
- return await apiRequest('/auth/login', {
5
+ import { toAuthenticatedSession } from './auth-mapper.js';
6
+ export async function loginAuth(command) {
7
+ const response = await checkedApiRequest(loginResponseSchema, '/auth/login', {
6
8
  method: 'POST',
7
- body
9
+ body: command
8
10
  });
11
+ return toAuthenticatedSession(response);
9
12
  }
10
13
  export function useLoginAuth() {
11
14
  const { enterAuthenticated } = useAuthTransition();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/api/login-auth.ts"],"sourcesContent":["import type {LoginBodyDto, LoginResponseDto} 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 loginAuth(body: LoginBodyDto) {\n return await apiRequest<LoginResponseDto>('/auth/login', {method: 'POST', body});\n}\n\nexport function useLoginAuth() {\n const {enterAuthenticated} = useAuthTransition();\n\n return useMutation({\n mutationFn: loginAuth,\n onSuccess: enterAuthenticated,\n });\n}\n"],"names":["apiRequest","useMutation","useAuthTransition","loginAuth","body","method","useLoginAuth","enterAuthenticated","mutationFn","onSuccess"],"mappings":"AACA,SAAQA,UAAU,QAAO,sBAAsB;AAC/C,SAAQC,WAAW,QAAO,wBAAwB;AAClD,SAAQC,iBAAiB,QAAO,iBAAiB;AAEjD,OAAO,eAAeC,UAAUC,IAAkB;IAChD,OAAO,MAAMJ,WAA6B,eAAe;QAACK,QAAQ;QAAQD;IAAI;AAChF;AAEA,OAAO,SAASE;IACd,MAAM,EAACC,kBAAkB,EAAC,GAAGL;IAE7B,OAAOD,YAAY;QACjBO,YAAYL;QACZM,WAAWF;IACb;AACF"}
1
+ {"version":3,"sources":["../../../src/hooks/api/login-auth.ts"],"sourcesContent":["import {loginResponseSchema} from '@shipfox/api-auth-dto';\nimport {checkedApiRequest} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport type {LoginCommand} from '#core/auth.js';\nimport {useAuthTransition} from '#state/auth.js';\nimport {toAuthenticatedSession} from './auth-mapper.js';\n\nexport async function loginAuth(command: LoginCommand) {\n const response = await checkedApiRequest(loginResponseSchema, '/auth/login', {\n method: 'POST',\n body: command,\n });\n return toAuthenticatedSession(response);\n}\n\nexport function useLoginAuth() {\n const {enterAuthenticated} = useAuthTransition();\n\n return useMutation({\n mutationFn: loginAuth,\n onSuccess: enterAuthenticated,\n });\n}\n"],"names":["loginResponseSchema","checkedApiRequest","useMutation","useAuthTransition","toAuthenticatedSession","loginAuth","command","response","method","body","useLoginAuth","enterAuthenticated","mutationFn","onSuccess"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,wBAAwB;AAC1D,SAAQC,iBAAiB,QAAO,sBAAsB;AACtD,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,iBAAiB,QAAO,iBAAiB;AACjD,SAAQC,sBAAsB,QAAO,mBAAmB;AAExD,OAAO,eAAeC,UAAUC,OAAqB;IACnD,MAAMC,WAAW,MAAMN,kBAAkBD,qBAAqB,eAAe;QAC3EQ,QAAQ;QACRC,MAAMH;IACR;IACA,OAAOF,uBAAuBG;AAChC;AAEA,OAAO,SAASG;IACd,MAAM,EAACC,kBAAkB,EAAC,GAAGR;IAE7B,OAAOD,YAAY;QACjBU,YAAYP;QACZQ,WAAWF;IACb;AACF"}
@@ -1,9 +1,9 @@
1
- import { apiRequest } from '@shipfox/client-api';
1
+ import { checkedApiRequest, emptyResponseSchema } from '@shipfox/client-api';
2
2
  import { useMutation } from '@tanstack/react-query';
3
3
  import { useAuthTransition } from '#state/auth.js';
4
4
  async function logoutAuth() {
5
5
  try {
6
- await apiRequest('/auth/logout', {
6
+ await checkedApiRequest(emptyResponseSchema, '/auth/logout', {
7
7
  method: 'POST',
8
8
  body: {}
9
9
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/api/logout-auth.ts"],"sourcesContent":["import {apiRequest} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport {useAuthTransition} from '#state/auth.js';\n\nasync function logoutAuth() {\n try {\n await apiRequest<void>('/auth/logout', {method: 'POST', body: {}});\n } catch {\n // Logout is best-effort: local session state must clear even if the API is offline.\n }\n}\n\nexport function useLogoutAuth() {\n const {enterGuest} = useAuthTransition();\n\n return useMutation({\n mutationFn: logoutAuth,\n onSettled: enterGuest,\n });\n}\n"],"names":["apiRequest","useMutation","useAuthTransition","logoutAuth","method","body","useLogoutAuth","enterGuest","mutationFn","onSettled"],"mappings":"AAAA,SAAQA,UAAU,QAAO,sBAAsB;AAC/C,SAAQC,WAAW,QAAO,wBAAwB;AAClD,SAAQC,iBAAiB,QAAO,iBAAiB;AAEjD,eAAeC;IACb,IAAI;QACF,MAAMH,WAAiB,gBAAgB;YAACI,QAAQ;YAAQC,MAAM,CAAC;QAAC;IAClE,EAAE,OAAM;IACN,oFAAoF;IACtF;AACF;AAEA,OAAO,SAASC;IACd,MAAM,EAACC,UAAU,EAAC,GAAGL;IAErB,OAAOD,YAAY;QACjBO,YAAYL;QACZM,WAAWF;IACb;AACF"}
1
+ {"version":3,"sources":["../../../src/hooks/api/logout-auth.ts"],"sourcesContent":["import {checkedApiRequest, emptyResponseSchema} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport {useAuthTransition} from '#state/auth.js';\n\nasync function logoutAuth() {\n try {\n await checkedApiRequest(emptyResponseSchema, '/auth/logout', {method: 'POST', body: {}});\n } catch {\n // Logout is best-effort: local session state must clear even if the API is offline.\n }\n}\n\nexport function useLogoutAuth() {\n const {enterGuest} = useAuthTransition();\n\n return useMutation({\n mutationFn: logoutAuth,\n onSettled: enterGuest,\n });\n}\n"],"names":["checkedApiRequest","emptyResponseSchema","useMutation","useAuthTransition","logoutAuth","method","body","useLogoutAuth","enterGuest","mutationFn","onSettled"],"mappings":"AAAA,SAAQA,iBAAiB,EAAEC,mBAAmB,QAAO,sBAAsB;AAC3E,SAAQC,WAAW,QAAO,wBAAwB;AAClD,SAAQC,iBAAiB,QAAO,iBAAiB;AAEjD,eAAeC;IACb,IAAI;QACF,MAAMJ,kBAAkBC,qBAAqB,gBAAgB;YAACI,QAAQ;YAAQC,MAAM,CAAC;QAAC;IACxF,EAAE,OAAM;IACN,oFAAoF;IACtF;AACF;AAEA,OAAO,SAASC;IACd,MAAM,EAACC,UAAU,EAAC,GAAGL;IAErB,OAAOD,YAAY;QACjBO,YAAYL;QACZM,WAAWF;IACb;AACF"}
@@ -1,33 +1,6 @@
1
- import type { PasswordResetConfirmBodyDto, PasswordResetRequestBodyDto } from '@shipfox/api-auth-dto';
2
- export declare function requestPasswordReset(body: PasswordResetRequestBodyDto): Promise<void>;
3
- export declare function confirmPasswordReset(body: PasswordResetConfirmBodyDto): Promise<{
4
- token: string;
5
- user: {
6
- id: string;
7
- email: string;
8
- name: string | null;
9
- email_verified_at: string | null;
10
- status: "active" | "suspended" | "deleted";
11
- created_at: string;
12
- updated_at: string;
13
- };
14
- }>;
15
- export declare function useRequestPasswordResetAuth(): import("@tanstack/react-query").UseMutationResult<void, Error, {
16
- email: string;
17
- }, unknown>;
18
- export declare function useConfirmPasswordResetAuth(): import("@tanstack/react-query").UseMutationResult<{
19
- token: string;
20
- user: {
21
- id: string;
22
- email: string;
23
- name: string | null;
24
- email_verified_at: string | null;
25
- status: "active" | "suspended" | "deleted";
26
- created_at: string;
27
- updated_at: string;
28
- };
29
- }, Error, {
30
- token: string;
31
- new_password: string;
32
- }, unknown>;
1
+ import type { PasswordResetConfirmCommand, PasswordResetRequestCommand } from '#core/auth.js';
2
+ export declare function requestPasswordReset(command: PasswordResetRequestCommand): Promise<void>;
3
+ export declare function confirmPasswordReset(command: PasswordResetConfirmCommand): Promise<import("@shipfox/client-shell/runtime").AuthenticatedSession>;
4
+ export declare function useRequestPasswordResetAuth(): import("@tanstack/react-query").UseMutationResult<void, Error, PasswordResetRequestCommand, unknown>;
5
+ export declare function useConfirmPasswordResetAuth(): import("@tanstack/react-query").UseMutationResult<import("@shipfox/client-shell/runtime").AuthenticatedSession, Error, PasswordResetConfirmCommand, unknown>;
33
6
  //# sourceMappingURL=password-reset-auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"password-reset-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/password-reset-auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,2BAA2B,EAE3B,2BAA2B,EAC5B,MAAM,uBAAuB,CAAC;AAK/B,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,2BAA2B,iBAE3E;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,2BAA2B;;;;;;;;;;;GAK3E;AAED,wBAAgB,2BAA2B;;YAE1C;AAED,wBAAgB,2BAA2B;;;;;;;;;;;;;;YAO1C"}
1
+ {"version":3,"file":"password-reset-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/password-reset-auth.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,2BAA2B,EAAE,2BAA2B,EAAC,MAAM,eAAe,CAAC;AAI5F,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,iBAK9E;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,yEAU9E;AAED,wBAAgB,2BAA2B,yGAE1C;AAED,wBAAgB,2BAA2B,iKAO1C"}
@@ -1,17 +1,23 @@
1
- import { apiRequest } from '@shipfox/client-api';
1
+ import { passwordResetConfirmResponseSchema } from '@shipfox/api-auth-dto';
2
+ import { checkedApiRequest, emptyResponseSchema } from '@shipfox/client-api';
2
3
  import { useMutation } from '@tanstack/react-query';
3
4
  import { useAuthTransition } from '#state/auth.js';
4
- export async function requestPasswordReset(body) {
5
- await apiRequest('/auth/password-reset', {
5
+ import { toAuthenticatedSession } from './auth-mapper.js';
6
+ export async function requestPasswordReset(command) {
7
+ await checkedApiRequest(emptyResponseSchema, '/auth/password-reset', {
6
8
  method: 'POST',
7
- body
9
+ body: command
8
10
  });
9
11
  }
10
- export async function confirmPasswordReset(body) {
11
- return await apiRequest('/auth/password-reset/confirm', {
12
+ export async function confirmPasswordReset(command) {
13
+ const response = await checkedApiRequest(passwordResetConfirmResponseSchema, '/auth/password-reset/confirm', {
12
14
  method: 'POST',
13
- body
15
+ body: {
16
+ token: command.token,
17
+ new_password: command.newPassword
18
+ }
14
19
  });
20
+ return toAuthenticatedSession(response);
15
21
  }
16
22
  export function useRequestPasswordResetAuth() {
17
23
  return useMutation({