@object-ui/auth 17.5.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 +600 -0
- package/README.md +245 -15
- package/dist/ActiveOrganizationStorage.d.ts +199 -0
- package/dist/ActiveOrganizationStorage.d.ts.map +1 -0
- package/dist/ActiveOrganizationStorage.js +584 -0
- package/dist/AuthContext.d.ts +23 -3
- package/dist/AuthContext.d.ts.map +1 -1
- package/dist/AuthGuard.d.ts +8 -1
- package/dist/AuthGuard.d.ts.map +1 -1
- package/dist/AuthGuard.js +16 -3
- package/dist/AuthProvider.d.ts +1 -1
- package/dist/AuthProvider.d.ts.map +1 -1
- package/dist/AuthProvider.js +274 -9
- package/dist/ForgotPasswordForm.d.ts +1 -1
- package/dist/ForgotPasswordForm.d.ts.map +1 -1
- package/dist/ForgotPasswordForm.js +5 -5
- package/dist/LoginForm.d.ts +11 -2
- package/dist/LoginForm.d.ts.map +1 -1
- package/dist/LoginForm.js +5 -6
- package/dist/PreviewBanner.js +1 -1
- package/dist/RegisterForm.d.ts +22 -3
- package/dist/RegisterForm.d.ts.map +1 -1
- package/dist/RegisterForm.js +6 -7
- package/dist/SocialSignInButtons.d.ts +9 -2
- package/dist/SocialSignInButtons.d.ts.map +1 -1
- package/dist/SocialSignInButtons.js +5 -5
- package/dist/UserMenu.d.ts +1 -1
- package/dist/UserMenu.js +3 -3
- package/dist/createAuthClient.d.ts +1 -1
- package/dist/createAuthClient.d.ts.map +1 -1
- package/dist/createAuthClient.js +42 -4
- package/dist/createAuthenticatedFetch.d.ts +9 -9
- package/dist/createAuthenticatedFetch.d.ts.map +1 -1
- package/dist/createAuthenticatedFetch.js +50 -38
- package/dist/index.d.ts +21 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -17
- package/dist/invitation-status.d.ts +59 -0
- package/dist/invitation-status.d.ts.map +1 -0
- package/dist/invitation-status.js +32 -0
- package/dist/types.d.ts +25 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/useAuth.d.ts +1 -1
- package/dist/useAuth.d.ts.map +1 -1
- package/dist/useAuth.js +5 -1
- package/dist/useWorkspaceAdminStatus.d.ts +134 -0
- package/dist/useWorkspaceAdminStatus.d.ts.map +1 -0
- package/dist/useWorkspaceAdminStatus.js +208 -0
- package/package.json +6 -7
- package/dist/useIsWorkspaceAdmin.d.ts +0 -21
- package/dist/useIsWorkspaceAdmin.d.ts.map +0 -1
- package/dist/useIsWorkspaceAdmin.js +0 -47
package/dist/RegisterForm.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
import React from 'react';
|
|
9
|
-
import type { AuthLinkComponentProps } from './types';
|
|
9
|
+
import type { AuthLinkComponentProps } from './types.js';
|
|
10
10
|
/** Translatable labels for the RegisterForm */
|
|
11
11
|
export interface RegisterFormLabels {
|
|
12
12
|
nameLabel?: string;
|
|
@@ -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,
|
|
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
|
@@ -7,9 +7,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
7
7
|
* LICENSE file in the root directory of this source tree.
|
|
8
8
|
*/
|
|
9
9
|
import { useState } from 'react';
|
|
10
|
-
import { useAuth } from './useAuth';
|
|
11
|
-
import { SocialSignInButtons } from './SocialSignInButtons';
|
|
12
|
-
import { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthErrorBanner, AuthFormHeader, AuthSpinner, } from './authStyles';
|
|
10
|
+
import { useAuth } from './useAuth.js';
|
|
11
|
+
import { SocialSignInButtons } from './SocialSignInButtons.js';
|
|
12
|
+
import { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthErrorBanner, AuthFormHeader, AuthSpinner, } from './authStyles.js';
|
|
13
13
|
const DefaultLink = ({ href, className, children }) => (_jsx("a", { href: href, className: className, children: children }));
|
|
14
14
|
const DefaultUserPlusIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round", className: "h-6 w-6", "aria-hidden": "true", children: [_jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }), _jsx("circle", { cx: "9", cy: "7", r: "4" }), _jsx("line", { x1: "19", y1: "8", x2: "19", y2: "14" }), _jsx("line", { x1: "22", y1: "11", x2: "16", y2: "11" })] }));
|
|
15
15
|
/**
|
|
@@ -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"}
|
|
@@ -7,8 +7,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
7
7
|
* LICENSE file in the root directory of this source tree.
|
|
8
8
|
*/
|
|
9
9
|
import { useEffect, useState } from 'react';
|
|
10
|
-
import { useAuth } from './useAuth';
|
|
11
|
-
import { AuthSpinner } from './authStyles';
|
|
10
|
+
import { useAuth } from './useAuth.js';
|
|
11
|
+
import { AuthSpinner } from './authStyles.js';
|
|
12
12
|
// Brand name overrides for providers whose `name` from the server may be unset
|
|
13
13
|
// or where we want to canonicalize casing.
|
|
14
14
|
const PROVIDER_LABEL = {
|
|
@@ -48,7 +48,7 @@ function ProviderIcon({ id }) {
|
|
|
48
48
|
*
|
|
49
49
|
* Returns `null` while loading or when the server reports no providers.
|
|
50
50
|
*/
|
|
51
|
-
export function SocialSignInButtons({ mode = 'sign-in', callbackURL, errorCallbackURL, dividerText = 'or continue with email', onProvidersResolved, }) {
|
|
51
|
+
export function SocialSignInButtons({ mode = 'sign-in', callbackURL, errorCallbackURL, dividerText = 'or continue with email', buttonText, onProvidersResolved, }) {
|
|
52
52
|
const { getAuthConfig, signInWithProvider } = useAuth();
|
|
53
53
|
const [providers, setProviders] = useState([]);
|
|
54
54
|
const [loading, setLoading] = useState(true);
|
|
@@ -86,7 +86,7 @@ export function SocialSignInButtons({ mode = 'sign-in', callbackURL, errorCallba
|
|
|
86
86
|
}, [getAuthConfig]);
|
|
87
87
|
if (loading || providers.length === 0)
|
|
88
88
|
return null;
|
|
89
|
-
const
|
|
89
|
+
const labelTemplate = buttonText ?? (mode === 'sign-in' ? 'Continue with {provider}' : 'Sign up with {provider}');
|
|
90
90
|
const defaultCallback = typeof window !== 'undefined' ? window.location.href : undefined;
|
|
91
91
|
const onClick = async (provider) => {
|
|
92
92
|
if (pendingId)
|
|
@@ -107,5 +107,5 @@ export function SocialSignInButtons({ mode = 'sign-in', callbackURL, errorCallba
|
|
|
107
107
|
setPendingId(null);
|
|
108
108
|
}
|
|
109
109
|
};
|
|
110
|
-
return (_jsxs("div", { className: "flex flex-col gap-2", children: [error && (_jsx("div", { className: "rounded-md bg-destructive/15 p-3 text-sm text-destructive", role: "alert", children: error })), providers.map((p) => (_jsxs("button", { type: "button", onClick: () => onClick(p), disabled: pendingId !== null, "aria-busy": pendingId === p.id, className: "inline-flex h-10 w-full items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", children: [pendingId === p.id ? _jsx(AuthSpinner, {}) : _jsx(ProviderIcon, { id: p.id }),
|
|
110
|
+
return (_jsxs("div", { className: "flex flex-col gap-2", children: [error && (_jsx("div", { className: "rounded-md bg-destructive/15 p-3 text-sm text-destructive", role: "alert", children: error })), providers.map((p) => (_jsxs("button", { type: "button", onClick: () => onClick(p), disabled: pendingId !== null, "aria-busy": pendingId === p.id, className: "inline-flex h-10 w-full items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", children: [pendingId === p.id ? _jsx(AuthSpinner, {}) : _jsx(ProviderIcon, { id: p.id }), labelTemplate.replace('{provider}', () => PROVIDER_LABEL[p.id] ?? p.name)] }, p.id))), _jsxs("div", { className: "relative my-1", children: [_jsx("div", { className: "absolute inset-0 flex items-center", children: _jsx("span", { className: "w-full border-t" }) }), _jsx("div", { className: "relative flex justify-center text-xs uppercase", children: _jsx("span", { className: "bg-background px-2 text-muted-foreground", children: dividerText }) })] })] }));
|
|
111
111
|
}
|
package/dist/UserMenu.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export interface UserMenuProps {
|
|
|
21
21
|
* Shows avatar, name, email, and common actions (profile, settings, sign out).
|
|
22
22
|
*
|
|
23
23
|
* This is a headless component that provides the user data and actions.
|
|
24
|
-
* The actual dropdown rendering is handled by the consumer
|
|
24
|
+
* The actual dropdown rendering is handled by the consumer.
|
|
25
25
|
*
|
|
26
26
|
* @example
|
|
27
27
|
* ```tsx
|
package/dist/UserMenu.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAuth } from './useAuth';
|
|
3
|
-
import { getUserInitials } from './types';
|
|
2
|
+
import { useAuth } from './useAuth.js';
|
|
3
|
+
import { getUserInitials } from './types.js';
|
|
4
4
|
/**
|
|
5
5
|
* User menu component displaying the authenticated user's info.
|
|
6
6
|
* Shows avatar, name, email, and common actions (profile, settings, sign out).
|
|
7
7
|
*
|
|
8
8
|
* This is a headless component that provides the user data and actions.
|
|
9
|
-
* The actual dropdown rendering is handled by the consumer
|
|
9
|
+
* The actual dropdown rendering is handled by the consumer.
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
12
|
* ```tsx
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* This source code is licensed under the MIT license found in the
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
|
-
import type { AuthClient, AuthClientConfig } from './types';
|
|
8
|
+
import type { AuthClient, AuthClientConfig } from './types.js';
|
|
9
9
|
/**
|
|
10
10
|
* Simple token storage backed by localStorage.
|
|
11
11
|
* Falls back to in-memory storage when localStorage is unavailable (SSR, tests).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createAuthClient.d.ts","sourceRoot":"","sources":["../src/createAuthClient.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EACV,UAAU,EAAE,gBAAgB,EAE7B,MAAM,
|
|
1
|
+
{"version":3,"file":"createAuthClient.d.ts","sourceRoot":"","sources":["../src/createAuthClient.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EACV,UAAU,EAAE,gBAAgB,EAE7B,MAAM,YAAY,CAAC;AAKpB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,YAAY;kBACD,MAAM,GAAG,IAAI;kCACD,IAAI;WAE/B,MAAM,GAAG,IAAI;eAST,MAAM,GAAG,IAAI;aAkBf,IAAI;IASb;;;OAGG;gCACyB,MAAM,IAAI,GAAG,MAAM,IAAI;CAMpD,CAAC;AA2KF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CA2rBrE"}
|
package/dist/createAuthClient.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { createAuthClient as createBetterAuthClient } from 'better-auth/client';
|
|
9
9
|
import { organizationClient, twoFactorClient } from 'better-auth/client/plugins';
|
|
10
|
+
import { AUTH_INVITATION_STATUSES, isAuthInvitationStatus } from './invitation-status.js';
|
|
10
11
|
const TOKEN_STORAGE_KEY = 'auth-session-token';
|
|
11
12
|
/**
|
|
12
13
|
* Simple token storage backed by localStorage.
|
|
@@ -109,6 +110,37 @@ function toAuthError(error, fallbackMessage) {
|
|
|
109
110
|
err.code = error.code;
|
|
110
111
|
return err;
|
|
111
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* The wire boundary for invitations (objectui#3879).
|
|
115
|
+
*
|
|
116
|
+
* better-auth's client hands these routes back as `any`, so `as AuthInvitation`
|
|
117
|
+
* was a claim nothing checked — and with `status` narrowed to a closed union,
|
|
118
|
+
* an unchecked cast would make that union a comment again the day a backend
|
|
119
|
+
* stored a fifth value. This is the ONE place the claim is verified.
|
|
120
|
+
*
|
|
121
|
+
* It fails LOUDLY, naming the offending value, rather than degrading: a status
|
|
122
|
+
* outside better-auth's own `InvitationStatus` is a producer defect, and the
|
|
123
|
+
* alternatives all hide it — a neutral badge label renders it as UI copy in ten
|
|
124
|
+
* packs (the objectui#3879 symptom), and dropping the row deletes an invitation
|
|
125
|
+
* from an administrative ledger without saying so. Both call paths already
|
|
126
|
+
* render a rejection with a retry (`InvitationsPage`, `AcceptInvitationPage`),
|
|
127
|
+
* so the throw lands on a designed surface; `resolveOrgErrorMessage` shows the
|
|
128
|
+
* sentence verbatim, which is that module's own stated preference over
|
|
129
|
+
* swallowing an error.
|
|
130
|
+
*/
|
|
131
|
+
function asAuthInvitation(raw, method) {
|
|
132
|
+
const status = raw?.status;
|
|
133
|
+
if (!isAuthInvitationStatus(status)) {
|
|
134
|
+
throw new Error(`${method}: unexpected invitation status ${JSON.stringify(status)} — ` +
|
|
135
|
+
`expected one of ${AUTH_INVITATION_STATUSES.join(' | ')}`);
|
|
136
|
+
}
|
|
137
|
+
return raw;
|
|
138
|
+
}
|
|
139
|
+
/** Same boundary, per row, for the list-returning invitation routes. */
|
|
140
|
+
function asAuthInvitations(raw, method) {
|
|
141
|
+
const rows = Array.isArray(raw) ? raw : [];
|
|
142
|
+
return rows.map((row) => asAuthInvitation(row, method));
|
|
143
|
+
}
|
|
112
144
|
/**
|
|
113
145
|
* Resolve a baseURL (which may be relative or absolute) into the
|
|
114
146
|
* `{ origin, basePath }` pair required by the better-auth client.
|
|
@@ -328,6 +360,12 @@ export function createAuthClient(config) {
|
|
|
328
360
|
email: signUpData.email,
|
|
329
361
|
password: signUpData.password,
|
|
330
362
|
name: signUpData.name,
|
|
363
|
+
// objectui#10893 — the verification mail's link lands here. Without
|
|
364
|
+
// it better-auth writes `callbackURL=/`, and an invitee who registers
|
|
365
|
+
// from an invitation link is dropped on the workspace picker instead
|
|
366
|
+
// of the invitation. Only sent when the caller has somewhere to go,
|
|
367
|
+
// so the server default is untouched otherwise.
|
|
368
|
+
...(signUpData.callbackURL ? { callbackURL: signUpData.callbackURL } : {}),
|
|
331
369
|
});
|
|
332
370
|
if (error) {
|
|
333
371
|
throw toAuthError(error);
|
|
@@ -753,7 +791,7 @@ export function createAuthClient(config) {
|
|
|
753
791
|
});
|
|
754
792
|
if (error)
|
|
755
793
|
throw toAuthError(error, 'Failed to invite member');
|
|
756
|
-
return data;
|
|
794
|
+
return asAuthInvitation(data, 'inviteMember');
|
|
757
795
|
},
|
|
758
796
|
async removeMember(removeData) {
|
|
759
797
|
const { error } = await betterAuth.organization.removeMember({
|
|
@@ -802,7 +840,7 @@ export function createAuthClient(config) {
|
|
|
802
840
|
});
|
|
803
841
|
if (error)
|
|
804
842
|
throw toAuthError(error, 'Failed to list invitations');
|
|
805
|
-
return (data
|
|
843
|
+
return asAuthInvitations(data, 'listInvitations');
|
|
806
844
|
},
|
|
807
845
|
async cancelInvitation(invitationId) {
|
|
808
846
|
const { error } = await betterAuth.organization.cancelInvitation({ invitationId });
|
|
@@ -815,7 +853,7 @@ export function createAuthClient(config) {
|
|
|
815
853
|
});
|
|
816
854
|
if (error)
|
|
817
855
|
throw toAuthError(error, 'Failed to load invitation');
|
|
818
|
-
return data;
|
|
856
|
+
return asAuthInvitation(data, 'getInvitation');
|
|
819
857
|
},
|
|
820
858
|
async acceptInvitation(invitationId) {
|
|
821
859
|
const { error } = await betterAuth.organization.acceptInvitation({ invitationId });
|
|
@@ -831,7 +869,7 @@ export function createAuthClient(config) {
|
|
|
831
869
|
const { data, error } = await betterAuth.organization.listUserInvitations();
|
|
832
870
|
if (error)
|
|
833
871
|
throw toAuthError(error, 'Failed to list invitations');
|
|
834
|
-
return (data
|
|
872
|
+
return asAuthInvitations(data, 'listUserInvitations');
|
|
835
873
|
},
|
|
836
874
|
};
|
|
837
875
|
}
|
|
@@ -15,15 +15,13 @@ export interface AuthenticatedAdapterOptions {
|
|
|
15
15
|
[key: string]: unknown;
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* Re-exported from its own module so this file stays the WIRE lane and the
|
|
19
|
+
* storage lane has one home. `ActiveOrganizationStorage` moved out when it
|
|
20
|
+
* gained per-user scoping (objectui#5664); the export identity is unchanged,
|
|
21
|
+
* so `@object-ui/auth`'s barrel, this package's tests and every consumer
|
|
22
|
+
* import the same symbol from the same place they did before.
|
|
20
23
|
*/
|
|
21
|
-
export
|
|
22
|
-
_memoryValue: string | null;
|
|
23
|
-
get(): string | null;
|
|
24
|
-
set(orgId: string): void;
|
|
25
|
-
clear(): void;
|
|
26
|
-
};
|
|
24
|
+
export { ActiveOrganizationStorage, SessionUserScope, purgePreviousUserClientState, getSessionOwnerChangeCount, subscribeSessionOwnerChange, } from './ActiveOrganizationStorage.js';
|
|
27
25
|
export interface CreateAuthenticatedFetchOptions {
|
|
28
26
|
/**
|
|
29
27
|
* When true, requests whose URL resolves to a different origin than the
|
|
@@ -39,7 +37,9 @@ export interface CreateAuthenticatedFetchOptions {
|
|
|
39
37
|
/**
|
|
40
38
|
* Creates an authenticated fetch wrapper that injects the Bearer token
|
|
41
39
|
* from localStorage into every request to the ObjectStack API.
|
|
42
|
-
* Also injects X-Tenant-ID header when an active organization is set
|
|
40
|
+
* Also injects X-Tenant-ID header when an active organization is set — see the
|
|
41
|
+
* "The `X-Tenant-ID` edge contract" section of this package's README for what
|
|
42
|
+
* that header means, who reads it, and the window in which it is not sent.
|
|
43
43
|
*
|
|
44
44
|
* @example
|
|
45
45
|
* ```ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createAuthenticatedFetch.d.ts","sourceRoot":"","sources":["../src/createAuthenticatedFetch.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"createAuthenticatedFetch.d.ts","sourceRoot":"","sources":["../src/createAuthenticatedFetch.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;GAMG;AACH,OAAO,EACL,yBAAyB,EACzB,gBAAgB,EAChB,4BAA4B,EAC5B,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,gCAAgC,CAAC;AAExC,MAAM,WAAW,+BAA+B;IAC9C;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAYD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,CAAC,EAAE,+BAA+B,GACxC,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CA+GrE"}
|
|
@@ -5,43 +5,17 @@
|
|
|
5
5
|
* This source code is licensed under the MIT license found in the
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
|
-
import { TokenStorage } from './createAuthClient';
|
|
9
|
-
import { authGateEvents, detectAuthGate } from './auth-gate-events';
|
|
10
|
-
|
|
8
|
+
import { TokenStorage } from './createAuthClient.js';
|
|
9
|
+
import { authGateEvents, detectAuthGate } from './auth-gate-events.js';
|
|
10
|
+
import { ActiveOrganizationStorage } from './ActiveOrganizationStorage.js';
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* Re-exported from its own module so this file stays the WIRE lane and the
|
|
13
|
+
* storage lane has one home. `ActiveOrganizationStorage` moved out when it
|
|
14
|
+
* gained per-user scoping (objectui#5664); the export identity is unchanged,
|
|
15
|
+
* so `@object-ui/auth`'s barrel, this package's tests and every consumer
|
|
16
|
+
* import the same symbol from the same place they did before.
|
|
14
17
|
*/
|
|
15
|
-
export
|
|
16
|
-
_memoryValue: null,
|
|
17
|
-
get() {
|
|
18
|
-
try {
|
|
19
|
-
if (typeof localStorage !== 'undefined') {
|
|
20
|
-
return localStorage.getItem(ACTIVE_ORG_STORAGE_KEY);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
catch { /* SSR / test */ }
|
|
24
|
-
return this._memoryValue;
|
|
25
|
-
},
|
|
26
|
-
set(orgId) {
|
|
27
|
-
this._memoryValue = orgId;
|
|
28
|
-
try {
|
|
29
|
-
if (typeof localStorage !== 'undefined') {
|
|
30
|
-
localStorage.setItem(ACTIVE_ORG_STORAGE_KEY, orgId);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
catch { /* SSR / test */ }
|
|
34
|
-
},
|
|
35
|
-
clear() {
|
|
36
|
-
this._memoryValue = null;
|
|
37
|
-
try {
|
|
38
|
-
if (typeof localStorage !== 'undefined') {
|
|
39
|
-
localStorage.removeItem(ACTIVE_ORG_STORAGE_KEY);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
catch { /* SSR / test */ }
|
|
43
|
-
},
|
|
44
|
-
};
|
|
18
|
+
export { ActiveOrganizationStorage, SessionUserScope, purgePreviousUserClientState, getSessionOwnerChangeCount, subscribeSessionOwnerChange, } from './ActiveOrganizationStorage.js';
|
|
45
19
|
/** True when `url` resolves to a different origin than the current page. */
|
|
46
20
|
function isCrossOrigin(url) {
|
|
47
21
|
if (typeof window === 'undefined' || !window.location)
|
|
@@ -56,7 +30,9 @@ function isCrossOrigin(url) {
|
|
|
56
30
|
/**
|
|
57
31
|
* Creates an authenticated fetch wrapper that injects the Bearer token
|
|
58
32
|
* from localStorage into every request to the ObjectStack API.
|
|
59
|
-
* Also injects X-Tenant-ID header when an active organization is set
|
|
33
|
+
* Also injects X-Tenant-ID header when an active organization is set — see the
|
|
34
|
+
* "The `X-Tenant-ID` edge contract" section of this package's README for what
|
|
35
|
+
* that header means, who reads it, and the window in which it is not sent.
|
|
60
36
|
*
|
|
61
37
|
* @example
|
|
62
38
|
* ```ts
|
|
@@ -83,7 +59,43 @@ export function createAuthenticatedFetch(options) {
|
|
|
83
59
|
if (token && isApiCall) {
|
|
84
60
|
headers.set('Authorization', `Bearer ${token}`);
|
|
85
61
|
}
|
|
86
|
-
//
|
|
62
|
+
// ── `X-Tenant-ID` — the edge routing contract (objectui#5279) ────────
|
|
63
|
+
//
|
|
64
|
+
// WHAT IT MEANS. A routing hint for the hosting edge: "this request belongs
|
|
65
|
+
// to tenant <id>". The value is the better-auth `activeOrganizationId` the
|
|
66
|
+
// session already carries. It is NOT an identity claim, NOT an
|
|
67
|
+
// authorization input, and NOT what scopes rows.
|
|
68
|
+
//
|
|
69
|
+
// DO NOT DELETE THIS ON THE STRENGTH OF A GREP. The framework
|
|
70
|
+
// (`objectstack`) does not read it: `resolveAuthzContext` takes `tenantId`
|
|
71
|
+
// from the API-key principal or `session.activeOrganizationId` and never
|
|
72
|
+
// from a header, and environment routing reads the hostname and
|
|
73
|
+
// `X-Environment-Id`. So a search confined to this repo plus the framework
|
|
74
|
+
// finds zero consumers and reads as "dead stamp" — which is the false
|
|
75
|
+
// premise objectui#5279 was filed on. The consumer is in the CLOUD repo,
|
|
76
|
+
// which neither checkout contains: `service-tenant`'s `tenant-context.ts`
|
|
77
|
+
// resolves the header, and `tenant-router`'s `turso-multi-tenant.zod.ts`
|
|
78
|
+
// configures that resolution. The configuration contract IS readable from
|
|
79
|
+
// here — `TenantRoutingConfigSchema` in `@objectstack/spec/cloud` defaults
|
|
80
|
+
// `tenantHeaderName` to `X-Tenant-ID` and ranks `header` SECOND of six
|
|
81
|
+
// identification sources, behind `subdomain`.
|
|
82
|
+
//
|
|
83
|
+
// THE UNSTAMPED-FIRST-REQUEST GAP. `ActiveOrganizationStorage` is filled
|
|
84
|
+
// only after AuthProvider's async organization chain resolves, so early
|
|
85
|
+
// requests go out with the header ABSENT — never present-and-empty. A
|
|
86
|
+
// reader must fall through to its next identification source rather than
|
|
87
|
+
// fail closed. Nothing about row visibility rides on this: the framework
|
|
88
|
+
// scopes from the session, so a response computed inside the window is
|
|
89
|
+
// still computed for the right tenant.
|
|
90
|
+
//
|
|
91
|
+
// Not gated on `isApiCall`, unlike `Authorization` and `Accept-Language`
|
|
92
|
+
// above — recorded as the behaviour that ships, not endorsed; the
|
|
93
|
+
// asymmetry is reported on objectui#5279 for triage to route. A wrapper
|
|
94
|
+
// built with `sameOriginOnly` short-circuits every cross-origin request
|
|
95
|
+
// before this line.
|
|
96
|
+
//
|
|
97
|
+
// Full contract, including what a reader may and may not assume: this
|
|
98
|
+
// package's README, "The `X-Tenant-ID` edge contract".
|
|
87
99
|
const activeOrgId = ActiveOrganizationStorage.get();
|
|
88
100
|
if (activeOrgId) {
|
|
89
101
|
headers.set('X-Tenant-ID', activeOrgId);
|
|
@@ -94,7 +106,7 @@ export function createAuthenticatedFetch(options) {
|
|
|
94
106
|
// switcher, so reading it here means a language switch carries the new
|
|
95
107
|
// `Accept-Language` on every subsequent request — closing the gap where
|
|
96
108
|
// server-resolved labels stayed in the old language until a page refresh
|
|
97
|
-
// (issue #1319). We only fold it in for our own API calls, and never
|
|
109
|
+
// (issue objectstack-ai/objectstack#1319). We only fold it in for our own API calls, and never
|
|
98
110
|
// clobber an `Accept-Language` the caller set explicitly.
|
|
99
111
|
if (isApiCall && !headers.has('Accept-Language') && typeof document !== 'undefined') {
|
|
100
112
|
const lang = document.documentElement.lang;
|
package/dist/index.d.ts
CHANGED
|
@@ -19,23 +19,25 @@
|
|
|
19
19
|
*
|
|
20
20
|
* @packageDocumentation
|
|
21
21
|
*/
|
|
22
|
-
export { AuthProvider, type AuthProviderProps } from './AuthProvider';
|
|
23
|
-
export { useAuth } from './useAuth';
|
|
24
|
-
export {
|
|
25
|
-
export { AuthGuard, type AuthGuardProps } from './AuthGuard';
|
|
26
|
-
export { AuthShell, type AuthShellProps, type AuthShellBrandPanel } from './AuthShell';
|
|
27
|
-
export { LoginForm, type LoginFormProps, type LoginFormLabels } from './LoginForm';
|
|
28
|
-
export { RegisterForm, type RegisterFormProps, type RegisterFormLabels } from './RegisterForm';
|
|
29
|
-
export { ForgotPasswordForm, type ForgotPasswordFormProps, type ForgotPasswordFormLabels } from './ForgotPasswordForm';
|
|
30
|
-
export { SocialSignInButtons, type SocialSignInButtonsProps } from './SocialSignInButtons';
|
|
31
|
-
export { UserMenu, type UserMenuProps } from './UserMenu';
|
|
32
|
-
export { PreviewBanner, type PreviewBannerProps } from './PreviewBanner';
|
|
33
|
-
export { createAuthClient, TokenStorage } from './createAuthClient';
|
|
34
|
-
export { normalizePhoneIdentifier, looksLikePhoneIdentifier } from './phone-identifier';
|
|
35
|
-
export { createAuthenticatedFetch, ActiveOrganizationStorage, type AuthenticatedAdapterOptions } from './createAuthenticatedFetch';
|
|
36
|
-
export {
|
|
37
|
-
export {
|
|
38
|
-
export {
|
|
39
|
-
export
|
|
40
|
-
export
|
|
22
|
+
export { AuthProvider, type AuthProviderProps } from './AuthProvider.js';
|
|
23
|
+
export { useAuth } from './useAuth.js';
|
|
24
|
+
export { useWorkspaceAdminStatus, type WorkspaceAdminStatus } from './useWorkspaceAdminStatus.js';
|
|
25
|
+
export { AuthGuard, type AuthGuardProps } from './AuthGuard.js';
|
|
26
|
+
export { AuthShell, type AuthShellProps, type AuthShellBrandPanel } from './AuthShell.js';
|
|
27
|
+
export { LoginForm, type LoginFormProps, type LoginFormLabels } from './LoginForm.js';
|
|
28
|
+
export { RegisterForm, type RegisterFormProps, type RegisterFormLabels } from './RegisterForm.js';
|
|
29
|
+
export { ForgotPasswordForm, type ForgotPasswordFormProps, type ForgotPasswordFormLabels } from './ForgotPasswordForm.js';
|
|
30
|
+
export { SocialSignInButtons, type SocialSignInButtonsProps } from './SocialSignInButtons.js';
|
|
31
|
+
export { UserMenu, type UserMenuProps } from './UserMenu.js';
|
|
32
|
+
export { PreviewBanner, type PreviewBannerProps } from './PreviewBanner.js';
|
|
33
|
+
export { createAuthClient, TokenStorage } from './createAuthClient.js';
|
|
34
|
+
export { normalizePhoneIdentifier, looksLikePhoneIdentifier } from './phone-identifier.js';
|
|
35
|
+
export { createAuthenticatedFetch, ActiveOrganizationStorage, type AuthenticatedAdapterOptions } from './createAuthenticatedFetch.js';
|
|
36
|
+
export { getSessionOwnerChangeCount, subscribeSessionOwnerChange } from './ActiveOrganizationStorage.js';
|
|
37
|
+
export { getUserInitials } from './types.js';
|
|
38
|
+
export { ORG_ROLE_OWNER, ORG_ROLE_ADMIN, ORG_ROLE_DELEGATED_ADMIN, ORG_ROLE_MEMBER, ORG_ROLES, ORG_ROLE_LABELS, orgRoleGrade, invitableOrgRoles, assignableOrgRoles, type OrgRole, } from './org-roles.js';
|
|
39
|
+
export { AUTH_INVITATION_STATUSES, isAuthInvitationStatus, type AuthInvitationStatus, } from './invitation-status.js';
|
|
40
|
+
export { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthAlertIcon, AuthCheckIcon, AuthDivider, AuthErrorBanner, AuthFormHeader, AuthMailIcon, AuthSpinner, } from './authStyles.js';
|
|
41
|
+
export type { AuthUser, AuthClientSession, AuthState, AuthClient, AuthClientConfig, AuthLinkComponentProps, AuthProviderOptions, PreviewModeOptions, SignInCredentials, SignUpData, AuthOrganization, AuthOrganizationMember, AuthInvitation, AuthSocialProvider, AuthPublicConfig, SignInWithProviderOptions, TenancyPosture, DelegableScope, } from './types.js';
|
|
42
|
+
export type { AuthContextValue } from './AuthContext.js';
|
|
41
43
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAOvC,OAAO,EAAE,uBAAuB,EAAE,KAAK,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAClG,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1F,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAClG,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAC1H,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAC9F,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,KAAK,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAMtI,OAAO,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AACzG,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAO7C,OAAO,EACL,cAAc,EACd,cAAc,EACd,wBAAwB,EACxB,eAAe,EACf,SAAS,EACT,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,OAAO,GACb,MAAM,gBAAgB,CAAC;AAMxB,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,KAAK,oBAAoB,GAC1B,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EACf,yBAAyB,EACzB,aAAa,EACb,aAAa,EACb,WAAW,EACX,eAAe,EACf,cAAc,EACd,YAAY,EACZ,WAAW,GACZ,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EACV,QAAQ,EACR,iBAAiB,EACjB,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,yBAAyB,EACzB,cAAc,EACd,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -19,27 +19,44 @@
|
|
|
19
19
|
*
|
|
20
20
|
* @packageDocumentation
|
|
21
21
|
*/
|
|
22
|
-
export { AuthProvider } from './AuthProvider';
|
|
23
|
-
export { useAuth } from './useAuth';
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
export
|
|
29
|
-
|
|
30
|
-
export {
|
|
31
|
-
export {
|
|
32
|
-
export {
|
|
33
|
-
export {
|
|
34
|
-
export {
|
|
35
|
-
export {
|
|
36
|
-
export {
|
|
22
|
+
export { AuthProvider } from './AuthProvider.js';
|
|
23
|
+
export { useAuth } from './useAuth.js';
|
|
24
|
+
// objectui#5619 — replaces `useIsWorkspaceAdmin(): boolean`, which had no way
|
|
25
|
+
// to say "not resolved yet" and so answered "not an admin" about an
|
|
26
|
+
// administrator whose adminship lives only in the active member row. The old
|
|
27
|
+
// name is REMOVED rather than kept alongside: a caller that misses the third
|
|
28
|
+
// state is the whole defect, and a deleted export makes that a compile error
|
|
29
|
+
// instead of a silent access-denied screen.
|
|
30
|
+
export { useWorkspaceAdminStatus } from './useWorkspaceAdminStatus.js';
|
|
31
|
+
export { AuthGuard } from './AuthGuard.js';
|
|
32
|
+
export { AuthShell } from './AuthShell.js';
|
|
33
|
+
export { LoginForm } from './LoginForm.js';
|
|
34
|
+
export { RegisterForm } from './RegisterForm.js';
|
|
35
|
+
export { ForgotPasswordForm } from './ForgotPasswordForm.js';
|
|
36
|
+
export { SocialSignInButtons } from './SocialSignInButtons.js';
|
|
37
|
+
export { UserMenu } from './UserMenu.js';
|
|
38
|
+
export { PreviewBanner } from './PreviewBanner.js';
|
|
39
|
+
export { createAuthClient, TokenStorage } from './createAuthClient.js';
|
|
40
|
+
export { normalizePhoneIdentifier, looksLikePhoneIdentifier } from './phone-identifier.js';
|
|
41
|
+
export { createAuthenticatedFetch, ActiveOrganizationStorage } from './createAuthenticatedFetch.js';
|
|
42
|
+
// objectui#10193 — "the browser changed hands in this page-load". The purge on a
|
|
43
|
+
// change of session user clears storage; state already derived from it in
|
|
44
|
+
// memory (the UI language, first of all) is re-derived by whoever owns it, and
|
|
45
|
+
// these two are how that owner finds out — including one that mounts after the
|
|
46
|
+
// purge fired.
|
|
47
|
+
export { getSessionOwnerChangeCount, subscribeSessionOwnerChange } from './ActiveOrganizationStorage.js';
|
|
48
|
+
export { getUserInitials } from './types.js';
|
|
37
49
|
// Organization membership-role vocabulary — a CLOSED, framework-owned list of
|
|
38
50
|
// four (framework ADR-0108), re-exported from `@objectstack/spec`'s
|
|
39
51
|
// `BUILTIN_MEMBERSHIP_ROLES` so it cannot drift — plus the labels and
|
|
40
52
|
// narrowing helpers every org screen shares, which stay console-owned
|
|
41
53
|
// (see `org-roles.ts` for the boundary).
|
|
42
|
-
export { ORG_ROLE_OWNER, ORG_ROLE_ADMIN, ORG_ROLE_DELEGATED_ADMIN, ORG_ROLE_MEMBER, ORG_ROLES, ORG_ROLE_LABELS, orgRoleGrade, invitableOrgRoles, assignableOrgRoles, } from './org-roles';
|
|
54
|
+
export { ORG_ROLE_OWNER, ORG_ROLE_ADMIN, ORG_ROLE_DELEGATED_ADMIN, ORG_ROLE_MEMBER, ORG_ROLES, ORG_ROLE_LABELS, orgRoleGrade, invitableOrgRoles, assignableOrgRoles, } from './org-roles.js';
|
|
55
|
+
// Invitation lifecycle vocabulary — a CLOSED set of four, bound to better-auth's
|
|
56
|
+
// own `InvitationStatus` so it cannot drift, plus the narrowing guard the wire
|
|
57
|
+
// boundary uses. Exported because a screen switching on `AuthInvitation.status`
|
|
58
|
+
// needs the union by name (objectui#3879).
|
|
59
|
+
export { AUTH_INVITATION_STATUSES, isAuthInvitationStatus, } from './invitation-status.js';
|
|
43
60
|
// Shared auth form primitives — exposed so consumers can build custom forms
|
|
44
61
|
// that match the look of LoginForm / RegisterForm / ForgotPasswordForm.
|
|
45
|
-
export { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthAlertIcon, AuthCheckIcon, AuthDivider, AuthErrorBanner, AuthFormHeader, AuthMailIcon, AuthSpinner, } from './authStyles';
|
|
62
|
+
export { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthAlertIcon, AuthCheckIcon, AuthDivider, AuthErrorBanner, AuthFormHeader, AuthMailIcon, AuthSpinner, } from './authStyles.js';
|