@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.
Files changed (52) hide show
  1. package/CHANGELOG.md +600 -0
  2. package/README.md +245 -15
  3. package/dist/ActiveOrganizationStorage.d.ts +199 -0
  4. package/dist/ActiveOrganizationStorage.d.ts.map +1 -0
  5. package/dist/ActiveOrganizationStorage.js +584 -0
  6. package/dist/AuthContext.d.ts +23 -3
  7. package/dist/AuthContext.d.ts.map +1 -1
  8. package/dist/AuthGuard.d.ts +8 -1
  9. package/dist/AuthGuard.d.ts.map +1 -1
  10. package/dist/AuthGuard.js +16 -3
  11. package/dist/AuthProvider.d.ts +1 -1
  12. package/dist/AuthProvider.d.ts.map +1 -1
  13. package/dist/AuthProvider.js +274 -9
  14. package/dist/ForgotPasswordForm.d.ts +1 -1
  15. package/dist/ForgotPasswordForm.d.ts.map +1 -1
  16. package/dist/ForgotPasswordForm.js +5 -5
  17. package/dist/LoginForm.d.ts +11 -2
  18. package/dist/LoginForm.d.ts.map +1 -1
  19. package/dist/LoginForm.js +5 -6
  20. package/dist/PreviewBanner.js +1 -1
  21. package/dist/RegisterForm.d.ts +22 -3
  22. package/dist/RegisterForm.d.ts.map +1 -1
  23. package/dist/RegisterForm.js +6 -7
  24. package/dist/SocialSignInButtons.d.ts +9 -2
  25. package/dist/SocialSignInButtons.d.ts.map +1 -1
  26. package/dist/SocialSignInButtons.js +5 -5
  27. package/dist/UserMenu.d.ts +1 -1
  28. package/dist/UserMenu.js +3 -3
  29. package/dist/createAuthClient.d.ts +1 -1
  30. package/dist/createAuthClient.d.ts.map +1 -1
  31. package/dist/createAuthClient.js +42 -4
  32. package/dist/createAuthenticatedFetch.d.ts +9 -9
  33. package/dist/createAuthenticatedFetch.d.ts.map +1 -1
  34. package/dist/createAuthenticatedFetch.js +50 -38
  35. package/dist/index.d.ts +21 -19
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +34 -17
  38. package/dist/invitation-status.d.ts +59 -0
  39. package/dist/invitation-status.d.ts.map +1 -0
  40. package/dist/invitation-status.js +32 -0
  41. package/dist/types.d.ts +25 -5
  42. package/dist/types.d.ts.map +1 -1
  43. package/dist/useAuth.d.ts +1 -1
  44. package/dist/useAuth.d.ts.map +1 -1
  45. package/dist/useAuth.js +5 -1
  46. package/dist/useWorkspaceAdminStatus.d.ts +134 -0
  47. package/dist/useWorkspaceAdminStatus.d.ts.map +1 -0
  48. package/dist/useWorkspaceAdminStatus.js +208 -0
  49. package/package.json +6 -7
  50. package/dist/useIsWorkspaceAdmin.d.ts +0 -21
  51. package/dist/useIsWorkspaceAdmin.d.ts.map +0 -1
  52. package/dist/useIsWorkspaceAdmin.js +0 -47
@@ -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
- /** Divider label between social sign-up and email/password (defaults to "or") */
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,SAAS,CAAC;AAWtD,+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,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;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,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,OAAO,EACP,QAAmB,EACnB,KAA2B,EAC3B,WAAqD,EACrD,IAAI,EACJ,QAAgB,EAChB,aAAa,EAAE,QAAsB,EACrC,MAAW,EACX,aAAa,GACd,EAAE,iBAAiB,qBAuKnB"}
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"}
@@ -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,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,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,mBAAmB,GACpB,EAAE,wBAAwB,4BAyF1B"}
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 label = mode === 'sign-in' ? 'Continue with' : 'Sign up with';
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 }), label, " ", 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 }) })] })] }));
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
  }
@@ -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 (e.g., AppSidebar).
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 (e.g., AppSidebar).
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,SAAS,CAAC;AAIjB;;;;;;;;;;;;;;;;;;;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;AAwIF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CAqrBrE"}
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"}
@@ -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
- * Get/set the active organization ID for tenant-scoped API requests.
19
- * Used by createAuthenticatedFetch to inject X-Tenant-ID header.
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 declare const ActiveOrganizationStorage: {
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;AAKH;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAID;;;GAGG;AACH,eAAO,MAAM,yBAAyB;kBACd,MAAM,GAAG,IAAI;WAE5B,MAAM,GAAG,IAAI;eAST,MAAM,GAAG,IAAI;aASf,IAAI;CAQd,CAAC;AAEF,MAAM,WAAW,+BAA+B;IAC9C;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAYD;;;;;;;;;;;;;;;;;GAiBG;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,CA2ErE"}
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
- const ACTIVE_ORG_STORAGE_KEY = 'auth-active-organization-id';
8
+ import { TokenStorage } from './createAuthClient.js';
9
+ import { authGateEvents, detectAuthGate } from './auth-gate-events.js';
10
+ import { ActiveOrganizationStorage } from './ActiveOrganizationStorage.js';
11
11
  /**
12
- * Get/set the active organization ID for tenant-scoped API requests.
13
- * Used by createAuthenticatedFetch to inject X-Tenant-ID header.
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 const ActiveOrganizationStorage = {
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
- // Inject tenant header for multi-tenant routing
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 { useIsWorkspaceAdmin } from './useIsWorkspaceAdmin';
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 { getUserInitials } from './types';
37
- 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';
38
- export { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthAlertIcon, AuthCheckIcon, AuthDivider, AuthErrorBanner, AuthFormHeader, AuthMailIcon, AuthSpinner, } from './authStyles';
39
- export type { AuthUser, AuthClientSession, AuthState, AuthClient, AuthClientConfig, AuthLinkComponentProps, AuthProviderOptions, PreviewModeOptions, SignInCredentials, SignUpData, AuthOrganization, AuthOrganizationMember, AuthInvitation, AuthSocialProvider, AuthPublicConfig, SignInWithProviderOptions, TenancyPosture, DelegableScope, } from './types';
40
- export type { AuthContextValue } from './AuthContext';
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
@@ -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,gBAAgB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACvH,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,KAAK,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACnI,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAO1C,OAAO,EACL,cAAc,EACd,cAAc,EACd,wBAAwB,EACxB,eAAe,EACf,SAAS,EACT,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,OAAO,GACb,MAAM,aAAa,CAAC;AAIrB,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,cAAc,CAAC;AAGtB,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,SAAS,CAAC;AAEjB,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
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
- export { useIsWorkspaceAdmin } from './useIsWorkspaceAdmin';
25
- export { AuthGuard } from './AuthGuard';
26
- export { AuthShell } from './AuthShell';
27
- export { LoginForm } from './LoginForm';
28
- export { RegisterForm } from './RegisterForm';
29
- export { ForgotPasswordForm } from './ForgotPasswordForm';
30
- export { SocialSignInButtons } from './SocialSignInButtons';
31
- export { UserMenu } from './UserMenu';
32
- export { PreviewBanner } from './PreviewBanner';
33
- export { createAuthClient, TokenStorage } from './createAuthClient';
34
- export { normalizePhoneIdentifier, looksLikePhoneIdentifier } from './phone-identifier';
35
- export { createAuthenticatedFetch, ActiveOrganizationStorage } from './createAuthenticatedFetch';
36
- export { getUserInitials } from './types';
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';