@object-ui/auth 17.6.0 → 17.7.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/CHANGELOG.md +490 -0
- package/README.md +97 -15
- package/dist/ActiveOrganizationStorage.d.ts +32 -1
- package/dist/ActiveOrganizationStorage.d.ts.map +1 -1
- package/dist/ActiveOrganizationStorage.js +72 -3
- package/dist/AuthContext.d.ts +4 -2
- package/dist/AuthContext.d.ts.map +1 -1
- package/dist/AuthProvider.js +4 -4
- package/dist/LoginForm.d.ts +10 -1
- package/dist/LoginForm.d.ts.map +1 -1
- package/dist/LoginForm.js +1 -2
- package/dist/RegisterForm.d.ts +21 -2
- package/dist/RegisterForm.d.ts.map +1 -1
- package/dist/RegisterForm.js +3 -4
- package/dist/SocialSignInButtons.d.ts +9 -2
- package/dist/SocialSignInButtons.d.ts.map +1 -1
- package/dist/SocialSignInButtons.js +3 -3
- package/dist/UserMenu.d.ts +1 -1
- package/dist/UserMenu.js +1 -1
- package/dist/createAuthClient.d.ts.map +1 -1
- package/dist/createAuthClient.js +6 -0
- package/dist/createAuthenticatedFetch.d.ts +1 -1
- package/dist/createAuthenticatedFetch.d.ts.map +1 -1
- package/dist/createAuthenticatedFetch.js +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/types.d.ts +14 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/useWorkspaceAdminStatus.d.ts +76 -27
- package/dist/useWorkspaceAdminStatus.d.ts.map +1 -1
- package/dist/useWorkspaceAdminStatus.js +146 -40
- package/package.json +5 -6
package/README.md
CHANGED
|
@@ -25,16 +25,18 @@ npm install @object-ui/auth
|
|
|
25
25
|
## Quick Start
|
|
26
26
|
|
|
27
27
|
```tsx
|
|
28
|
-
import {
|
|
29
|
-
import { createAuthClient } from '@object-ui/auth';
|
|
28
|
+
import type { ReactNode } from 'react';
|
|
29
|
+
import { AuthProvider, AuthGuard, createAuthClient, useAuth } from '@object-ui/auth';
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
// Your app supplies the sign-in page shown to unauthenticated visitors.
|
|
32
|
+
declare const LoginPage: () => ReactNode;
|
|
33
|
+
|
|
34
|
+
const authUrl = 'https://api.example.com/auth';
|
|
35
|
+
const authClient = createAuthClient({ baseURL: authUrl });
|
|
34
36
|
|
|
35
37
|
function App() {
|
|
36
38
|
return (
|
|
37
|
-
<AuthProvider client={authClient}>
|
|
39
|
+
<AuthProvider authUrl={authUrl} client={authClient}>
|
|
38
40
|
<AuthGuard fallback={<LoginPage />}>
|
|
39
41
|
<Dashboard />
|
|
40
42
|
</AuthGuard>
|
|
@@ -57,12 +59,21 @@ function Dashboard() {
|
|
|
57
59
|
|
|
58
60
|
### AuthProvider
|
|
59
61
|
|
|
60
|
-
Wraps your application with authentication context
|
|
62
|
+
Wraps your application with authentication context. `authUrl` is **required**;
|
|
63
|
+
`client` is optional, and when you pass one it is used instead of the client
|
|
64
|
+
`AuthProvider` would otherwise build from `authUrl`:
|
|
61
65
|
|
|
62
66
|
```tsx
|
|
63
|
-
|
|
67
|
+
import type { ReactNode } from 'react';
|
|
68
|
+
import { AuthProvider } from '@object-ui/auth';
|
|
69
|
+
import type { AuthClient } from '@object-ui/auth';
|
|
70
|
+
|
|
71
|
+
declare const authClient: AuthClient;
|
|
72
|
+
declare const App: () => ReactNode;
|
|
73
|
+
|
|
74
|
+
<AuthProvider authUrl="/api/v1/auth" client={authClient}>
|
|
64
75
|
<App />
|
|
65
|
-
</AuthProvider
|
|
76
|
+
</AuthProvider>;
|
|
66
77
|
```
|
|
67
78
|
|
|
68
79
|
### useAuth
|
|
@@ -70,6 +81,8 @@ Wraps your application with authentication context:
|
|
|
70
81
|
Hook for accessing auth state and methods:
|
|
71
82
|
|
|
72
83
|
```tsx
|
|
84
|
+
import { useAuth } from '@object-ui/auth';
|
|
85
|
+
|
|
73
86
|
const {
|
|
74
87
|
user,
|
|
75
88
|
session,
|
|
@@ -100,9 +113,14 @@ const {
|
|
|
100
113
|
Protects children from unauthenticated access:
|
|
101
114
|
|
|
102
115
|
```tsx
|
|
116
|
+
import type { ReactNode } from 'react';
|
|
117
|
+
import { AuthGuard, LoginForm } from '@object-ui/auth';
|
|
118
|
+
|
|
119
|
+
declare const ProtectedContent: () => ReactNode;
|
|
120
|
+
|
|
103
121
|
<AuthGuard fallback={<LoginForm />}>
|
|
104
122
|
<ProtectedContent />
|
|
105
|
-
</AuthGuard
|
|
123
|
+
</AuthGuard>;
|
|
106
124
|
```
|
|
107
125
|
|
|
108
126
|
### LoginForm / RegisterForm / ForgotPasswordForm
|
|
@@ -110,9 +128,40 @@ Protects children from unauthenticated access:
|
|
|
110
128
|
Pre-built authentication form components:
|
|
111
129
|
|
|
112
130
|
```tsx
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
131
|
+
import { ForgotPasswordForm, LoginForm, RegisterForm } from '@object-ui/auth';
|
|
132
|
+
|
|
133
|
+
declare const navigate: (to: string) => void;
|
|
134
|
+
|
|
135
|
+
<LoginForm onSuccess={() => navigate('/dashboard')} />;
|
|
136
|
+
<RegisterForm onSuccess={() => navigate('/welcome')} />;
|
|
137
|
+
<ForgotPasswordForm onSuccess={() => navigate('/check-email')} />;
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`labels` is how the forms take translated text, and it reaches the social
|
|
141
|
+
provider buttons the server's `/auth/config` turns on: `socialButton`
|
|
142
|
+
is a template whose `{provider}` is replaced with the provider's display name
|
|
143
|
+
(defaults "Continue with {provider}" on `LoginForm`, "Sign up with {provider}"
|
|
144
|
+
on `RegisterForm`), and `orText` is the divider under the buttons (default
|
|
145
|
+
"or continue with email").
|
|
146
|
+
|
|
147
|
+
When the server requires email verification, a registration ends in the user's
|
|
148
|
+
inbox, and the verification link is the only way back. `verificationCallbackURL`
|
|
149
|
+
says where that link lands, e.g. the invitation the user signed up from. It is
|
|
150
|
+
sent as better-auth's sign-up `callbackURL` (the same value as the fourth
|
|
151
|
+
argument of `useAuth().signUp`). The server accepts only a root-relative path
|
|
152
|
+
or an absolute URL on a trusted origin, and refuses a document-relative `./…`
|
|
153
|
+
with `INVALID_CALLBACK_URL`, which fails the sign-up. Resolve an SPA route
|
|
154
|
+
against its mount first. Omitted, the server default (`/`) applies.
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
import { RegisterForm } from '@object-ui/auth';
|
|
158
|
+
|
|
159
|
+
declare const navigate: (to: string) => void;
|
|
160
|
+
|
|
161
|
+
<RegisterForm
|
|
162
|
+
verificationCallbackURL="/_console/accept-invitation/inv_123"
|
|
163
|
+
onVerificationRequired={(email) => navigate(`/verify-email-prompt?email=${encodeURIComponent(email)}`)}
|
|
164
|
+
/>;
|
|
116
165
|
```
|
|
117
166
|
|
|
118
167
|
### UserMenu
|
|
@@ -120,7 +169,9 @@ Pre-built authentication form components:
|
|
|
120
169
|
Displays current user info with avatar and sign-out:
|
|
121
170
|
|
|
122
171
|
```tsx
|
|
123
|
-
|
|
172
|
+
import { UserMenu } from '@object-ui/auth';
|
|
173
|
+
|
|
174
|
+
<UserMenu />;
|
|
124
175
|
```
|
|
125
176
|
|
|
126
177
|
### createAuthenticatedFetch
|
|
@@ -129,6 +180,8 @@ Creates a fetch wrapper that injects the stored Bearer token (plus
|
|
|
129
180
|
`X-Tenant-ID` and `Accept-Language`) into API requests:
|
|
130
181
|
|
|
131
182
|
```tsx
|
|
183
|
+
import { createAuthenticatedFetch } from '@object-ui/auth';
|
|
184
|
+
|
|
132
185
|
const authedFetch = createAuthenticatedFetch();
|
|
133
186
|
|
|
134
187
|
// For fetches whose target URL comes from view metadata (`provider: 'api'`
|
|
@@ -137,6 +190,30 @@ const authedFetch = createAuthenticatedFetch();
|
|
|
137
190
|
const apiProviderFetch = createAuthenticatedFetch({ sameOriginOnly: true });
|
|
138
191
|
```
|
|
139
192
|
|
|
193
|
+
### getSessionOwnerChangeCount / subscribeSessionOwnerChange
|
|
194
|
+
|
|
195
|
+
When the session resolves to a different user than the one this browser last
|
|
196
|
+
held, `AuthProvider` drops the previous user's client state (objectui#5664).
|
|
197
|
+
That clears storage only. State already derived from that storage and held in
|
|
198
|
+
memory, such as the UI language the boot resolved, has to be re-derived by
|
|
199
|
+
whoever owns it. These two exports tell that owner a change happened in this
|
|
200
|
+
page-load (objectui#10193). The count lets an owner that mounts after the purge
|
|
201
|
+
still see it:
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
import { useSyncExternalStore } from 'react';
|
|
205
|
+
import { getSessionOwnerChangeCount, subscribeSessionOwnerChange } from '@object-ui/auth';
|
|
206
|
+
|
|
207
|
+
const ownerChanges = useSyncExternalStore(
|
|
208
|
+
subscribeSessionOwnerChange,
|
|
209
|
+
getSessionOwnerChangeCount,
|
|
210
|
+
getSessionOwnerChangeCount,
|
|
211
|
+
);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
The count lives in memory for one page-load and is never persisted.
|
|
215
|
+
`@object-ui/app-shell`'s `useSignedInUserLocale` is the in-repo consumer.
|
|
216
|
+
|
|
140
217
|
## The `X-Tenant-ID` edge contract
|
|
141
218
|
|
|
142
219
|
`createAuthenticatedFetch` stamps `X-Tenant-ID` on the requests it wraps. This section is
|
|
@@ -325,13 +402,16 @@ not a gap.
|
|
|
325
402
|
|
|
326
403
|
Preview mode allows visitors (e.g. marketplace customers) to explore the platform without registering or logging in. The `AuthProvider` auto-authenticates with a simulated user identity and bypasses login/registration screens.
|
|
327
404
|
|
|
328
|
-
This
|
|
405
|
+
This capability is host-supplied and has no `@objectstack/spec` anchor. It aligned with `PreviewModeConfig` from `@objectstack/spec/kernel` until that symbol was retired upstream (objectstack#11846), which removed it together with the `RuntimeMode` value `'preview'`; the spec this package resolves no longer exports it. The `previewMode` prop below is unaffected — it is the host's to supply, and always was.
|
|
329
406
|
|
|
330
407
|
### Usage
|
|
331
408
|
|
|
332
409
|
```tsx
|
|
410
|
+
import type { ReactNode } from 'react';
|
|
333
411
|
import { AuthProvider, PreviewBanner } from '@object-ui/auth';
|
|
334
412
|
|
|
413
|
+
declare const Dashboard: () => ReactNode;
|
|
414
|
+
|
|
335
415
|
function App() {
|
|
336
416
|
return (
|
|
337
417
|
<AuthProvider
|
|
@@ -377,6 +457,8 @@ import { PreviewBanner } from '@object-ui/auth';
|
|
|
377
457
|
Use the `useAuth` hook to check if the app is in preview mode:
|
|
378
458
|
|
|
379
459
|
```tsx
|
|
460
|
+
import { useAuth } from '@object-ui/auth';
|
|
461
|
+
|
|
380
462
|
function MyComponent() {
|
|
381
463
|
const { isPreviewMode, previewMode } = useAuth();
|
|
382
464
|
|
|
@@ -21,6 +21,30 @@
|
|
|
21
21
|
* next in that tab unless something removes them.
|
|
22
22
|
*/
|
|
23
23
|
export declare function purgePreviousUserClientState(): void;
|
|
24
|
+
/**
|
|
25
|
+
* The number of owner changes {@link SessionUserScope.adopt} has performed in
|
|
26
|
+
* this page-load — `0` until a DIFFERENT user than the one the browser
|
|
27
|
+
* previously held is adopted.
|
|
28
|
+
*
|
|
29
|
+
* ## Why a count and not only an event (objectui#10193)
|
|
30
|
+
*
|
|
31
|
+
* The purge sweeps the previous owner's STORAGE, but state that was already
|
|
32
|
+
* derived from that storage before the purge — the UI language the boot
|
|
33
|
+
* resolved out of the previous owner's language slots, above all — lives in
|
|
34
|
+
* memory and is untouched by it. Whoever owns such state has to re-derive it,
|
|
35
|
+
* and the component that does may mount AFTER the purge happened (the shell
|
|
36
|
+
* mounts behind the session gate, the purge fires as the session resolves). A
|
|
37
|
+
* bare event would be missed by it; a count lets a late reader compare against
|
|
38
|
+
* what it has already handled. Shaped for React's `useSyncExternalStore`
|
|
39
|
+
* together with {@link subscribeSessionOwnerChange}.
|
|
40
|
+
*/
|
|
41
|
+
export declare function getSessionOwnerChangeCount(): number;
|
|
42
|
+
/**
|
|
43
|
+
* Be told each time {@link SessionUserScope.adopt} drops a previous owner's
|
|
44
|
+
* state. Returns the unsubscribe function. A listener that throws is reported
|
|
45
|
+
* and skipped, never allowed to break the sign-in path that called `adopt`.
|
|
46
|
+
*/
|
|
47
|
+
export declare function subscribeSessionOwnerChange(listener: () => void): () => void;
|
|
24
48
|
/**
|
|
25
49
|
* Which user's client state this browser holds, and the transition that drops
|
|
26
50
|
* the previous user's state.
|
|
@@ -39,6 +63,13 @@ export declare const SessionUserScope: {
|
|
|
39
63
|
* Record `userId` as the owner of this browser's client state, dropping the
|
|
40
64
|
* previous owner's state wholesale when it changes.
|
|
41
65
|
*
|
|
66
|
+
* Returns `true` when it dropped a previous owner's state, `false`
|
|
67
|
+
* otherwise (same user, first-ever owner, empty id). A drop is also reported
|
|
68
|
+
* to {@link subscribeSessionOwnerChange} listeners and counted by
|
|
69
|
+
* {@link getSessionOwnerChangeCount} (objectui#10193): the purge clears
|
|
70
|
+
* storage, and anything already derived from that storage in memory is the
|
|
71
|
+
* listener's to re-derive.
|
|
72
|
+
*
|
|
42
73
|
* Idempotent: re-adopting the same user purges nothing. Called from
|
|
43
74
|
* `AuthProvider` for real sessions only — the synthetic `preview-user` /
|
|
44
75
|
* `guest` identities never reach it, so a preview mount cannot purge a real
|
|
@@ -51,7 +82,7 @@ export declare const SessionUserScope: {
|
|
|
51
82
|
* it removes every active-org spelling and leaves `auth-session-user-id`
|
|
52
83
|
* alone on purpose.
|
|
53
84
|
*/
|
|
54
|
-
adopt(userId: string):
|
|
85
|
+
adopt(userId: string): boolean;
|
|
55
86
|
/**
|
|
56
87
|
* Forget the in-memory pointer. Test seam only — production has no reason to
|
|
57
88
|
* un-know who is signed in, and sign-out deliberately KEEPS the persisted
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActiveOrganizationStorage.d.ts","sourceRoot":"","sources":["../src/ActiveOrganizationStorage.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAyOH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,4BAA4B,IAAI,IAAI,CAInD;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB;IAC3B;;;;;OAKG;aACc,MAAM,GAAG,IAAI;IAE9B,mFAAmF;eACxE,MAAM,GAAG,IAAI;IAKxB
|
|
1
|
+
{"version":3,"file":"ActiveOrganizationStorage.d.ts","sourceRoot":"","sources":["../src/ActiveOrganizationStorage.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAyOH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,4BAA4B,IAAI,IAAI,CAInD;AAkBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAEnD;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAK5E;AAaD;;;GAGG;AACH,eAAO,MAAM,gBAAgB;IAC3B;;;;;OAKG;aACc,MAAM,GAAG,IAAI;IAE9B,mFAAmF;eACxE,MAAM,GAAG,IAAI;IAKxB;;;;;;;;;;;;;;;;;;;;;;OAsBG;kBACW,MAAM,GAAG,OAAO;IA+B9B;;;;;OAKG;sBACe,IAAI;CAGvB,CAAC;AAqBF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,yBAAyB;kBACd,MAAM,GAAG,IAAI;IAEnC;;;;;;;;OAQG;;IAGH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;WACI,MAAM,GAAG,IAAI;IAsBpB;;;;OAIG;eACQ,MAAM,GAAG,IAAI;IAOxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoCG;aACM,IAAI;CAyCd,CAAC"}
|
|
@@ -252,6 +252,62 @@ export function purgePreviousUserClientState() {
|
|
|
252
252
|
sweepStore(safeStore('local'));
|
|
253
253
|
sweepStore(safeStore('session'));
|
|
254
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* Listeners told that {@link SessionUserScope.adopt} dropped a previous
|
|
257
|
+
* owner's state (objectui#10193).
|
|
258
|
+
*/
|
|
259
|
+
const ownerChangeListeners = new Set();
|
|
260
|
+
/**
|
|
261
|
+
* How many times THIS page-load has dropped a previous owner's state.
|
|
262
|
+
*
|
|
263
|
+
* In memory on purpose, and never persisted: the question it answers is "has a
|
|
264
|
+
* purge happened since this code started running", and a storage copy would
|
|
265
|
+
* answer it for a page-load that no longer exists. ⛔ It is not a storage key,
|
|
266
|
+
* and the ruling on objectui#10193 refuses one.
|
|
267
|
+
*/
|
|
268
|
+
let ownerChangeCount = 0;
|
|
269
|
+
/**
|
|
270
|
+
* The number of owner changes {@link SessionUserScope.adopt} has performed in
|
|
271
|
+
* this page-load — `0` until a DIFFERENT user than the one the browser
|
|
272
|
+
* previously held is adopted.
|
|
273
|
+
*
|
|
274
|
+
* ## Why a count and not only an event (objectui#10193)
|
|
275
|
+
*
|
|
276
|
+
* The purge sweeps the previous owner's STORAGE, but state that was already
|
|
277
|
+
* derived from that storage before the purge — the UI language the boot
|
|
278
|
+
* resolved out of the previous owner's language slots, above all — lives in
|
|
279
|
+
* memory and is untouched by it. Whoever owns such state has to re-derive it,
|
|
280
|
+
* and the component that does may mount AFTER the purge happened (the shell
|
|
281
|
+
* mounts behind the session gate, the purge fires as the session resolves). A
|
|
282
|
+
* bare event would be missed by it; a count lets a late reader compare against
|
|
283
|
+
* what it has already handled. Shaped for React's `useSyncExternalStore`
|
|
284
|
+
* together with {@link subscribeSessionOwnerChange}.
|
|
285
|
+
*/
|
|
286
|
+
export function getSessionOwnerChangeCount() {
|
|
287
|
+
return ownerChangeCount;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Be told each time {@link SessionUserScope.adopt} drops a previous owner's
|
|
291
|
+
* state. Returns the unsubscribe function. A listener that throws is reported
|
|
292
|
+
* and skipped, never allowed to break the sign-in path that called `adopt`.
|
|
293
|
+
*/
|
|
294
|
+
export function subscribeSessionOwnerChange(listener) {
|
|
295
|
+
ownerChangeListeners.add(listener);
|
|
296
|
+
return () => {
|
|
297
|
+
ownerChangeListeners.delete(listener);
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
function notifyOwnerChange() {
|
|
301
|
+
ownerChangeCount += 1;
|
|
302
|
+
for (const listener of [...ownerChangeListeners]) {
|
|
303
|
+
try {
|
|
304
|
+
listener();
|
|
305
|
+
}
|
|
306
|
+
catch (err) {
|
|
307
|
+
console.warn('[SessionUserScope] an owner-change listener threw:', err);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
255
311
|
/**
|
|
256
312
|
* Which user's client state this browser holds, and the transition that drops
|
|
257
313
|
* the previous user's state.
|
|
@@ -274,6 +330,13 @@ export const SessionUserScope = {
|
|
|
274
330
|
* Record `userId` as the owner of this browser's client state, dropping the
|
|
275
331
|
* previous owner's state wholesale when it changes.
|
|
276
332
|
*
|
|
333
|
+
* Returns `true` when it dropped a previous owner's state, `false`
|
|
334
|
+
* otherwise (same user, first-ever owner, empty id). A drop is also reported
|
|
335
|
+
* to {@link subscribeSessionOwnerChange} listeners and counted by
|
|
336
|
+
* {@link getSessionOwnerChangeCount} (objectui#10193): the purge clears
|
|
337
|
+
* storage, and anything already derived from that storage in memory is the
|
|
338
|
+
* listener's to re-derive.
|
|
339
|
+
*
|
|
277
340
|
* Idempotent: re-adopting the same user purges nothing. Called from
|
|
278
341
|
* `AuthProvider` for real sessions only — the synthetic `preview-user` /
|
|
279
342
|
* `guest` identities never reach it, so a preview mount cannot purge a real
|
|
@@ -288,13 +351,13 @@ export const SessionUserScope = {
|
|
|
288
351
|
*/
|
|
289
352
|
adopt(userId) {
|
|
290
353
|
if (!userId)
|
|
291
|
-
return;
|
|
354
|
+
return false;
|
|
292
355
|
// Already this page-load's owner. Short-circuits before the storage read
|
|
293
356
|
// below, which matters in a browser that REJECTS WRITES: there the pointer
|
|
294
357
|
// write further down silently fails, so every later call would re-read a
|
|
295
358
|
// stale persisted owner and purge again.
|
|
296
359
|
if (this._userId === userId)
|
|
297
|
-
return;
|
|
360
|
+
return false;
|
|
298
361
|
// WHOSE RESIDUE IS IN THIS STORE — read from storage, deliberately not
|
|
299
362
|
// from {@link current}. The two questions are different and take different
|
|
300
363
|
// authorities. `current()` answers "which key do I use right now", and
|
|
@@ -304,7 +367,8 @@ export const SessionUserScope = {
|
|
|
304
367
|
// to drop, and purging on the strength of an in-memory id would delete
|
|
305
368
|
// state that was written for the arriving user.
|
|
306
369
|
const persistedPrevious = readPersisted(SESSION_USER_STORAGE_KEY);
|
|
307
|
-
|
|
370
|
+
const ownerChanged = persistedPrevious !== null && persistedPrevious !== userId;
|
|
371
|
+
if (ownerChanged) {
|
|
308
372
|
purgePreviousUserClientState();
|
|
309
373
|
}
|
|
310
374
|
this._userId = userId;
|
|
@@ -312,6 +376,11 @@ export const SessionUserScope = {
|
|
|
312
376
|
// Unattributable legacy state, cleaned up on any adopt rather than only on
|
|
313
377
|
// a change — see LEGACY_ACTIVE_ORG_KEY.
|
|
314
378
|
removePersisted(LEGACY_ACTIVE_ORG_KEY);
|
|
379
|
+
// Last, so a listener that reads `current()` or the store sees the
|
|
380
|
+
// arriving owner and the swept storage, never a half-adopted state.
|
|
381
|
+
if (ownerChanged)
|
|
382
|
+
notifyOwnerChange();
|
|
383
|
+
return ownerChanged;
|
|
315
384
|
},
|
|
316
385
|
/**
|
|
317
386
|
* Forget the in-memory pointer. Test seam only — production has no reason to
|
package/dist/AuthContext.d.ts
CHANGED
|
@@ -33,8 +33,10 @@ export interface AuthContextValue {
|
|
|
33
33
|
/** Sign up with name, email, and password.
|
|
34
34
|
* Returns `{ requiresVerification: true }` when the server accepted the
|
|
35
35
|
* account but is gating sign-in on email verification; callers should
|
|
36
|
-
* show a "check your inbox" UI instead of navigating to a protected page.
|
|
37
|
-
|
|
36
|
+
* show a "check your inbox" UI instead of navigating to a protected page.
|
|
37
|
+
* `callbackURL` is where the email-verification link lands — see
|
|
38
|
+
* `SignUpData.callbackURL` for the shape the server accepts. */
|
|
39
|
+
signUp: (name: string, email: string, password: string, callbackURL?: string) => Promise<{
|
|
38
40
|
requiresVerification: boolean;
|
|
39
41
|
}>;
|
|
40
42
|
/** Sign out the current user */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../src/AuthContext.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,cAAc,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEzM,MAAM,WAAW,gBAAgB;IAC/B,iCAAiC;IACjC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtB,kCAAkC;IAClC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAClC,wCAAwC;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB;;;;;OAKG;IACH,aAAa,EAAE,OAAO,CAAC;IACvB,oCAAoC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,2BAA2B;IAC3B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,iDAAiD;IACjD,aAAa,EAAE,OAAO,CAAC;IACvB,uEAAuE;IACvE,WAAW,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACvC,sCAAsC;IACtC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D
|
|
1
|
+
{"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../src/AuthContext.ts"],"names":[],"mappings":"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"}
|
package/dist/AuthProvider.js
CHANGED
|
@@ -29,8 +29,8 @@ const METADATA_SEED_CACHE_PREFIX = 'objectui:metadata:';
|
|
|
29
29
|
* (objectui#5198).
|
|
30
30
|
*
|
|
31
31
|
* `sessionStorage` is per-TAB, not per-session, and no sign-out call site
|
|
32
|
-
* reloads the page — `
|
|
33
|
-
*
|
|
32
|
+
* reloads the page — `AppHeader`, `UserMenu` and `RemediationOverlay` all
|
|
33
|
+
* just call `signOut()` and let the SPA keep running.
|
|
34
34
|
* So without this the next person to sign in in the same tab (a shared or
|
|
35
35
|
* kiosk browser, a handover, a support session) is SEEDED from the previous
|
|
36
36
|
* user's entry, and what is in it is that user's PERMISSION-FILTERED app list —
|
|
@@ -334,11 +334,11 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
|
|
|
334
334
|
setIsLoading(false);
|
|
335
335
|
}
|
|
336
336
|
}, [client]);
|
|
337
|
-
const signUp = useCallback(async (name, email, password) => {
|
|
337
|
+
const signUp = useCallback(async (name, email, password, callbackURL) => {
|
|
338
338
|
setIsLoading(true);
|
|
339
339
|
setError(null);
|
|
340
340
|
try {
|
|
341
|
-
const result = await client.signUp({ name, email, password });
|
|
341
|
+
const result = await client.signUp({ name, email, password, ...(callbackURL ? { callbackURL } : {}) });
|
|
342
342
|
if (result.requiresVerification) {
|
|
343
343
|
// No session was created — the user must verify their email before
|
|
344
344
|
// they can sign in. Leave auth state untouched so the caller can
|
package/dist/LoginForm.d.ts
CHANGED
|
@@ -22,8 +22,17 @@ export interface LoginFormLabels {
|
|
|
22
22
|
submittingButton?: string;
|
|
23
23
|
noAccountText?: string;
|
|
24
24
|
signUpText?: string;
|
|
25
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* Divider label between the social provider buttons and the email/password
|
|
27
|
+
* form (defaults to "or continue with email"). Rendered only when the server
|
|
28
|
+
* reports at least one social provider.
|
|
29
|
+
*/
|
|
26
30
|
orText?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Social provider button label (defaults to "Continue with {provider}");
|
|
33
|
+
* `{provider}` is replaced with the provider's display name.
|
|
34
|
+
*/
|
|
35
|
+
socialButton?: string;
|
|
27
36
|
/** Label for the SSO sign-in button (defaults to "Sign in with SSO") */
|
|
28
37
|
ssoButton?: string;
|
|
29
38
|
/**
|
package/dist/LoginForm.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoginForm.d.ts","sourceRoot":"","sources":["../src/LoginForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"LoginForm.d.ts","sourceRoot":"","sources":["../src/LoginForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAWzD,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6FAA6F;IAC7F,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8GAA8G;IAC9G,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gGAAgG;IAChG,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,8FAA8F;IAC9F,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iGAAiG;IACjG,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,yHAAyH;IACzH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,gCAAgC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC5D,uCAAuC;IACvC,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,OAAO,EACP,WAAyB,EACzB,iBAAsC,EACtC,KAAiC,EACjC,WAAyD,EACzD,IAAI,EACJ,QAAgB,EAChB,aAAa,EAAE,QAAsB,EACrC,MAAW,EACX,aAAa,GACd,EAAE,cAAc,qBAsbhB"}
|
package/dist/LoginForm.js
CHANGED
|
@@ -117,7 +117,6 @@ export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgo
|
|
|
117
117
|
submittingButton: labels.submittingButton ?? 'Signing in…',
|
|
118
118
|
noAccountText: labels.noAccountText ?? "Don't have an account?",
|
|
119
119
|
signUpText: labels.signUpText ?? 'Sign up',
|
|
120
|
-
orText: labels.orText ?? 'or',
|
|
121
120
|
ssoButton: labels.ssoButton ?? 'Sign in with SSO',
|
|
122
121
|
usePasswordText: labels.usePasswordText ?? 'Use a password instead',
|
|
123
122
|
backToSsoText: labels.backToSsoText ?? 'Back to single sign-on',
|
|
@@ -234,7 +233,7 @@ export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgo
|
|
|
234
233
|
setSsoSubmitting(false);
|
|
235
234
|
}
|
|
236
235
|
};
|
|
237
|
-
return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: hideIcon ? undefined : (icon ?? _jsx(DefaultLockIcon, {})), title: title, description: ssoEnforced && !showPasswordFallback ? l.ssoOnlyDescription : description }), _jsx("div", { className: "space-y-5", children: configPending ? (_jsx("div", { className: "flex justify-center py-10", role: "status", "aria-live": "polite", "data-testid": "login-config-loading", children: _jsx(AuthSpinner, {}) })) : (_jsxs(_Fragment, { children: [_jsx(SocialSignInButtons, { mode: "sign-in", onProvidersResolved: (hasProviders) => setHasSocialProviders(hasProviders) }), passwordFormVisible ? (mode === 'phone-otp' ? (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-phone", className: AUTH_FIELD_LABEL_CLASS, children: l.phoneLabel }), _jsx("input", { id: "login-phone", type: "tel", placeholder: l.phonePlaceholder, value: phone, onChange: (e) => setPhone(e.target.value), required: true, autoComplete: "tel", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-otp", className: AUTH_FIELD_LABEL_CLASS, children: l.otpCodeLabel }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { id: "login-otp", type: "text", inputMode: "numeric", placeholder: l.otpCodePlaceholder, value: otpCode, onChange: (e) => setOtpCode(e.target.value), required: true, autoComplete: "one-time-code", disabled: isLoading, className: AUTH_INPUT_CLASS }), _jsxs("button", { type: "button", onClick: handleSendOtp, disabled: otpSending || otpCooldown > 0 || !phone.trim() || isLoading, className: "shrink-0 rounded-md border border-input bg-background px-3 py-2 text-sm font-medium transition-colors hover:bg-accent disabled:opacity-50", children: [otpSending && _jsx(AuthSpinner, {}), otpCooldown > 0
|
|
236
|
+
return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: hideIcon ? undefined : (icon ?? _jsx(DefaultLockIcon, {})), title: title, description: ssoEnforced && !showPasswordFallback ? l.ssoOnlyDescription : description }), _jsx("div", { className: "space-y-5", children: configPending ? (_jsx("div", { className: "flex justify-center py-10", role: "status", "aria-live": "polite", "data-testid": "login-config-loading", children: _jsx(AuthSpinner, {}) })) : (_jsxs(_Fragment, { children: [_jsx(SocialSignInButtons, { mode: "sign-in", dividerText: labels.orText, buttonText: labels.socialButton, onProvidersResolved: (hasProviders) => setHasSocialProviders(hasProviders) }), passwordFormVisible ? (mode === 'phone-otp' ? (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-phone", className: AUTH_FIELD_LABEL_CLASS, children: l.phoneLabel }), _jsx("input", { id: "login-phone", type: "tel", placeholder: l.phonePlaceholder, value: phone, onChange: (e) => setPhone(e.target.value), required: true, autoComplete: "tel", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-otp", className: AUTH_FIELD_LABEL_CLASS, children: l.otpCodeLabel }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { id: "login-otp", type: "text", inputMode: "numeric", placeholder: l.otpCodePlaceholder, value: otpCode, onChange: (e) => setOtpCode(e.target.value), required: true, autoComplete: "one-time-code", disabled: isLoading, className: AUTH_INPUT_CLASS }), _jsxs("button", { type: "button", onClick: handleSendOtp, disabled: otpSending || otpCooldown > 0 || !phone.trim() || isLoading, className: "shrink-0 rounded-md border border-input bg-background px-3 py-2 text-sm font-medium transition-colors hover:bg-accent disabled:opacity-50", children: [otpSending && _jsx(AuthSpinner, {}), otpCooldown > 0
|
|
238
237
|
? l.resendOtpCountdownText.replace('{seconds}', String(otpCooldown))
|
|
239
238
|
: l.sendOtpButton] })] })] }), _jsxs("button", { type: "submit", disabled: isLoading || !otpSent, className: AUTH_PRIMARY_BUTTON_CLASS, children: [isLoading && _jsx(AuthSpinner, {}), isLoading ? l.submittingButton : l.submitButton] }), _jsx("button", { type: "button", onClick: () => switchMode('password'), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.usePasswordSignInText })] })) : (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-email", className: AUTH_FIELD_LABEL_CLASS, children: phonePasswordEnabled ? l.emailOrPhoneLabel : l.emailLabel }), _jsx("input", { id: "login-email",
|
|
240
239
|
// `text` (not `email`) when a phone number is also accepted, so the
|
package/dist/RegisterForm.d.ts
CHANGED
|
@@ -23,8 +23,17 @@ export interface RegisterFormLabels {
|
|
|
23
23
|
submittingButton?: string;
|
|
24
24
|
hasAccountText?: string;
|
|
25
25
|
signInText?: string;
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Divider label between the social provider buttons and the email/password
|
|
28
|
+
* form (defaults to "or continue with email"). Rendered only when the server
|
|
29
|
+
* reports at least one social provider.
|
|
30
|
+
*/
|
|
27
31
|
orText?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Social provider button label (defaults to "Sign up with {provider}");
|
|
34
|
+
* `{provider}` is replaced with the provider's display name.
|
|
35
|
+
*/
|
|
36
|
+
socialButton?: string;
|
|
28
37
|
}
|
|
29
38
|
export interface RegisterFormProps {
|
|
30
39
|
/** Callback on successful registration AND auto sign-in. Not called when the
|
|
@@ -34,6 +43,16 @@ export interface RegisterFormProps {
|
|
|
34
43
|
* sign-in on email verification. The page should swap the form for a
|
|
35
44
|
* "check your inbox" confirmation. */
|
|
36
45
|
onVerificationRequired?: (email: string) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Where the email-verification link should land once the address is
|
|
48
|
+
* verified — e.g. the invitation page the user registered from
|
|
49
|
+
* (objectui#10893). Forwarded to `signUp` as better-auth's sign-up
|
|
50
|
+
* `callbackURL`; see `SignUpData.callbackURL` for the only shapes the server
|
|
51
|
+
* accepts (a document-relative `./…` fails the whole sign-up). Omitted, the
|
|
52
|
+
* server default (`/`) applies. Only matters when the server requires email
|
|
53
|
+
* verification — an auto-signed-in registration calls `onSuccess` instead.
|
|
54
|
+
*/
|
|
55
|
+
verificationCallbackURL?: string;
|
|
37
56
|
/** Callback on registration error */
|
|
38
57
|
onError?: (error: Error) => void;
|
|
39
58
|
/** Link to login page */
|
|
@@ -70,5 +89,5 @@ export interface RegisterFormProps {
|
|
|
70
89
|
* />
|
|
71
90
|
* ```
|
|
72
91
|
*/
|
|
73
|
-
export declare function RegisterForm({ onSuccess, onVerificationRequired, onError, loginUrl, title, description, icon, hideIcon, linkComponent: LinkComp, labels, errorMessages, }: RegisterFormProps): React.JSX.Element;
|
|
92
|
+
export declare function RegisterForm({ onSuccess, onVerificationRequired, verificationCallbackURL, onError, loginUrl, title, description, icon, hideIcon, linkComponent: LinkComp, labels, errorMessages, }: RegisterFormProps): React.JSX.Element;
|
|
74
93
|
//# sourceMappingURL=RegisterForm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RegisterForm.d.ts","sourceRoot":"","sources":["../src/RegisterForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAWzD,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB
|
|
1
|
+
{"version":3,"file":"RegisterForm.d.ts","sourceRoot":"","sources":["../src/RegisterForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAWzD,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC;sFACkF;IAClF,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB;;2CAEuC;IACvC,sBAAsB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD;;;;;;;;OAQG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,qCAAqC;IACrC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC5D,uCAAuC;IACvC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAwBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,EAC3B,SAAS,EACT,sBAAsB,EACtB,uBAAuB,EACvB,OAAO,EACP,QAAmB,EACnB,KAA2B,EAC3B,WAAqD,EACrD,IAAI,EACJ,QAAgB,EAChB,aAAa,EAAE,QAAsB,EACrC,MAAW,EACX,aAAa,GACd,EAAE,iBAAiB,qBA4KnB"}
|
package/dist/RegisterForm.js
CHANGED
|
@@ -25,7 +25,7 @@ const DefaultUserPlusIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "n
|
|
|
25
25
|
* />
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
-
export function RegisterForm({ onSuccess, onVerificationRequired, onError, loginUrl = '/login', title = 'Create an account', description = 'Enter your information to get started', icon, hideIcon = false, linkComponent: LinkComp = DefaultLink, labels = {}, errorMessages, }) {
|
|
28
|
+
export function RegisterForm({ onSuccess, onVerificationRequired, verificationCallbackURL, onError, loginUrl = '/login', title = 'Create an account', description = 'Enter your information to get started', icon, hideIcon = false, linkComponent: LinkComp = DefaultLink, labels = {}, errorMessages, }) {
|
|
29
29
|
const { signUp, isLoading } = useAuth();
|
|
30
30
|
const [name, setName] = useState('');
|
|
31
31
|
const [email, setEmail] = useState('');
|
|
@@ -47,7 +47,6 @@ export function RegisterForm({ onSuccess, onVerificationRequired, onError, login
|
|
|
47
47
|
submittingButton: labels.submittingButton ?? 'Creating account…',
|
|
48
48
|
hasAccountText: labels.hasAccountText ?? 'Already have an account?',
|
|
49
49
|
signInText: labels.signInText ?? 'Sign in',
|
|
50
|
-
orText: labels.orText ?? 'or',
|
|
51
50
|
};
|
|
52
51
|
const handleSubmit = async (e) => {
|
|
53
52
|
e.preventDefault();
|
|
@@ -64,7 +63,7 @@ export function RegisterForm({ onSuccess, onVerificationRequired, onError, login
|
|
|
64
63
|
// that the server rejects as "Invalid email" (#3238) — trim before use.
|
|
65
64
|
const trimmedEmail = email.trim();
|
|
66
65
|
try {
|
|
67
|
-
const result = await signUp(name, trimmedEmail, password);
|
|
66
|
+
const result = await signUp(name, trimmedEmail, password, verificationCallbackURL);
|
|
68
67
|
if (result?.requiresVerification) {
|
|
69
68
|
onVerificationRequired?.(trimmedEmail);
|
|
70
69
|
return;
|
|
@@ -78,5 +77,5 @@ export function RegisterForm({ onSuccess, onVerificationRequired, onError, login
|
|
|
78
77
|
onError?.(authError);
|
|
79
78
|
}
|
|
80
79
|
};
|
|
81
|
-
return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: hideIcon ? undefined : (icon ?? _jsx(DefaultUserPlusIcon, {})), title: title, description: description }), _jsxs("div", { className: "space-y-5", children: [_jsx(SocialSignInButtons, { mode: "sign-up" }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-name", className: AUTH_FIELD_LABEL_CLASS, children: l.nameLabel }), _jsx("input", { id: "register-name", type: "text", placeholder: l.namePlaceholder, value: name, onChange: (e) => setName(e.target.value), required: true, autoComplete: "name", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-email", className: AUTH_FIELD_LABEL_CLASS, children: l.emailLabel }), _jsx("input", { id: "register-email", type: "email", placeholder: l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "email", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-password", className: AUTH_FIELD_LABEL_CLASS, children: l.passwordLabel }), _jsx("input", { id: "register-password", type: "password", placeholder: l.passwordPlaceholder, value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 8, autoComplete: "new-password", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-confirm-password", className: AUTH_FIELD_LABEL_CLASS, children: l.confirmPasswordLabel }), _jsx("input", { id: "register-confirm-password", type: "password", placeholder: l.confirmPasswordPlaceholder, value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), required: true, minLength: 8, autoComplete: "new-password", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("button", { type: "submit", disabled: isLoading, className: AUTH_PRIMARY_BUTTON_CLASS, children: [isLoading && _jsx(AuthSpinner, {}), isLoading ? l.submittingButton : l.submitButton] })] })] }), loginUrl && (_jsxs("p", { className: "px-8 text-center text-sm text-muted-foreground", children: [l.hasAccountText, ' ', _jsx(LinkComp, { href: loginUrl, className: AUTH_LINK_CLASS, children: l.signInText })] }))] }));
|
|
80
|
+
return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: hideIcon ? undefined : (icon ?? _jsx(DefaultUserPlusIcon, {})), title: title, description: description }), _jsxs("div", { className: "space-y-5", children: [_jsx(SocialSignInButtons, { mode: "sign-up", dividerText: labels.orText, buttonText: labels.socialButton }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-name", className: AUTH_FIELD_LABEL_CLASS, children: l.nameLabel }), _jsx("input", { id: "register-name", type: "text", placeholder: l.namePlaceholder, value: name, onChange: (e) => setName(e.target.value), required: true, autoComplete: "name", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-email", className: AUTH_FIELD_LABEL_CLASS, children: l.emailLabel }), _jsx("input", { id: "register-email", type: "email", placeholder: l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "email", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-password", className: AUTH_FIELD_LABEL_CLASS, children: l.passwordLabel }), _jsx("input", { id: "register-password", type: "password", placeholder: l.passwordPlaceholder, value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 8, autoComplete: "new-password", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-confirm-password", className: AUTH_FIELD_LABEL_CLASS, children: l.confirmPasswordLabel }), _jsx("input", { id: "register-confirm-password", type: "password", placeholder: l.confirmPasswordPlaceholder, value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), required: true, minLength: 8, autoComplete: "new-password", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("button", { type: "submit", disabled: isLoading, className: AUTH_PRIMARY_BUTTON_CLASS, children: [isLoading && _jsx(AuthSpinner, {}), isLoading ? l.submittingButton : l.submitButton] })] })] }), loginUrl && (_jsxs("p", { className: "px-8 text-center text-sm text-muted-foreground", children: [l.hasAccountText, ' ', _jsx(LinkComp, { href: loginUrl, className: AUTH_LINK_CLASS, children: l.signInText })] }))] }));
|
|
82
81
|
}
|
|
@@ -13,8 +13,15 @@ export interface SocialSignInButtonsProps {
|
|
|
13
13
|
callbackURL?: string;
|
|
14
14
|
/** Where the provider should redirect on error. Defaults to current page. */
|
|
15
15
|
errorCallbackURL?: string;
|
|
16
|
-
/** Divider text shown between social buttons and the email form */
|
|
16
|
+
/** Divider text shown between social buttons and the email form (defaults to "or continue with email") */
|
|
17
17
|
dividerText?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Provider button label, for i18n. `{provider}` is replaced with the
|
|
20
|
+
* provider's display name, so a translation places the name where its
|
|
21
|
+
* grammar needs it. Defaults to "Continue with {provider}" in `sign-in`
|
|
22
|
+
* mode and "Sign up with {provider}" in `sign-up` mode.
|
|
23
|
+
*/
|
|
24
|
+
buttonText?: string;
|
|
18
25
|
/** Called once after config resolves with whether any social providers are available. */
|
|
19
26
|
onProvidersResolved?: (hasProviders: boolean) => void;
|
|
20
27
|
}
|
|
@@ -25,5 +32,5 @@ export interface SocialSignInButtonsProps {
|
|
|
25
32
|
*
|
|
26
33
|
* Returns `null` while loading or when the server reports no providers.
|
|
27
34
|
*/
|
|
28
|
-
export declare function SocialSignInButtons({ mode, callbackURL, errorCallbackURL, dividerText, onProvidersResolved, }: SocialSignInButtonsProps): React.JSX.Element | null;
|
|
35
|
+
export declare function SocialSignInButtons({ mode, callbackURL, errorCallbackURL, dividerText, buttonText, onProvidersResolved, }: SocialSignInButtonsProps): React.JSX.Element | null;
|
|
29
36
|
//# sourceMappingURL=SocialSignInButtons.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SocialSignInButtons.d.ts","sourceRoot":"","sources":["../src/SocialSignInButtons.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAkFnD,MAAM,WAAW,wBAAwB;IACvC,sFAAsF;IACtF,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,
|
|
1
|
+
{"version":3,"file":"SocialSignInButtons.d.ts","sourceRoot":"","sources":["../src/SocialSignInButtons.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAkFnD,MAAM,WAAW,wBAAwB;IACvC,sFAAsF;IACtF,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0GAA0G;IAC1G,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,mBAAmB,CAAC,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;CACvD;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,IAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,WAAsC,EACtC,UAAU,EACV,mBAAmB,GACpB,EAAE,wBAAwB,4BA2F1B"}
|