@voyantjs/auth-react 0.34.0 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +157 -1
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/use-accept-invitation.d.ts +11 -0
- package/dist/hooks/use-accept-invitation.d.ts.map +1 -0
- package/dist/hooks/use-accept-invitation.js +35 -0
- package/dist/hooks/use-accept-invitation.test.d.ts +2 -0
- package/dist/hooks/use-accept-invitation.test.d.ts.map +1 -0
- package/dist/hooks/use-accept-invitation.test.js +36 -0
- package/dist/hooks/use-account-mutation.d.ts +41 -0
- package/dist/hooks/use-account-mutation.d.ts.map +1 -0
- package/dist/hooks/use-account-mutation.js +68 -0
- package/dist/hooks/use-account-mutation.test.d.ts +2 -0
- package/dist/hooks/use-account-mutation.test.d.ts.map +1 -0
- package/dist/hooks/use-account-mutation.test.js +67 -0
- package/dist/hooks/use-current-user.d.ts +2 -0
- package/dist/hooks/use-current-user.d.ts.map +1 -1
- package/dist/hooks/use-password-reset.d.ts +20 -0
- package/dist/hooks/use-password-reset.d.ts.map +1 -0
- package/dist/hooks/use-password-reset.js +83 -0
- package/dist/hooks/use-password-reset.test.d.ts +2 -0
- package/dist/hooks/use-password-reset.test.d.ts.map +1 -0
- package/dist/hooks/use-password-reset.test.js +55 -0
- package/dist/hooks/use-sign-in.d.ts +15 -0
- package/dist/hooks/use-sign-in.d.ts.map +1 -0
- package/dist/hooks/use-sign-in.js +80 -0
- package/dist/hooks/use-sign-in.test.d.ts +2 -0
- package/dist/hooks/use-sign-in.test.d.ts.map +1 -0
- package/dist/hooks/use-sign-in.test.js +49 -0
- package/dist/hooks/use-sign-up.d.ts +15 -0
- package/dist/hooks/use-sign-up.d.ts.map +1 -0
- package/dist/hooks/use-sign-up.js +80 -0
- package/dist/hooks/use-sign-up.test.d.ts +2 -0
- package/dist/hooks/use-sign-up.test.d.ts.map +1 -0
- package/dist/hooks/use-sign-up.test.js +49 -0
- package/dist/hooks/use-update-account-profile.d.ts +25 -0
- package/dist/hooks/use-update-account-profile.d.ts.map +1 -0
- package/dist/hooks/use-update-account-profile.js +37 -0
- package/dist/hooks/use-update-account-profile.test.d.ts +2 -0
- package/dist/hooks/use-update-account-profile.test.d.ts.map +1 -0
- package/dist/hooks/use-update-account-profile.test.js +62 -0
- package/dist/hooks/use-verify-email.d.ts +18 -0
- package/dist/hooks/use-verify-email.d.ts.map +1 -0
- package/dist/hooks/use-verify-email.js +86 -0
- package/dist/hooks/use-verify-email.test.d.ts +2 -0
- package/dist/hooks/use-verify-email.test.d.ts.map +1 -0
- package/dist/hooks/use-verify-email.test.js +50 -0
- package/dist/hooks/use-workspace-mutation.d.ts +2 -0
- package/dist/hooks/use-workspace-mutation.d.ts.map +1 -1
- package/dist/query-options.d.ts +8 -0
- package/dist/query-options.d.ts.map +1 -1
- package/dist/schemas.d.ts +2 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +2 -0
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -5,12 +5,23 @@ React runtime package for Voyant authentication and optional workspace state.
|
|
|
5
5
|
This package wraps the shared Voyant auth HTTP contract:
|
|
6
6
|
|
|
7
7
|
- `/auth/me`
|
|
8
|
+
- `PATCH /auth/me`
|
|
8
9
|
- `/auth/status`
|
|
10
|
+
- `/auth/request-password-reset`
|
|
11
|
+
- `/auth/reset-password`
|
|
12
|
+
- `/auth/sign-in/email`
|
|
13
|
+
- `/auth/change-password`
|
|
14
|
+
- `/auth/email-otp/request-email-change`
|
|
15
|
+
- `/auth/email-otp/change-email`
|
|
16
|
+
- `/auth/sign-up/email`
|
|
17
|
+
- `/auth/verify-email`
|
|
18
|
+
- `/auth/email-otp/verify-email`
|
|
9
19
|
- `/auth/workspace/current`
|
|
10
20
|
- `/auth/workspace/active-organization`
|
|
11
21
|
- `/auth/organization/list-members`
|
|
12
22
|
- `/auth/organization/list-invitations`
|
|
13
23
|
- `/auth/organization/invite-member`
|
|
24
|
+
- `/auth/organization/accept-invitation`
|
|
14
25
|
- `/auth/organization/update-member-role`
|
|
15
26
|
- `/auth/organization/remove-member`
|
|
16
27
|
- `/auth/organization/cancel-invitation`
|
|
@@ -20,12 +31,157 @@ This package wraps the shared Voyant auth HTTP contract:
|
|
|
20
31
|
It provides reusable React surfaces for:
|
|
21
32
|
|
|
22
33
|
- current user state
|
|
34
|
+
- account profile, password, and email-change mutations
|
|
23
35
|
- optional workspace and organization state
|
|
24
36
|
- organization member listing
|
|
25
37
|
- organization invitation listing
|
|
26
|
-
-
|
|
38
|
+
- email/password sign-in
|
|
39
|
+
- email/password sign-up
|
|
40
|
+
- email verification by Better Auth token or email OTP
|
|
41
|
+
- password reset request and confirmation
|
|
42
|
+
- invite, accept, cancel, remove, and role update mutations
|
|
27
43
|
- API token listing, creation, update, and deletion
|
|
28
44
|
|
|
45
|
+
## Sign-In
|
|
46
|
+
|
|
47
|
+
`useSignIn()` exposes the shared email/password Better Auth flow:
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
const signIn = useSignIn()
|
|
51
|
+
|
|
52
|
+
await signIn.email.mutateAsync({
|
|
53
|
+
email,
|
|
54
|
+
password,
|
|
55
|
+
callbackURL: "/",
|
|
56
|
+
})
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
After Better Auth accepts the credentials, the hook calls `/auth/status` to
|
|
60
|
+
provision the Voyant user profile if needed and invalidates the current auth
|
|
61
|
+
queries.
|
|
62
|
+
|
|
63
|
+
## Account self-service
|
|
64
|
+
|
|
65
|
+
`useUpdateAccountProfile()` updates Voyant profile fields through
|
|
66
|
+
`PATCH /auth/me` and refreshes the current-user query:
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
const updateProfile = useUpdateAccountProfile()
|
|
70
|
+
|
|
71
|
+
await updateProfile.mutateAsync({
|
|
72
|
+
firstName: "Ana",
|
|
73
|
+
lastName: "Pop",
|
|
74
|
+
locale: "ro",
|
|
75
|
+
timezone: "Europe/Bucharest",
|
|
76
|
+
profilePictureUrl: null,
|
|
77
|
+
})
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Apps can mount `handleAccountProfileRequest(...)` from `@voyantjs/auth/server`
|
|
81
|
+
to provide this route without depending on a specific template. The mounted
|
|
82
|
+
route validates the session, calls `updateCurrentUserProfile(...)` from
|
|
83
|
+
`@voyantjs/auth/workspace`, and returns the updated current-user shape.
|
|
84
|
+
|
|
85
|
+
Password and email changes call the mounted Better Auth API:
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
const changePassword = useChangeAccountPassword()
|
|
89
|
+
await changePassword.mutateAsync({
|
|
90
|
+
currentPassword,
|
|
91
|
+
newPassword,
|
|
92
|
+
revokeOtherSessions: true,
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const requestEmailChange = useRequestAccountEmailChange()
|
|
96
|
+
await requestEmailChange.mutateAsync({ newEmail })
|
|
97
|
+
|
|
98
|
+
const confirmEmailChange = useConfirmAccountEmailChange()
|
|
99
|
+
await confirmEmailChange.mutateAsync({ newEmail, otp })
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Sign-Up
|
|
103
|
+
|
|
104
|
+
`useSignUp()` exposes the shared email/password Better Auth registration flow:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
const signUp = useSignUp()
|
|
108
|
+
|
|
109
|
+
await signUp.email.mutateAsync({
|
|
110
|
+
name,
|
|
111
|
+
email,
|
|
112
|
+
password,
|
|
113
|
+
callbackURL: "/",
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The hook posts to the mounted Better Auth `/auth/sign-up/email` endpoint, calls
|
|
118
|
+
`/auth/status` after success for profile provisioning fallback, and invalidates
|
|
119
|
+
the current auth queries. Invitation-backed registration should use the app's
|
|
120
|
+
invitation redemption endpoint, because Better Auth email sign-up cannot redeem
|
|
121
|
+
Voyant admin-issued invite tokens.
|
|
122
|
+
|
|
123
|
+
## Invitation Acceptance
|
|
124
|
+
|
|
125
|
+
`useAcceptInvitation()` posts a Better Auth organization invitation token to the
|
|
126
|
+
mounted `/auth/organization/accept-invitation` endpoint:
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
const acceptInvitation = useAcceptInvitation()
|
|
130
|
+
|
|
131
|
+
await acceptInvitation.mutateAsync({ token: invitationId })
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The helper also accepts Better Auth's native field name:
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
await acceptInvitation.mutateAsync({ invitationId })
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
On success, current-user, current-workspace, organization-member, and
|
|
141
|
+
organization-invitation queries are invalidated so app shells can refresh their
|
|
142
|
+
membership state.
|
|
143
|
+
|
|
144
|
+
## Password Reset
|
|
145
|
+
|
|
146
|
+
`useRequestPasswordReset()` and `useConfirmPasswordReset()` expose the mounted
|
|
147
|
+
Better Auth reset-password endpoints:
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
const requestReset = useRequestPasswordReset()
|
|
151
|
+
|
|
152
|
+
await requestReset.mutateAsync({
|
|
153
|
+
email,
|
|
154
|
+
redirectTo: "https://operator.example/reset-password",
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
const confirmReset = useConfirmPasswordReset()
|
|
158
|
+
|
|
159
|
+
await confirmReset.mutateAsync({
|
|
160
|
+
token,
|
|
161
|
+
newPassword,
|
|
162
|
+
})
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The request hook posts to `/auth/request-password-reset` with `email` and
|
|
166
|
+
`redirectTo`. The confirm hook posts to `/auth/reset-password` with `token` and
|
|
167
|
+
`newPassword`, then invalidates the current auth queries.
|
|
168
|
+
|
|
169
|
+
## Email Verification
|
|
170
|
+
|
|
171
|
+
`useVerifyEmail()` exposes the shared Better Auth verification flow. Token links
|
|
172
|
+
call the mounted Better Auth `/auth/verify-email` endpoint; OTP verification
|
|
173
|
+
uses the email OTP plugin route used by the templates.
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
const verifyEmail = useVerifyEmail()
|
|
177
|
+
|
|
178
|
+
await verifyEmail.mutateAsync({ token })
|
|
179
|
+
await verifyEmail.mutateAsync({ email, otp })
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
After verification succeeds, the hook calls `/auth/status` to provision the
|
|
183
|
+
Voyant user profile if needed and invalidates the current auth queries.
|
|
184
|
+
|
|
29
185
|
## Single-Tenant Apps
|
|
30
186
|
|
|
31
187
|
Single-tenant operator apps should bootstrap their shell from `useCurrentUser()`
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { type AcceptInvitationInput, type AcceptInvitationResult, acceptInvitation, useAcceptInvitation, } from "./use-accept-invitation.js";
|
|
2
|
+
export { type ChangeAccountPasswordInput, type ConfirmAccountEmailChangeInput, changeAccountPassword, confirmAccountEmailChange, type RequestAccountEmailChangeInput, requestAccountEmailChange, type UpdateAccountProfileInput, updateAccountProfile, useAccountMutation, useChangeAccountPassword, useConfirmAccountEmailChange, useRequestAccountEmailChange, useUpdateAccountProfile, } from "./use-account-mutation.js";
|
|
1
3
|
export { type UseAuthStatusOptions, useAuthStatus } from "./use-auth-status.js";
|
|
2
4
|
export { type UseCurrentUserOptions, useCurrentUser } from "./use-current-user.js";
|
|
3
5
|
export { type UseCurrentWorkspaceOptions, useCurrentWorkspace } from "./use-current-workspace.js";
|
|
@@ -5,7 +7,11 @@ export { type CancelOrganizationInvitationInput, type InviteOrganizationMemberIn
|
|
|
5
7
|
export { type UseOrganizationInvitationsOptions, useOrganizationInvitations, } from "./use-organization-invitations.js";
|
|
6
8
|
export { type RemoveOrganizationMemberInput, type UpdateOrganizationMemberRoleInput, useOrganizationMemberMutation, } from "./use-organization-member-mutation.js";
|
|
7
9
|
export { type UseOrganizationMembersOptions, useOrganizationMembers, } from "./use-organization-members.js";
|
|
10
|
+
export { type ConfirmPasswordResetInput, type ConfirmPasswordResetResult, confirmPasswordReset, type RequestPasswordResetInput, type RequestPasswordResetResult, requestPasswordReset, useConfirmPasswordReset, useRequestPasswordReset, } from "./use-password-reset.js";
|
|
8
11
|
export { type CreateApiTokenInput, type CreateServiceApiKeyInput, type DeleteApiTokenInput, type DeleteServiceApiKeyInput, type UpdateApiTokenInput, type UpdateServiceApiKeyInput, useApiTokenMutation, useServiceApiKeyMutation, } from "./use-service-api-key-mutation.js";
|
|
9
12
|
export { type UseApiTokensOptions, type UseServiceApiKeysOptions, useApiTokens, useServiceApiKeys, } from "./use-service-api-keys.js";
|
|
13
|
+
export { type SignInEmailInput, type SignInEmailResult, signInWithEmail, useSignIn, } from "./use-sign-in.js";
|
|
14
|
+
export { type SignUpEmailInput, type SignUpEmailResult, signUpWithEmail, useSignUp, } from "./use-sign-up.js";
|
|
15
|
+
export { useVerifyEmail, type VerifyEmailInput, type VerifyEmailOtpInput, type VerifyEmailResult, type VerifyEmailTokenInput, verifyEmail, } from "./use-verify-email.js";
|
|
10
16
|
export { useWorkspaceMutation } from "./use-workspace-mutation.js";
|
|
11
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,oBAAoB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC/E,OAAO,EAAE,KAAK,qBAAqB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAClF,OAAO,EAAE,KAAK,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AACjG,OAAO,EACL,KAAK,iCAAiC,EACtC,KAAK,6BAA6B,EAClC,iCAAiC,GAClC,MAAM,2CAA2C,CAAA;AAClD,OAAO,EACL,KAAK,iCAAiC,EACtC,0BAA0B,GAC3B,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EACL,KAAK,6BAA6B,EAClC,KAAK,iCAAiC,EACtC,6BAA6B,GAC9B,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EACL,KAAK,6BAA6B,EAClC,sBAAsB,GACvB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,YAAY,EACZ,iBAAiB,GAClB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,8BAA8B,EACnC,qBAAqB,EACrB,yBAAyB,EACzB,KAAK,8BAA8B,EACnC,yBAAyB,EACzB,KAAK,yBAAyB,EAC9B,oBAAoB,EACpB,kBAAkB,EAClB,wBAAwB,EACxB,4BAA4B,EAC5B,4BAA4B,EAC5B,uBAAuB,GACxB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAAE,KAAK,oBAAoB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAC/E,OAAO,EAAE,KAAK,qBAAqB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAClF,OAAO,EAAE,KAAK,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AACjG,OAAO,EACL,KAAK,iCAAiC,EACtC,KAAK,6BAA6B,EAClC,iCAAiC,GAClC,MAAM,2CAA2C,CAAA;AAClD,OAAO,EACL,KAAK,iCAAiC,EACtC,0BAA0B,GAC3B,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EACL,KAAK,6BAA6B,EAClC,KAAK,iCAAiC,EACtC,6BAA6B,GAC9B,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EACL,KAAK,6BAA6B,EAClC,sBAAsB,GACvB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAC/B,oBAAoB,EACpB,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAC/B,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,YAAY,EACZ,iBAAiB,GAClB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,eAAe,EACf,SAAS,GACV,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,eAAe,EACf,SAAS,GACV,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,cAAc,EACd,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,WAAW,GACZ,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA"}
|
package/dist/hooks/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { acceptInvitation, useAcceptInvitation, } from "./use-accept-invitation.js";
|
|
2
|
+
export { changeAccountPassword, confirmAccountEmailChange, requestAccountEmailChange, updateAccountProfile, useAccountMutation, useChangeAccountPassword, useConfirmAccountEmailChange, useRequestAccountEmailChange, useUpdateAccountProfile, } from "./use-account-mutation.js";
|
|
1
3
|
export { useAuthStatus } from "./use-auth-status.js";
|
|
2
4
|
export { useCurrentUser } from "./use-current-user.js";
|
|
3
5
|
export { useCurrentWorkspace } from "./use-current-workspace.js";
|
|
@@ -5,6 +7,10 @@ export { useOrganizationInvitationMutation, } from "./use-organization-invitatio
|
|
|
5
7
|
export { useOrganizationInvitations, } from "./use-organization-invitations.js";
|
|
6
8
|
export { useOrganizationMemberMutation, } from "./use-organization-member-mutation.js";
|
|
7
9
|
export { useOrganizationMembers, } from "./use-organization-members.js";
|
|
10
|
+
export { confirmPasswordReset, requestPasswordReset, useConfirmPasswordReset, useRequestPasswordReset, } from "./use-password-reset.js";
|
|
8
11
|
export { useApiTokenMutation, useServiceApiKeyMutation, } from "./use-service-api-key-mutation.js";
|
|
9
12
|
export { useApiTokens, useServiceApiKeys, } from "./use-service-api-keys.js";
|
|
13
|
+
export { signInWithEmail, useSignIn, } from "./use-sign-in.js";
|
|
14
|
+
export { signUpWithEmail, useSignUp, } from "./use-sign-up.js";
|
|
15
|
+
export { useVerifyEmail, verifyEmail, } from "./use-verify-email.js";
|
|
10
16
|
export { useWorkspaceMutation } from "./use-workspace-mutation.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type FetchWithValidationOptions } from "../client.js";
|
|
2
|
+
export interface AcceptInvitationInput {
|
|
3
|
+
invitationId?: string | undefined;
|
|
4
|
+
token?: string | undefined;
|
|
5
|
+
}
|
|
6
|
+
export interface AcceptInvitationResult {
|
|
7
|
+
data: unknown;
|
|
8
|
+
}
|
|
9
|
+
export declare function acceptInvitation(input: AcceptInvitationInput, client: FetchWithValidationOptions): Promise<AcceptInvitationResult>;
|
|
10
|
+
export declare function useAcceptInvitation(): import("@tanstack/react-query").UseMutationResult<AcceptInvitationResult, Error, AcceptInvitationInput, unknown>;
|
|
11
|
+
//# sourceMappingURL=use-accept-invitation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-accept-invitation.d.ts","sourceRoot":"","sources":["../../src/hooks/use-accept-invitation.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,0BAA0B,EAAuB,MAAM,cAAc,CAAA;AAInF,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,OAAO,CAAA;CACd;AAaD,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,qBAAqB,EAC5B,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC,sBAAsB,CAAC,CAajC;AAED,wBAAgB,mBAAmB,qHAalC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { fetchWithValidation } from "../client.js";
|
|
5
|
+
import { useVoyantAuthContext } from "../provider.js";
|
|
6
|
+
import { authQueryKeys } from "../query-keys.js";
|
|
7
|
+
const acceptInvitationResponseSchema = z.unknown();
|
|
8
|
+
function invitationIdFromInput(input) {
|
|
9
|
+
const invitationId = input.invitationId ?? input.token;
|
|
10
|
+
if (!invitationId?.trim()) {
|
|
11
|
+
throw new Error("Invitation token is required.");
|
|
12
|
+
}
|
|
13
|
+
return invitationId.trim();
|
|
14
|
+
}
|
|
15
|
+
export async function acceptInvitation(input, client) {
|
|
16
|
+
const invitationId = invitationIdFromInput(input);
|
|
17
|
+
const data = await fetchWithValidation("/auth/organization/accept-invitation", acceptInvitationResponseSchema, client, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
body: JSON.stringify({ invitationId }),
|
|
20
|
+
});
|
|
21
|
+
return { data };
|
|
22
|
+
}
|
|
23
|
+
export function useAcceptInvitation() {
|
|
24
|
+
const { baseUrl, fetcher } = useVoyantAuthContext();
|
|
25
|
+
const queryClient = useQueryClient();
|
|
26
|
+
return useMutation({
|
|
27
|
+
mutationFn: (input) => acceptInvitation(input, { baseUrl, fetcher }),
|
|
28
|
+
onSuccess: () => {
|
|
29
|
+
void queryClient.invalidateQueries({ queryKey: authQueryKeys.currentUser() });
|
|
30
|
+
void queryClient.invalidateQueries({ queryKey: authQueryKeys.currentWorkspace() });
|
|
31
|
+
void queryClient.invalidateQueries({ queryKey: authQueryKeys.organizationMembers() });
|
|
32
|
+
void queryClient.invalidateQueries({ queryKey: authQueryKeys.organizationInvitations() });
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-accept-invitation.test.d.ts","sourceRoot":"","sources":["../../src/hooks/use-accept-invitation.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { acceptInvitation } from "./use-accept-invitation.js";
|
|
3
|
+
function jsonResponse(body, init) {
|
|
4
|
+
return new Response(JSON.stringify(body), {
|
|
5
|
+
headers: { "Content-Type": "application/json" },
|
|
6
|
+
...init,
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
describe("acceptInvitation", () => {
|
|
10
|
+
it("posts the invitation token to the mounted Better Auth organization endpoint", async () => {
|
|
11
|
+
const invitationToken = ["invitation", "123"].join("_");
|
|
12
|
+
const fetcher = vi.fn().mockResolvedValueOnce(jsonResponse({ success: true }));
|
|
13
|
+
const result = await acceptInvitation({ token: invitationToken }, { baseUrl: "https://operator.example/api", fetcher });
|
|
14
|
+
expect(result).toEqual({ data: { success: true } });
|
|
15
|
+
expect(fetcher).toHaveBeenCalledWith("https://operator.example/api/auth/organization/accept-invitation", {
|
|
16
|
+
method: "POST",
|
|
17
|
+
body: JSON.stringify({ invitationId: invitationToken }),
|
|
18
|
+
headers: expect.any(Headers),
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
it("also accepts Better Auth's invitationId field name", async () => {
|
|
22
|
+
const invitationToken = ["invitation", "456"].join("_");
|
|
23
|
+
const fetcher = vi
|
|
24
|
+
.fn()
|
|
25
|
+
.mockResolvedValueOnce(jsonResponse({ id: ["member", "123"].join("_") }));
|
|
26
|
+
await acceptInvitation({ invitationId: invitationToken }, { baseUrl: "https://operator.example/api/", fetcher });
|
|
27
|
+
expect(fetcher).toHaveBeenCalledWith("https://operator.example/api/auth/organization/accept-invitation", expect.objectContaining({
|
|
28
|
+
body: JSON.stringify({ invitationId: invitationToken }),
|
|
29
|
+
}));
|
|
30
|
+
});
|
|
31
|
+
it("requires a token or invitationId", async () => {
|
|
32
|
+
const fetcher = vi.fn();
|
|
33
|
+
await expect(acceptInvitation({ token: " " }, { baseUrl: "https://operator.example/api", fetcher })).rejects.toThrow("Invitation token is required.");
|
|
34
|
+
expect(fetcher).not.toHaveBeenCalled();
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type FetchWithValidationOptions } from "../client.js";
|
|
2
|
+
export type { UpdateAccountProfileInput, UpdateAccountProfileResult, } from "./use-update-account-profile.js";
|
|
3
|
+
export { updateAccountProfile, useUpdateAccountProfile, } from "./use-update-account-profile.js";
|
|
4
|
+
export interface ChangeAccountPasswordInput {
|
|
5
|
+
currentPassword: string;
|
|
6
|
+
newPassword: string;
|
|
7
|
+
revokeOtherSessions?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface RequestAccountEmailChangeInput {
|
|
10
|
+
newEmail: string;
|
|
11
|
+
otp?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ConfirmAccountEmailChangeInput {
|
|
14
|
+
newEmail: string;
|
|
15
|
+
otp: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function changeAccountPassword(input: ChangeAccountPasswordInput, client: FetchWithValidationOptions): Promise<unknown>;
|
|
18
|
+
export declare function requestAccountEmailChange(input: RequestAccountEmailChangeInput, client: FetchWithValidationOptions): Promise<unknown>;
|
|
19
|
+
export declare function confirmAccountEmailChange(input: ConfirmAccountEmailChangeInput, client: FetchWithValidationOptions): Promise<unknown>;
|
|
20
|
+
export declare function useChangeAccountPassword(): import("@tanstack/react-query").UseMutationResult<unknown, Error, ChangeAccountPasswordInput, unknown>;
|
|
21
|
+
export declare function useRequestAccountEmailChange(): import("@tanstack/react-query").UseMutationResult<unknown, Error, RequestAccountEmailChangeInput, unknown>;
|
|
22
|
+
export declare function useConfirmAccountEmailChange(): import("@tanstack/react-query").UseMutationResult<unknown, Error, ConfirmAccountEmailChangeInput, unknown>;
|
|
23
|
+
export declare function useAccountMutation(): {
|
|
24
|
+
updateProfile: import("@tanstack/react-query").UseMutationResult<{
|
|
25
|
+
id: string;
|
|
26
|
+
email: string | null;
|
|
27
|
+
firstName: string | null;
|
|
28
|
+
lastName: string | null;
|
|
29
|
+
locale: string;
|
|
30
|
+
timezone: string | null;
|
|
31
|
+
isSuperAdmin: boolean;
|
|
32
|
+
isSupportUser: boolean;
|
|
33
|
+
createdAt: string;
|
|
34
|
+
phoneNumber?: string | null | undefined;
|
|
35
|
+
profilePictureUrl?: string | null | undefined;
|
|
36
|
+
}, Error, import("./use-update-account-profile.js").UpdateAccountProfileInput, unknown>;
|
|
37
|
+
changePassword: import("@tanstack/react-query").UseMutationResult<unknown, Error, ChangeAccountPasswordInput, unknown>;
|
|
38
|
+
requestEmailChange: import("@tanstack/react-query").UseMutationResult<unknown, Error, RequestAccountEmailChangeInput, unknown>;
|
|
39
|
+
confirmEmailChange: import("@tanstack/react-query").UseMutationResult<unknown, Error, ConfirmAccountEmailChangeInput, unknown>;
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=use-account-mutation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-account-mutation.d.ts","sourceRoot":"","sources":["../../src/hooks/use-account-mutation.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,0BAA0B,EAAuB,MAAM,cAAc,CAAA;AAKnF,YAAY,EACV,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,iCAAiC,CAAA;AACxC,OAAO,EACL,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,iCAAiC,CAAA;AAIxC,MAAM,WAAW,0BAA0B;IACzC,eAAe,EAAE,MAAM,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,0BAA0B,EACjC,MAAM,EAAE,0BAA0B,oBAUnC;AAED,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,8BAA8B,EACrC,MAAM,EAAE,0BAA0B,oBAcnC;AAED,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,8BAA8B,EACrC,MAAM,EAAE,0BAA0B,oBASnC;AAED,wBAAgB,wBAAwB,2GAOvC;AAED,wBAAgB,4BAA4B,+GAO3C;AAED,wBAAgB,4BAA4B,+GAY3C;AAED,wBAAgB,kBAAkB;;;;;;;;;;;;;;;;;EAOjC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { fetchWithValidation } from "../client.js";
|
|
5
|
+
import { useVoyantAuthContext } from "../provider.js";
|
|
6
|
+
import { authQueryKeys } from "../query-keys.js";
|
|
7
|
+
import { useUpdateAccountProfile } from "./use-update-account-profile.js";
|
|
8
|
+
export { updateAccountProfile, useUpdateAccountProfile, } from "./use-update-account-profile.js";
|
|
9
|
+
const accountMutationResultSchema = z.unknown();
|
|
10
|
+
export async function changeAccountPassword(input, client) {
|
|
11
|
+
return fetchWithValidation("/auth/change-password", accountMutationResultSchema, client, {
|
|
12
|
+
method: "POST",
|
|
13
|
+
body: JSON.stringify({
|
|
14
|
+
currentPassword: input.currentPassword,
|
|
15
|
+
newPassword: input.newPassword,
|
|
16
|
+
revokeOtherSessions: input.revokeOtherSessions,
|
|
17
|
+
}),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export async function requestAccountEmailChange(input, client) {
|
|
21
|
+
return fetchWithValidation("/auth/email-otp/request-email-change", accountMutationResultSchema, client, {
|
|
22
|
+
method: "POST",
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
newEmail: input.newEmail,
|
|
25
|
+
otp: input.otp,
|
|
26
|
+
}),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export async function confirmAccountEmailChange(input, client) {
|
|
30
|
+
return fetchWithValidation("/auth/email-otp/change-email", accountMutationResultSchema, client, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
body: JSON.stringify({
|
|
33
|
+
newEmail: input.newEmail,
|
|
34
|
+
otp: input.otp,
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export function useChangeAccountPassword() {
|
|
39
|
+
const { baseUrl, fetcher } = useVoyantAuthContext();
|
|
40
|
+
return useMutation({
|
|
41
|
+
mutationFn: (input) => changeAccountPassword(input, { baseUrl, fetcher }),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
export function useRequestAccountEmailChange() {
|
|
45
|
+
const { baseUrl, fetcher } = useVoyantAuthContext();
|
|
46
|
+
return useMutation({
|
|
47
|
+
mutationFn: (input) => requestAccountEmailChange(input, { baseUrl, fetcher }),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export function useConfirmAccountEmailChange() {
|
|
51
|
+
const { baseUrl, fetcher } = useVoyantAuthContext();
|
|
52
|
+
const queryClient = useQueryClient();
|
|
53
|
+
return useMutation({
|
|
54
|
+
mutationFn: (input) => confirmAccountEmailChange(input, { baseUrl, fetcher }),
|
|
55
|
+
onSuccess: () => {
|
|
56
|
+
void queryClient.invalidateQueries({ queryKey: authQueryKeys.currentUser() });
|
|
57
|
+
void queryClient.invalidateQueries({ queryKey: authQueryKeys.authStatus() });
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
export function useAccountMutation() {
|
|
62
|
+
return {
|
|
63
|
+
updateProfile: useUpdateAccountProfile(),
|
|
64
|
+
changePassword: useChangeAccountPassword(),
|
|
65
|
+
requestEmailChange: useRequestAccountEmailChange(),
|
|
66
|
+
confirmEmailChange: useConfirmAccountEmailChange(),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-account-mutation.test.d.ts","sourceRoot":"","sources":["../../src/hooks/use-account-mutation.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { changeAccountPassword, confirmAccountEmailChange, requestAccountEmailChange, updateAccountProfile, } from "./use-account-mutation.js";
|
|
3
|
+
function jsonResponse(body, init) {
|
|
4
|
+
return new Response(JSON.stringify(body), {
|
|
5
|
+
headers: { "Content-Type": "application/json" },
|
|
6
|
+
...init,
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
describe("account mutation request helpers", () => {
|
|
10
|
+
it("patches the Voyant profile endpoint", async () => {
|
|
11
|
+
const fetcher = vi.fn().mockResolvedValueOnce(jsonResponse({
|
|
12
|
+
id: "user_1",
|
|
13
|
+
email: "ana@example.com",
|
|
14
|
+
firstName: "Ana",
|
|
15
|
+
lastName: "Pop",
|
|
16
|
+
isSuperAdmin: false,
|
|
17
|
+
isSupportUser: false,
|
|
18
|
+
createdAt: "2026-05-12T00:00:00.000Z",
|
|
19
|
+
profilePictureUrl: null,
|
|
20
|
+
}));
|
|
21
|
+
await updateAccountProfile({ firstName: "Ana", lastName: "Pop", profilePictureUrl: null }, { baseUrl: "https://operator.example/api", fetcher });
|
|
22
|
+
expect(fetcher).toHaveBeenCalledWith("https://operator.example/api/auth/me", {
|
|
23
|
+
method: "PATCH",
|
|
24
|
+
headers: expect.any(Headers),
|
|
25
|
+
body: JSON.stringify({
|
|
26
|
+
firstName: "Ana",
|
|
27
|
+
lastName: "Pop",
|
|
28
|
+
profilePictureUrl: null,
|
|
29
|
+
}),
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
it("posts password changes to the mounted Better Auth endpoint", async () => {
|
|
33
|
+
const fetcher = vi.fn().mockResolvedValueOnce(jsonResponse({ success: true }));
|
|
34
|
+
await changeAccountPassword({
|
|
35
|
+
currentPassword: "old-password",
|
|
36
|
+
newPassword: "new-password",
|
|
37
|
+
revokeOtherSessions: true,
|
|
38
|
+
}, { baseUrl: "https://operator.example/api/", fetcher });
|
|
39
|
+
expect(fetcher).toHaveBeenCalledWith("https://operator.example/api/auth/change-password", {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: expect.any(Headers),
|
|
42
|
+
body: JSON.stringify({
|
|
43
|
+
currentPassword: "old-password",
|
|
44
|
+
newPassword: "new-password",
|
|
45
|
+
revokeOtherSessions: true,
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
it("posts email-change requests to the Email OTP endpoint", async () => {
|
|
50
|
+
const fetcher = vi.fn().mockResolvedValueOnce(jsonResponse({ success: true }));
|
|
51
|
+
await requestAccountEmailChange({ newEmail: "new@example.com" }, { baseUrl: "https://operator.example/api", fetcher });
|
|
52
|
+
expect(fetcher).toHaveBeenCalledWith("https://operator.example/api/auth/email-otp/request-email-change", {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: expect.any(Headers),
|
|
55
|
+
body: JSON.stringify({ newEmail: "new@example.com" }),
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
it("posts email-change confirmations to the Email OTP endpoint", async () => {
|
|
59
|
+
const fetcher = vi.fn().mockResolvedValueOnce(jsonResponse({ success: true }));
|
|
60
|
+
await confirmAccountEmailChange({ newEmail: "new@example.com", otp: "123456" }, { baseUrl: "https://operator.example/api", fetcher });
|
|
61
|
+
expect(fetcher).toHaveBeenCalledWith("https://operator.example/api/auth/email-otp/change-email", {
|
|
62
|
+
method: "POST",
|
|
63
|
+
headers: expect.any(Headers),
|
|
64
|
+
body: JSON.stringify({ newEmail: "new@example.com", otp: "123456" }),
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -6,6 +6,8 @@ export declare function useCurrentUser(options?: UseCurrentUserOptions): import(
|
|
|
6
6
|
email: string | null;
|
|
7
7
|
firstName: string | null;
|
|
8
8
|
lastName: string | null;
|
|
9
|
+
locale: string;
|
|
10
|
+
timezone: string | null;
|
|
9
11
|
isSuperAdmin: boolean;
|
|
10
12
|
isSupportUser: boolean;
|
|
11
13
|
createdAt: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-current-user.d.ts","sourceRoot":"","sources":["../../src/hooks/use-current-user.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B
|
|
1
|
+
{"version":3,"file":"use-current-user.d.ts","sourceRoot":"","sources":["../../src/hooks/use-current-user.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B;;;;;;;;;;;;UAQjE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type FetchWithValidationOptions } from "../client.js";
|
|
2
|
+
export interface RequestPasswordResetInput {
|
|
3
|
+
email: string;
|
|
4
|
+
redirectTo?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface RequestPasswordResetResult {
|
|
7
|
+
data: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface ConfirmPasswordResetInput {
|
|
10
|
+
token: string;
|
|
11
|
+
newPassword: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ConfirmPasswordResetResult {
|
|
14
|
+
data: unknown;
|
|
15
|
+
}
|
|
16
|
+
export declare function requestPasswordReset(input: RequestPasswordResetInput, client: FetchWithValidationOptions): Promise<RequestPasswordResetResult>;
|
|
17
|
+
export declare function confirmPasswordReset(input: ConfirmPasswordResetInput, client: FetchWithValidationOptions): Promise<ConfirmPasswordResetResult>;
|
|
18
|
+
export declare function useRequestPasswordReset(): import("@tanstack/react-query").UseMutationResult<RequestPasswordResetResult, Error, RequestPasswordResetInput, unknown>;
|
|
19
|
+
export declare function useConfirmPasswordReset(): import("@tanstack/react-query").UseMutationResult<ConfirmPasswordResetResult, Error, ConfirmPasswordResetInput, unknown>;
|
|
20
|
+
//# sourceMappingURL=use-password-reset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-password-reset.d.ts","sourceRoot":"","sources":["../../src/hooks/use-password-reset.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,0BAA0B,EAAkB,MAAM,cAAc,CAAA;AAI9E,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,OAAO,CAAA;CACd;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,OAAO,CAAA;CACd;AAwFD,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,yBAAyB,EAChC,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC,0BAA0B,CAAC,CAMrC;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,yBAAyB,EAChC,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC,0BAA0B,CAAC,CAMrC;AAED,wBAAgB,uBAAuB,6HAOtC;AAED,wBAAgB,uBAAuB,6HAatC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import { VoyantApiError } from "../client.js";
|
|
4
|
+
import { useVoyantAuthContext } from "../provider.js";
|
|
5
|
+
import { authQueryKeys } from "../query-keys.js";
|
|
6
|
+
function joinUrl(baseUrl, path) {
|
|
7
|
+
const trimmedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
8
|
+
const trimmedPath = path.startsWith("/") ? path : `/${path}`;
|
|
9
|
+
return `${trimmedBase}${trimmedPath}`;
|
|
10
|
+
}
|
|
11
|
+
function extractBetterAuthErrorMessage(body, fallback) {
|
|
12
|
+
if (typeof body !== "object" || body === null) {
|
|
13
|
+
return fallback;
|
|
14
|
+
}
|
|
15
|
+
const candidate = body;
|
|
16
|
+
if (typeof candidate.error === "string") {
|
|
17
|
+
return candidate.error;
|
|
18
|
+
}
|
|
19
|
+
if (typeof candidate.error === "object" &&
|
|
20
|
+
candidate.error !== null &&
|
|
21
|
+
"message" in candidate.error) {
|
|
22
|
+
return String(candidate.error.message);
|
|
23
|
+
}
|
|
24
|
+
if (candidate.message !== undefined) {
|
|
25
|
+
return String(candidate.message);
|
|
26
|
+
}
|
|
27
|
+
return fallback;
|
|
28
|
+
}
|
|
29
|
+
function hasBetterAuthError(body) {
|
|
30
|
+
return (typeof body === "object" &&
|
|
31
|
+
body !== null &&
|
|
32
|
+
"error" in body &&
|
|
33
|
+
body.error !== undefined &&
|
|
34
|
+
body.error !== null);
|
|
35
|
+
}
|
|
36
|
+
async function readJson(response) {
|
|
37
|
+
const text = await response.text();
|
|
38
|
+
if (!text) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(text);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return text;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function betterAuthPost(path, input, client) {
|
|
49
|
+
const response = await client.fetcher(joinUrl(client.baseUrl, path), {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: { "Content-Type": "application/json" },
|
|
52
|
+
body: JSON.stringify(input),
|
|
53
|
+
});
|
|
54
|
+
const body = await readJson(response);
|
|
55
|
+
if (!response.ok || hasBetterAuthError(body)) {
|
|
56
|
+
throw new VoyantApiError(extractBetterAuthErrorMessage(body, `Voyant API error: ${response.status} ${response.statusText}`), response.status, body);
|
|
57
|
+
}
|
|
58
|
+
return { data: body };
|
|
59
|
+
}
|
|
60
|
+
export function requestPasswordReset(input, client) {
|
|
61
|
+
return betterAuthPost("/auth/request-password-reset", input, client);
|
|
62
|
+
}
|
|
63
|
+
export function confirmPasswordReset(input, client) {
|
|
64
|
+
return betterAuthPost("/auth/reset-password", input, client);
|
|
65
|
+
}
|
|
66
|
+
export function useRequestPasswordReset() {
|
|
67
|
+
const { baseUrl, fetcher } = useVoyantAuthContext();
|
|
68
|
+
return useMutation({
|
|
69
|
+
mutationFn: (input) => requestPasswordReset(input, { baseUrl, fetcher }),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export function useConfirmPasswordReset() {
|
|
73
|
+
const { baseUrl, fetcher } = useVoyantAuthContext();
|
|
74
|
+
const queryClient = useQueryClient();
|
|
75
|
+
return useMutation({
|
|
76
|
+
mutationFn: (input) => confirmPasswordReset(input, { baseUrl, fetcher }),
|
|
77
|
+
onSuccess: () => {
|
|
78
|
+
void queryClient.invalidateQueries({ queryKey: authQueryKeys.authStatus() });
|
|
79
|
+
void queryClient.invalidateQueries({ queryKey: authQueryKeys.currentUser() });
|
|
80
|
+
void queryClient.invalidateQueries({ queryKey: authQueryKeys.currentWorkspace() });
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-password-reset.test.d.ts","sourceRoot":"","sources":["../../src/hooks/use-password-reset.test.ts"],"names":[],"mappings":""}
|