@object-ui/auth 17.7.0 → 18.0.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 CHANGED
@@ -1,5 +1,113 @@
1
1
  # @object-ui/auth
2
2
 
3
+ ## 18.0.0
4
+
5
+ ### Dependency floors
6
+
7
+ Computed from `.objectstack-sha` `06cab4849a8a`: the earliest published `@objectstack/spec` that contains it is `18.0.0`.
8
+
9
+ - `@objectstack/spec` (`dependencies`): `^18.0.0-next.1` → `^18.0.0`
10
+
11
+ ### Major Changes
12
+
13
+ - 6f3299f: objectui moves to major 18, following `@objectstack/*` from 17 to 18 (objectui#12334). objectui's major is not a count of its own breaking changes: it tracks the major of the `@objectstack/spec` its packages depend on, so that the same major means compatible across the two projects. These packages already declare `@objectstack/*` on the 18 line (objectui#12030), so every package in the fixed release group crosses to 18 together. It is the one `major` that rule admits: objectui's own breaking changes ship as `minor`, described in their entries.
14
+
15
+ The 18 line is released from Changesets pre mode on the `next` tag (`.changeset/pre.json`), as `@objectstack/*` 18 is: these releases are `18.0.0-next.N` on the npm `next` dist-tag, and they do not move `latest`. The first `18.0.0` on `latest` comes when `@objectstack` 18 is generally available and this repository leaves pre mode.
16
+
17
+ What a consumer must do to take it is in the `@objectstack/*` 18 entry of this release (objectui#12030): move its own `@objectstack/*` packages to the 18 line at the same time.
18
+
19
+ ### Minor Changes
20
+
21
+ - f1a177c: `LoginForm` shows its "Don't have an account? Sign up" row only when the caller passes `registerUrl` (objectui#11634). The prop used to default to `'/register'`, so a caller that passed `undefined` to withhold the link got it back. Both console login pages pass `undefined` when the server's `/auth/config` reports `emailPassword.disableSignUp: true`, so a deployment with sign-up turned off still offered a sign-up link. The server refused the sign-up and `/register` sent the user back to the login page.
22
+
23
+ **Behaviour change.** A `LoginForm` rendered without `registerUrl` no longer shows a sign-up link. A caller that left the prop out and relied on the `'/register'` default now passes the URL itself, `registerUrl="/register"`, to keep the link. The console app's login page and `@object-ui/app-shell`'s `DefaultLoginPage` already pass the URL whenever sign-up is on, so neither changes. Leaving the prop out, or passing `undefined`, is the one way to render no link: no second "off" value is added.
24
+
25
+ **Clause-②: no.** The prop's type is unchanged (`registerUrl?: string`). No export, prop, type member or i18n key is added or removed.
26
+ - daa7caf: The console's login and register pages offer a generic sign-up only where the server would accept one (objectui#11691). `/api/v1/auth/config` states the sign-up rule as two keys, `emailPassword.disableSignUp` and `features.audiencePosture`, and the server deliberately does not force the first from the second: under `invite_only` its sign-up route still admits a pending invitee. The pages read only `disableSignUp`, so under the default `invite_only` posture `/login` offered "Sign up" and `/register` refused the finished form with `SELF_REGISTRATION_CLOSED`.
27
+
28
+ Both pages now read both keys:
29
+
30
+ - `disableSignUp: true` still hides sign-up outright, invitation links included.
31
+ - Under `open` or `email_domain`, nothing changes.
32
+ - Under `invite_only`, `/login` shows no "Sign up" link. A visitor who arrived from an invitation (`?redirect=/accept-invitation/ID`, the signed-out bounce of the invitation page) still gets the link, and `/register` still renders the form for them. A deployment with no owner yet (`GET /api/v1/auth/bootstrap-status` answers `hasOwner: false`) keeps the link for its first owner, because the server admits the first account under every posture.
33
+ - Otherwise `/register` says that self-registration is not open and points back to sign-in, before any field is filled in, instead of refusing the submitted form.
34
+ - A server that sends no `audiencePosture` is answered as before, by `disableSignUp` alone. A posture value the console does not recognise reads as closed.
35
+
36
+ **Clause-②: yes.** `@object-ui/auth`'s published `AuthPublicConfig.features` gains an optional `audiencePosture` member, typed as `@objectstack/spec`'s `AudiencePosture`. The package's `@objectstack/spec` range moves from `^17.0.0` to `^17.3.0`, the first release that declares that type. No export, prop or i18n key is added or removed: the register page's explanation reuses the existing `auth.register.errors.selfRegistrationClosed` sentence.
37
+ - dfa15c8: A new workspace now takes its creator's browser timezone when it is created, so its first administrator is no longer asked for a zone the browser already knows (objectui#11908).
38
+
39
+ `createOrganization` accepts an optional `timezone`, an IANA zone such as `Asia/Shanghai`, on both `AuthClient` and the `useAuth()` context. The client sends it as the `timezone` query parameter of `POST /organization/create`; the request body stays `{ name, slug }` (plus `logo` when given). When the zone is absent or empty, no parameter is sent and the server keeps its default zone. A server that does not read the parameter ignores it.
40
+
41
+ The console's create-workspace dialog and the first-run setup page's create branch both pass the browser's `Intl.DateTimeFormat().resolvedOptions().timeZone`. A browser that reports no zone sends none. Existing workspaces are unchanged, and the one-time timezone prompt still asks about a workspace whose zone is still the default.
42
+ - c5406c2: Depend on the `@objectstack/*` 18 prerelease line (objectui#12030).
43
+
44
+ Every `@objectstack/*` range these packages declare in `dependencies` or `peerDependencies` moves from `^17.x` to `^18.0.0-next.0`, the `next` prerelease of `@objectstack/*` 18 (raised to `^18.0.0-next.1` by objectui#12370 before release).
45
+
46
+ **Breaking for consumers:** an install that resolves `@objectstack/spec` (or `@objectstack/client`, `@objectstack/formula`, `@objectstack/lint`) 17.x no longer satisfies these ranges. A consumer must move its own `@objectstack/*` packages to the 18 line, starting with `18.0.0-next.1` (objectui#12370), at the same time as it takes this release.
47
+
48
+ **objectui's own surface moves with it:**
49
+
50
+ - `element:record_picker`'s registration stops publishing the `object`, `filter`, `sort` and `limit` inputs, which spec 18 retires; a JSX page that writes one now gets `unknown-prop`.
51
+ - The `CapabilityMultiSelectField` widget's curated capability set (`@object-ui/fields`) follows spec 18: `manage_mailboxes` in, `manage_org_presentation` out.
52
+ - `element:number` and `element:repeater` nodes that bind no object are accepted, as spec 18's row and `PageComponentSchema` accept them; the two `ELEMENT_*_OBJECT_REQUIRED` refusals are gone.
53
+
54
+ **Retired with the spec:** `@objectstack/spec` 18 tombstones `object-grid`'s `defaultFilters` and refuses it by name, and `ObjectGrid` and `ObjectView` stop reading it (`table.defaultFilters` on an `object-view` included). A view that still carries it renders unfiltered: rename the key to `filter`, whose value is the same rule array.
55
+ - 37db09f: A user whose administrator forced a password change gets the change-password overlay instead of raw `403` responses (objectui#12365).
56
+
57
+ The ObjectStack backend answers an administrator-forced password change with `403 PASSWORD_RESET_REQUIRED`, its own code distinct from natural expiry `PASSWORD_EXPIRED` (objectstack#23287 ruling C′, carried by objectstack#23440).
58
+
59
+ - **`@object-ui/auth`:** the authenticated fetch wrapper now treats `PASSWORD_RESET_REQUIRED` as an auth-policy gate, like `MFA_REQUIRED` and `PASSWORD_EXPIRED`, so `AuthProvider` sets `remediationRequired` for it. Before the backend emits the code this changes nothing.
60
+ - **`@object-ui/app-shell`:** `RemediationOverlay` routes `PASSWORD_RESET_REQUIRED` to the change-password form. It shows the title "You must change your password" for it, because "Your password has expired" is false for a forced reset. `PASSWORD_EXPIRED` keeps its title.
61
+ - **`@object-ui/i18n`:** adds `auth.remediation.password.resetTitle` to all ten built-in language packs.
62
+
63
+ No export is added or removed, and the type of `remediationRequired` (`{ code: string; message: string }`) is unchanged.
64
+ - ff9df88: Depend on `@objectstack/*` `18.0.0-next.1` (objectui#12370).
65
+
66
+ Every `@objectstack/*` range these packages declare moves from `^18.0.0-next.0` to `^18.0.0-next.1`; the console and the runner bundle `18.0.0-next.1`. A consumer moves its own `@objectstack/*` packages to `18.0.0-next.1` with this release.
67
+
68
+ **Accept sets that narrow with it.** `@object-ui/types` validates page action rows and view data bindings through the spec's own rows, so its faces (`safeValidateSchema` and `StrictAnyComponentSchema`) now refuse what `18.0.0-next.1` refuses. Each was accepted on `18.0.0-next.0`:
69
+
70
+ - `onSuccess` on an `action:button` / `action:icon` row, or an `action:group` / `action:menu` member, whose executor is the `url`, `navigation`, `modal`, `flow` or `form` built-in, or that has no executor at all. Write the hop on an `api` or `script` action (or a host handler name), or drop it.
71
+ - `onSuccess` beside `operation: 'update'`, and an `onSuccess` block carrying a key outside `{ navigate, openIn }`.
72
+ - `actionType: 'navigation'` on a row (and `type: 'navigation'` on a container member): write `'url'`.
73
+ - A `url` executor's `target` that is not openable, judged on the executor the runner runs, including a row whose `name` selects it.
74
+ - A view `data` binding with `provider: 'api'`: bind the object or static rows; an API call is the page element's binding.
75
+ - 8ed7e5a: `LoginForm` gains an optional `hideHeader` prop and a password reveal toggle, and the shared auth form styles take the console login artboard's sizes (objectui#12600).
76
+
77
+ - **`hideHeader`** (default `false`) renders no header — no icon disc, no title, no description — for a host that draws its own. Left unset, the header renders exactly as before. Under SSO-only mode a headless form still shows the SSO-only description, as one line above the federated buttons.
78
+ - **Password reveal toggle.** The password field carries a 28 px show/hide button. Its accessible name comes from two new optional `LoginFormLabels` members, `showPasswordText` and `hidePasswordText` (defaults "Show password" / "Hide password").
79
+ - **Shared styles, every auth form:** `AUTH_INPUT_CLASS` and `AUTH_PRIMARY_BUTTON_CLASS` are 40 px tall (`h-10`, were `h-11`); the primary button is one flat `bg-primary` fill (was a `--primary` gradient); `AUTH_FIELD_LABEL_CLASS` is 13 px. `LoginForm`'s "Sign up" line is 13 px and its enterprise SSO button is 40 px with the inputs' radius.
80
+ - `LoginForm`'s root caps its width at 400 px (`sm:max-w-[400px]`) instead of fixing it there (`sm:w-[400px]`), so it fits a host card narrower than 400 px; wherever it had 400 px or more, nothing changes.
81
+
82
+ **Clause-②: yes.** Added: `LoginFormProps.hideHeader`, `LoginFormLabels.showPasswordText`, `LoginFormLabels.hidePasswordText`, all optional. Nothing is removed or renamed.
83
+ - 9b69e13: `LoginForm` no longer tells an SSO-enforced environment's users to use a password (objectui#12682).
84
+
85
+ - **While the auth config resolves**, the header shows its title and no description. It used to show the password form's description ("Enter your email and password to continue", or the `description` the host passed) because SSO enforcement was not known yet. Once the config answers, the description is what it was: `labels.ssoOnlyDescription` under SSO-only mode, `description` otherwise. A failed config read still falls back to the password form and its description.
86
+ - **Under SSO-only mode** (`features.ssoEnforced`), the provider buttons are no longer followed by an "or continue with email" divider with no email form under it. The divider now renders only while the password form is shown, so it comes back with the form when "Use a password instead" is clicked. A server that does not enforce SSO keeps the divider exactly as before.
87
+ - **`SocialSignInButtons` gains `hideDivider`** (optional, default `false`), which omits the divider under the buttons. Left unset, the component renders exactly as before, so `RegisterForm` and every other caller are unchanged.
88
+
89
+ **Clause-②: yes.** Added: `SocialSignInButtonsProps.hideDivider`, optional. Nothing is removed or renamed.
90
+ - 84b8ffa: The console splash no longer waits for requests the first screen does not need (objectui#12809).
91
+
92
+ - **The organization chain runs in parallel.** When the `get-session` answer carries the organization plugin's `activeOrganizationId`, `AuthProvider` names the active organization from that id and the `organization/list` answer, and asks for the member row (`get-active-member`) at the same time as the list. It no longer asks for `get-full-organization` on boot: nothing the console reads uses the members or invitations that answer adds. An id the list does not carry names no organization, and the stored id is cleared, as before. A session answer without the key (a sign-in response, or a server without the organization plugin) takes the old path. Switching organization, the single-membership repair, sign-in and sign-out are unchanged.
93
+ - **`AuthClientSession.activeOrganizationId`** is a new optional member: the id better-auth's organization plugin puts on the session, or `null` when the session holds none.
94
+ - **The console waits only for the metadata the current route reads.** `AppContent` used to hold the splash until the object, dashboard, report and page lists had all loaded, on every route. It now waits for the lists the current route reads (an object page waits for objects; a dashboard for dashboards and objects). After the first screen, opening a route whose lists have not loaded shows a skeleton where the page will be, inside the console, instead of an empty list or a "not found". A route a host adds through `extraRoutes` still waits for all four lists.
95
+
96
+ ### Patch Changes
97
+
98
+ - d75f212: Published text no longer teaches the retired view-level `provider: 'api'` data source (objectui#12364). A view binds `provider: 'object'` or `provider: 'value'`; a metadata-declared API call is the page element's `dataSource` binding. Text only: no schema accepts or refuses anything new, and no renderer behaves differently.
99
+
100
+ - **`@object-ui/types`:** the `object-tree` `data` description drops the `api` provider from the providers it names.
101
+ - **`@object-ui/plugin-grid` / `@object-ui/plugin-map`:** the `data` input descriptions drop the `api` provider.
102
+ - **`@object-ui/plugin-calendar` / `@object-ui/plugin-gantt` / `@object-ui/plugin-map`:** the error thrown when no `DataSource` is available now reads `DataSource required for the object provider` (was `DataSource required for object/api providers`). It fires in exactly the same conditions as before.
103
+ - **`@object-ui/react` / `@object-ui/auth`:** the README and docblocks describe `SchemaRendererProvider`'s `apiFetch` as what it is now: the host's authenticated fetch the renderers use for their own reads of the host's API (chart metadata, dataset dimension labels, record-permission probes). It is not a channel for a view's data source.
104
+ - **`@object-ui/app-shell`:** comment wording only in `ConsoleShell`, `useConsoleActionRuntime` and `ObjectView` (these comments ship in the built JS): no behaviour change.
105
+ - **`@object-ui/core`:** docblock wording only on `normalizeListViewSchema` and `resolveRecordSourceObjectName` (these ship in `dist/*.d.ts` and the built JS): no behaviour change.
106
+ - 6e141d9: After a reload, the console no longer keeps the previous organization's id once the server says the session has no active organization (objectui#12698). better-auth clears a session's active organization before it refuses a `set-active` to an organization the user is not a member of. On the next boot `AuthProvider` asked the server, heard "none", and left the old id in `ActiveOrganizationStorage`, so `X-Tenant-ID` and the metadata seed cache kept naming that organization. `refreshOrganizations` now clears the stored id whenever the server answers with no active organization, including when the single-membership repair (ADR-0081) is refused. When the repair succeeds, the server is re-stamped and the stored id follows the server's answer, as before. Nothing is added to or removed from the package entry.
107
+
108
+ The console header (`WorkspaceSwitcher`, `CurrentOrganizationIndicator`) now names only the organization the server reports as active, and shows no organization at all when there is none, instead of falling back to the first membership.
109
+ - 5d69b0e: `AuthProvider` no longer asks `get-session` a second time when the console has just validated the stored session before rendering. The validated answer becomes the provider's first state, once per page load; signing in or out, switching organisation and refreshing the session read it from the server as before.
110
+
3
111
  ## 17.7.0
4
112
 
5
113
  ### Minor Changes
package/README.md CHANGED
@@ -144,6 +144,14 @@ is a template whose `{provider}` is replaced with the provider's display name
144
144
  on `RegisterForm`), and `orText` is the divider under the buttons (default
145
145
  "or continue with email").
146
146
 
147
+ The divider introduces the email form, so `LoginForm` draws it only while that
148
+ form is shown: under SSO-only mode (`features.ssoEnforced`) the buttons stand
149
+ alone until "Use a password instead" reveals the form. A host rendering
150
+ `SocialSignInButtons` itself omits the divider with `hideDivider` (default
151
+ `false`). While the auth config is still loading, `LoginForm`'s header shows
152
+ its title and no description, because the description may describe a password
153
+ form the server does not offer.
154
+
147
155
  When the server requires email verification, a registration ends in the user's
148
156
  inbox, and the verification link is the only way back. `verificationCallbackURL`
149
157
  says where that link lands, e.g. the invitation the user signed up from. It is
@@ -184,10 +192,10 @@ import { createAuthenticatedFetch } from '@object-ui/auth';
184
192
 
185
193
  const authedFetch = createAuthenticatedFetch();
186
194
 
187
- // For fetches whose target URL comes from view metadata (`provider: 'api'`
188
- // data sources), restrict credential injection to the current page's origin
189
- // so the platform token never leaks to third-party hosts:
190
- const apiProviderFetch = createAuthenticatedFetch({ sameOriginOnly: true });
195
+ // For fetches whose target URL may come from metadata (an API-call
196
+ // action's target), restrict credential injection to the current page's
197
+ // origin so the platform token never leaks to third-party hosts:
198
+ const sameOriginFetch = createAuthenticatedFetch({ sameOriginOnly: true });
191
199
  ```
192
200
 
193
201
  ### getSessionOwnerChangeCount / subscribeSessionOwnerChange
@@ -371,6 +379,21 @@ gates the "Sign in with SSO" button, `features.phoneNumberOtp` gates the
371
379
  verification-code mode, `features.deviceAuthorization` gates the device-approval page,
372
380
  and so on.
373
381
 
382
+ ### `features.audiencePosture` — read it beside `emailPassword.disableSignUp`
383
+
384
+ `features.audiencePosture` reports which audience posture is in force: `invite_only` (the
385
+ default when the deployment declares none), `email_domain` or `open`. It is a value, not a
386
+ flag, and the server does **not** force `emailPassword.disableSignUp` from it: under
387
+ `invite_only` the sign-up route still admits a pending invitee, and a fresh deployment's
388
+ first owner. So `disableSignUp: false` on its own does not mean a stranger may register.
389
+
390
+ A surface that offers a generic sign-up reads both keys. `disableSignUp: true` hides
391
+ sign-up outright. Otherwise offer it when the posture is `open` or `email_domain`, or when
392
+ the visitor came from an invitation; under `invite_only` say that registration is by
393
+ invitation instead of rendering a form the server will refuse. A server that sends no
394
+ `audiencePosture` predates the key, and `disableSignUp` alone decides there. The
395
+ console's login and register pages are that reader (objectui#11691).
396
+
374
397
  ### Reserved flags — advertised by the server, consumed by nothing
375
398
 
376
399
  Two members of that map are **declared but deliberately not consumed** by this package:
@@ -143,11 +143,16 @@ export interface AuthContextValue {
143
143
  isMembershipResolved: boolean;
144
144
  /** Switch the active organization (workspace) */
145
145
  switchOrganization: (orgId: string) => Promise<void>;
146
- /** Create a new organization */
146
+ /**
147
+ * Create a new organization. `timezone` is the creator's IANA zone, sent as
148
+ * the `timezone` query parameter, never in the body; see
149
+ * `AuthClient.createOrganization` (objectui#11908).
150
+ */
147
151
  createOrganization: (data: {
148
152
  name: string;
149
153
  slug: string;
150
154
  logo?: string;
155
+ timezone?: string;
151
156
  }) => Promise<AuthOrganization>;
152
157
  /**
153
158
  * Refresh the organizations list. Returns the freshly fetched list so
@@ -1 +1 @@
1
- {"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../src/AuthContext.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../src/AuthContext.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AuthProvider.d.ts","sourceRoot":"","sources":["../src/AuthProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAC;AAEjF,OAAO,KAAK,EAAwB,mBAAmB,EAAE,kBAAkB,EAAyG,MAAM,YAAY,CAAC;AA4GvM,MAAM,WAAW,iBAAkB,SAAQ,mBAAmB;IAC5D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,MAAM,EAAE,cAAc,EACtB,iBAAiB,EACjB,OAAc,EACd,WAAW,EACX,QAAQ,GACT,EAAE,iBAAiB,qBA43BnB"}
1
+ {"version":3,"file":"AuthProvider.d.ts","sourceRoot":"","sources":["../src/AuthProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAC;AAEjF,OAAO,KAAK,EAAwB,mBAAmB,EAAE,kBAAkB,EAAyG,MAAM,YAAY,CAAC;AA4GvM,MAAM,WAAW,iBAAkB,SAAQ,mBAAmB;IAC5D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,MAAM,EAAE,cAAc,EACtB,iBAAiB,EACjB,OAAc,EACd,WAAW,EACX,QAAQ,GACT,EAAE,iBAAiB,qBAq9BnB"}
@@ -9,7 +9,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
9
9
  import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
10
10
  import { authGateEvents } from './auth-gate-events.js';
11
11
  import { AuthCtx } from './AuthContext.js';
12
- import { createAuthClient, TokenStorage } from './createAuthClient.js';
12
+ import { createAuthClient, takePreflightSession, TokenStorage } from './createAuthClient.js';
13
13
  import { ActiveOrganizationStorage, SessionUserScope } from './ActiveOrganizationStorage.js';
14
14
  /**
15
15
  * Prefix of every `MetadataProvider` seed entry in `sessionStorage`
@@ -141,9 +141,20 @@ function purgeSignedOutClientCaches() {
141
141
  */
142
142
  export function AuthProvider({ authUrl, client: externalClient, onAuthStateChange, enabled = true, previewMode, children, }) {
143
143
  const client = useMemo(() => externalClient ?? createAuthClient({ baseURL: authUrl }), [externalClient, authUrl]);
144
- const [user, setUser] = useState(null);
145
- const [session, setSession] = useState(null);
146
- const [isLoading, setIsLoading] = useState(true);
144
+ // objectui#12808 — the console's pre-React preflight already asked
145
+ // `get-session` with the stored Bearer. When that answer is still the one we
146
+ // would get, it IS the first state, and the mount below does not ask again.
147
+ // Taken once per page load, in an initializer so it runs once per instance
148
+ // (StrictMode keeps the first call's result). Only for a provider that builds
149
+ // its own client from `authUrl`: an injected client may talk to another server.
150
+ const [bootSession] = useState(() => (enabled && previewMode == null && !externalClient ? takePreflightSession(authUrl) : null));
151
+ const [user, setUser] = useState(() => bootSession?.user ?? null);
152
+ const [session, setSession] = useState(() => bootSession?.session ?? null);
153
+ const [isLoading, setIsLoading] = useState(() => bootSession === null);
154
+ // What the boot answer was taken for. The mount effect skips its load while
155
+ // it still holds (a StrictMode effect replay included); the first run that
156
+ // finds anything else drops it for good, so every later run loads as before.
157
+ const bootSessionFor = useRef(bootSession ? authUrl : null);
147
158
  const [error, setError] = useState(null);
148
159
  const [remediationRequired, setRemediationRequired] = useState(null);
149
160
  // Organization / workspace state
@@ -181,6 +192,16 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
181
192
  // stale, previous-organization data over the newer one (see
182
193
  // `switchOrganization`).
183
194
  const sessionLoadGeneration = useRef(0);
195
+ // objectui#12809 — the member row asked for at the same time as
196
+ // `organization/list`, when the session already names its active
197
+ // organization. `get-active-member` answers for the session's active
198
+ // organization, so it does not have to wait for the list. Held with the org
199
+ // and user it was asked for and taken once, by the first
200
+ // `refreshActiveMember` for that same organization; anything else drops it
201
+ // (a switch, a sign-out, an active organization the list did not confirm).
202
+ // Not a cache: the answer is used for the moment it was asked in, never for
203
+ // a later question.
204
+ const bootMemberRef = useRef(null);
184
205
  /**
185
206
  * The ONE session loader. Runs on mount (below) and on every later
186
207
  * re-resolution — `refreshSession` on the context, and the rotation
@@ -260,6 +281,9 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
260
281
  }, [enabled, isPreviewMode, loadSession]);
261
282
  // Load session on mount (only if auth is enabled and not in preview mode)
262
283
  useEffect(() => {
284
+ if (isPreviewMode || !enabled || externalClient || bootSessionFor.current !== authUrl) {
285
+ bootSessionFor.current = null;
286
+ }
263
287
  if (isPreviewMode) {
264
288
  // Preview mode: simulate a user based on previewMode config
265
289
  const role = previewMode.simulatedRole ?? 'admin';
@@ -303,10 +327,13 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
303
327
  setIsLoading(false);
304
328
  return;
305
329
  }
330
+ // The first state already holds the preflight's answer (see `bootSession`).
331
+ if (bootSessionFor.current !== null)
332
+ return;
306
333
  let cancelled = false;
307
334
  loadSession(() => cancelled);
308
335
  return () => { cancelled = true; };
309
- }, [client, enabled, isPreviewMode, previewMode, loadSession]);
336
+ }, [client, enabled, isPreviewMode, previewMode, loadSession, authUrl, externalClient]);
310
337
  // Notify on auth state changes
311
338
  useEffect(() => {
312
339
  onAuthStateChange?.({
@@ -377,6 +404,7 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
377
404
  // this file: drop the in-memory reference and the stored id together.
378
405
  setOrganizations([]);
379
406
  setActiveOrganization(null);
407
+ bootMemberRef.current = null;
380
408
  }
381
409
  catch (err) {
382
410
  setError(err instanceof Error ? err : new Error(String(err)));
@@ -547,7 +575,17 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
547
575
  }
548
576
  }, [client]);
549
577
  // --- Organization methods ---
550
- const refreshOrganizations = useCallback(async (isCancelled) => {
578
+ /**
579
+ * `sessionActiveOrgId` — objectui#12809. Passed only by the load that follows
580
+ * a `get-session` answer (the effect below), and only when that answer
581
+ * carries the organization plugin's `activeOrganizationId`. The session
582
+ * already names the server's active organization, so it is named from that
583
+ * id and the list answer: no `get-full-organization` round trip, whose extra
584
+ * fields (members, invitations) nothing the console reads. Every other caller
585
+ * (a mutation, `refreshOrganizations()` on the context) asks the server, as
586
+ * before: the session in hand may predate what that mutation changed.
587
+ */
588
+ const refreshOrganizations = useCallback(async (isCancelled, sessionActiveOrgId) => {
551
589
  if (!enabled || isPreviewMode)
552
590
  return;
553
591
  setIsOrganizationsLoading(true);
@@ -559,12 +597,19 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
559
597
  // If no active org is set but orgs exist, try to get active from server
560
598
  if (orgs.length > 0 && !activeOrganization) {
561
599
  let active = null;
562
- try {
563
- active = await client.getActiveOrganization();
600
+ if (sessionActiveOrgId !== undefined) {
601
+ // An id the list does not carry is no membership of this user's: the
602
+ // server's full-organization read refuses it the same way.
603
+ active = (sessionActiveOrgId && orgs.find((o) => o.id === sessionActiveOrgId)) || null;
564
604
  }
565
- catch {
566
- // No active org set — that's fine
567
- active = null;
605
+ else {
606
+ try {
607
+ active = await client.getActiveOrganization();
608
+ }
609
+ catch {
610
+ // No active org set — that's fine
611
+ active = null;
612
+ }
568
613
  }
569
614
  // Single-membership repair (ADR-0081): a session created before the
570
615
  // server-side active-org stamp existed carries no active org even
@@ -579,10 +624,27 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
579
624
  active = null;
580
625
  }
581
626
  }
582
- if (active && !isCancelled?.()) {
627
+ if (isCancelled?.())
628
+ return orgs;
629
+ if (bootMemberRef.current && bootMemberRef.current.orgId !== active?.id) {
630
+ bootMemberRef.current = null;
631
+ }
632
+ if (active) {
583
633
  setActiveOrganization(active);
584
634
  ActiveOrganizationStorage.set(active.id);
585
635
  }
636
+ else if (activeOrgIdRef.current === null) {
637
+ // objectui#12698 — the server answered "no active organization"
638
+ // (and, at one membership, refused the repair above). The stored id
639
+ // is a cache of a SERVER-owned fact, so it goes with that answer:
640
+ // left in place it keeps stamping `X-Tenant-ID` and keying the
641
+ // metadata seed cache for an organization this session does not
642
+ // hold — e.g. the one a refused `set-active` cleared server-side
643
+ // (better-auth nulls the session's active org before it refuses a
644
+ // non-member). The `activeOrgIdRef` guard keeps a user switch that
645
+ // landed while this request was in flight from being wiped.
646
+ ActiveOrganizationStorage.clear();
647
+ }
586
648
  }
587
649
  return orgs;
588
650
  }
@@ -634,8 +696,12 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
634
696
  // A switch re-opens the question: until `getActiveMember()` answers for the
635
697
  // NEW org, `activeMember` still holds the OLD org's row.
636
698
  setActiveMemberResolved(false);
699
+ const boot = bootMemberRef.current;
700
+ bootMemberRef.current = null;
637
701
  try {
638
- const member = await client.getActiveMember();
702
+ const member = boot && boot.orgId === activeOrganization.id
703
+ ? await boot.answer
704
+ : await client.getActiveMember();
639
705
  setActiveMember(member);
640
706
  }
641
707
  catch (err) {
@@ -682,11 +748,27 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
682
748
  refreshActiveMember();
683
749
  }, [refreshActiveMember]);
684
750
  // Load organizations once user is authenticated
751
+ //
752
+ // objectui#12809 — a session answer that carries the organization plugin's
753
+ // `activeOrganizationId` already names the server's active organization, so
754
+ // the member row is asked for now, beside `organization/list`, instead of
755
+ // after the active organization lands. A StrictMode effect replay finds the
756
+ // same question already asked and does not ask again.
685
757
  useEffect(() => {
686
758
  if (!(user && enabled && !isPreviewMode))
687
759
  return;
688
760
  let cancelled = false;
689
- refreshOrganizations(() => cancelled);
761
+ const sessionActiveOrgId = session?.activeOrganizationId;
762
+ if (typeof sessionActiveOrgId === 'string' && !activeOrganization) {
763
+ const asked = bootMemberRef.current;
764
+ if (!asked || asked.orgId !== sessionActiveOrgId || asked.userId !== user.id) {
765
+ const answer = client.getActiveMember();
766
+ // Taken later, or dropped: either way it must not surface as unhandled.
767
+ answer.catch(() => undefined);
768
+ bootMemberRef.current = { orgId: sessionActiveOrgId, userId: user.id, answer };
769
+ }
770
+ }
771
+ refreshOrganizations(() => cancelled, sessionActiveOrgId);
690
772
  return () => { cancelled = true; };
691
773
  }, [user, enabled, isPreviewMode]); // eslint-disable-line react-hooks/exhaustive-deps
692
774
  // objectui#5750 — keep `activeOrgIdRef` current for every path that can
@@ -728,6 +810,7 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
728
810
  const switchOrganization = useCallback(async (orgId) => {
729
811
  setError(null);
730
812
  const previousOrgId = activeOrgIdRef.current;
813
+ bootMemberRef.current = null;
731
814
  sessionLoadInFlight.current = true;
732
815
  try {
733
816
  const org = await client.setActiveOrganization(orgId);
@@ -25,7 +25,8 @@ export interface LoginFormLabels {
25
25
  /**
26
26
  * Divider label between the social provider buttons and the email/password
27
27
  * form (defaults to "or continue with email"). Rendered only when the server
28
- * reports at least one social provider.
28
+ * reports at least one social provider, and only while that form is shown:
29
+ * under SSO-only mode it appears once "Use a password instead" reveals it.
29
30
  */
30
31
  orText?: string;
31
32
  /**
@@ -61,19 +62,32 @@ export interface LoginFormLabels {
61
62
  usePasswordSignInText?: string;
62
63
  /** Description shown above the form in SSO-only mode (defaults to "Sign in with your organization's single sign-on"). */
63
64
  ssoOnlyDescription?: string;
65
+ /** Accessible name of the password field's reveal toggle while the password is hidden (defaults to "Show password"). */
66
+ showPasswordText?: string;
67
+ /** Accessible name of the password field's reveal toggle while the password is shown (defaults to "Hide password"). */
68
+ hidePasswordText?: string;
64
69
  }
65
70
  export interface LoginFormProps {
66
71
  /** Callback on successful login */
67
72
  onSuccess?: () => void;
68
73
  /** Callback on login error */
69
74
  onError?: (error: Error) => void;
70
- /** Link to registration page */
75
+ /**
76
+ * Link to registration page. The "Sign up" link renders only when this is
77
+ * set: there is no default, so leaving it out (or passing `undefined`, as a
78
+ * caller does when the server reports `emailPassword.disableSignUp`) renders
79
+ * no link.
80
+ */
71
81
  registerUrl?: string;
72
82
  /** Link to forgot password page */
73
83
  forgotPasswordUrl?: string;
74
84
  /** Custom title */
75
85
  title?: string;
76
- /** Custom description */
86
+ /**
87
+ * Custom description. Not shown while the server's auth config is still
88
+ * resolving, since it may describe a password form the server does not
89
+ * offer; under SSO-only mode `labels.ssoOnlyDescription` replaces it.
90
+ */
77
91
  description?: string;
78
92
  /** Custom icon shown above the title (defaults to a small lock disc) */
79
93
  icon?: React.ReactNode;
@@ -90,6 +104,14 @@ export interface LoginFormProps {
90
104
  errorMessages?: Record<string, string>;
91
105
  /** Hide the icon disc above the form title. Defaults to false. */
92
106
  hideIcon?: boolean;
107
+ /**
108
+ * Render no header — no icon disc, no title, no description — because the
109
+ * host draws its own above the form. Defaults to false, which renders the
110
+ * header exactly as before. Under SSO-only ("enforced") mode the form still
111
+ * says how to sign in: the SSO-only description, which the header would
112
+ * otherwise carry, renders as one muted line above the federated buttons.
113
+ */
114
+ hideHeader?: boolean;
93
115
  }
94
116
  /**
95
117
  * Login form component with email/password authentication.
@@ -105,5 +127,5 @@ export interface LoginFormProps {
105
127
  * />
106
128
  * ```
107
129
  */
108
- export declare function LoginForm({ onSuccess, onError, registerUrl, forgotPasswordUrl, title, description, icon, hideIcon, linkComponent: LinkComp, labels, errorMessages, }: LoginFormProps): React.JSX.Element;
130
+ export declare function LoginForm({ onSuccess, onError, registerUrl, forgotPasswordUrl, title, description, icon, hideIcon, hideHeader, linkComponent: LinkComp, labels, errorMessages, }: LoginFormProps): React.JSX.Element;
109
131
  //# sourceMappingURL=LoginForm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LoginForm.d.ts","sourceRoot":"","sources":["../src/LoginForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAWzD,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6FAA6F;IAC7F,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8GAA8G;IAC9G,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gGAAgG;IAChG,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,8FAA8F;IAC9F,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iGAAiG;IACjG,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,yHAAyH;IACzH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,gCAAgC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC5D,uCAAuC;IACvC,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,OAAO,EACP,WAAyB,EACzB,iBAAsC,EACtC,KAAiC,EACjC,WAAyD,EACzD,IAAI,EACJ,QAAgB,EAChB,aAAa,EAAE,QAAsB,EACrC,MAAW,EACX,aAAa,GACd,EAAE,cAAc,qBAsbhB"}
1
+ {"version":3,"file":"LoginForm.d.ts","sourceRoot":"","sources":["../src/LoginForm.tsx"],"names":[],"mappings":"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"}
package/dist/LoginForm.js CHANGED
@@ -12,6 +12,8 @@ import { SocialSignInButtons } from './SocialSignInButtons.js';
12
12
  import { looksLikePhoneIdentifier, normalizePhoneIdentifier } from './phone-identifier.js';
13
13
  import { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthErrorBanner, AuthFormHeader, AuthSpinner, } from './authStyles.js';
14
14
  const DefaultLink = ({ href, className, children }) => (_jsx("a", { href: href, className: className, children: children }));
15
+ const EyeIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "h-4 w-4", "aria-hidden": "true", children: [_jsx("path", { d: "M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" }), _jsx("circle", { cx: "12", cy: "12", r: "3" })] }));
16
+ const EyeOffIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "h-4 w-4", "aria-hidden": "true", children: [_jsx("path", { d: "M10.73 5.08A10.4 10.4 0 0 1 12 5c7 0 10 7 10 7a13.2 13.2 0 0 1-1.67 2.68" }), _jsx("path", { d: "M6.61 6.61A13.5 13.5 0 0 0 2 12s3 7 10 7a9.7 9.7 0 0 0 5.39-1.61" }), _jsx("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), _jsx("path", { d: "m2 2 20 20" })] }));
15
17
  const DefaultLockIcon = () => (_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("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2" }), _jsx("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })] }));
16
18
  /**
17
19
  * Login form component with email/password authentication.
@@ -27,10 +29,13 @@ const DefaultLockIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none"
27
29
  * />
28
30
  * ```
29
31
  */
30
- export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgotPasswordUrl = '/forgot-password', title = 'Sign in to your account', description = 'Enter your email and password to continue', icon, hideIcon = false, linkComponent: LinkComp = DefaultLink, labels = {}, errorMessages, }) {
32
+ export function LoginForm({ onSuccess, onError, registerUrl, forgotPasswordUrl = '/forgot-password', title = 'Sign in to your account', description = 'Enter your email and password to continue', icon, hideIcon = false, hideHeader = false, linkComponent: LinkComp = DefaultLink, labels = {}, errorMessages, }) {
31
33
  const { signIn, isLoading, getAuthConfig, sendPhoneOtp, signInWithPhoneOtp, signInWithPhonePassword } = useAuth();
32
34
  const [email, setEmail] = useState('');
33
35
  const [password, setPassword] = useState('');
36
+ // The password field's reveal toggle. Local and ephemeral on purpose: a
37
+ // revealed password must not survive a remount or reach any URL or storage.
38
+ const [passwordVisible, setPasswordVisible] = useState(false);
34
39
  const [error, setError] = useState(null);
35
40
  // Phone-OTP sign-in (framework#2780). Only offered when the server reports
36
41
  // `features.phoneNumberOtp` — i.e. the phoneNumber plugin is on AND a
@@ -129,6 +134,8 @@ export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgo
129
134
  resendOtpCountdownText: labels.resendOtpCountdownText ?? 'Resend in {seconds}s',
130
135
  usePhoneOtpText: labels.usePhoneOtpText ?? 'Sign in with verification code',
131
136
  usePasswordSignInText: labels.usePasswordSignInText ?? 'Sign in with password instead',
137
+ showPasswordText: labels.showPasswordText ?? 'Show password',
138
+ hidePasswordText: labels.hidePasswordText ?? 'Hide password',
132
139
  };
133
140
  // Tick the resend cooldown down once per second while it's armed.
134
141
  useEffect(() => {
@@ -233,10 +240,16 @@ export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgo
233
240
  setSsoSubmitting(false);
234
241
  }
235
242
  };
236
- return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: hideIcon ? undefined : (icon ?? _jsx(DefaultLockIcon, {})), title: title, description: ssoEnforced && !showPasswordFallback ? l.ssoOnlyDescription : description }), _jsx("div", { className: "space-y-5", children: configPending ? (_jsx("div", { className: "flex justify-center py-10", role: "status", "aria-live": "polite", "data-testid": "login-config-loading", children: _jsx(AuthSpinner, {}) })) : (_jsxs(_Fragment, { children: [_jsx(SocialSignInButtons, { mode: "sign-in", dividerText: labels.orText, buttonText: labels.socialButton, onProvidersResolved: (hasProviders) => setHasSocialProviders(hasProviders) }), passwordFormVisible ? (mode === 'phone-otp' ? (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-phone", className: AUTH_FIELD_LABEL_CLASS, children: l.phoneLabel }), _jsx("input", { id: "login-phone", type: "tel", placeholder: l.phonePlaceholder, value: phone, onChange: (e) => setPhone(e.target.value), required: true, autoComplete: "tel", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-otp", className: AUTH_FIELD_LABEL_CLASS, children: l.otpCodeLabel }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { id: "login-otp", type: "text", inputMode: "numeric", placeholder: l.otpCodePlaceholder, value: otpCode, onChange: (e) => setOtpCode(e.target.value), required: true, autoComplete: "one-time-code", disabled: isLoading, className: AUTH_INPUT_CLASS }), _jsxs("button", { type: "button", onClick: handleSendOtp, disabled: otpSending || otpCooldown > 0 || !phone.trim() || isLoading, className: "shrink-0 rounded-md border border-input bg-background px-3 py-2 text-sm font-medium transition-colors hover:bg-accent disabled:opacity-50", children: [otpSending && _jsx(AuthSpinner, {}), otpCooldown > 0
243
+ // The SSO-only view: enforced mode with the break-glass form still closed.
244
+ const ssoOnlyView = ssoEnforced && !showPasswordFallback;
245
+ return (_jsxs("div", { className: `mx-auto flex w-full flex-col justify-center sm:max-w-[400px] ${hideHeader ? 'space-y-4' : 'space-y-7'}`, children: [hideHeader ? (ssoOnlyView ? (_jsx("p", { className: "text-[13px] leading-relaxed text-muted-foreground", children: l.ssoOnlyDescription })) : null) : (_jsx(AuthFormHeader, { icon: hideIcon ? undefined : (icon ?? _jsx(DefaultLockIcon, {})), title: title,
246
+ // No description while the config resolves: `ssoEnforced` is not
247
+ // known yet, and the password form's copy would greet an SSO-only
248
+ // deployment (objectui#12682).
249
+ description: configPending ? undefined : ssoOnlyView ? l.ssoOnlyDescription : description })), _jsx("div", { className: "space-y-5", children: configPending ? (_jsx("div", { className: "flex justify-center py-10", role: "status", "aria-live": "polite", "data-testid": "login-config-loading", children: _jsx(AuthSpinner, {}) })) : (_jsxs(_Fragment, { children: [_jsx(SocialSignInButtons, { mode: "sign-in", dividerText: labels.orText, hideDivider: !passwordFormVisible, buttonText: labels.socialButton, onProvidersResolved: (hasProviders) => setHasSocialProviders(hasProviders) }), passwordFormVisible ? (mode === 'phone-otp' ? (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-phone", className: AUTH_FIELD_LABEL_CLASS, children: l.phoneLabel }), _jsx("input", { id: "login-phone", type: "tel", placeholder: l.phonePlaceholder, value: phone, onChange: (e) => setPhone(e.target.value), required: true, autoComplete: "tel", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-otp", className: AUTH_FIELD_LABEL_CLASS, children: l.otpCodeLabel }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { id: "login-otp", type: "text", inputMode: "numeric", placeholder: l.otpCodePlaceholder, value: otpCode, onChange: (e) => setOtpCode(e.target.value), required: true, autoComplete: "one-time-code", disabled: isLoading, className: AUTH_INPUT_CLASS }), _jsxs("button", { type: "button", onClick: handleSendOtp, disabled: otpSending || otpCooldown > 0 || !phone.trim() || isLoading, className: "shrink-0 rounded-md border border-input bg-background px-3 py-2 text-sm font-medium transition-colors hover:bg-accent disabled:opacity-50", children: [otpSending && _jsx(AuthSpinner, {}), otpCooldown > 0
237
250
  ? l.resendOtpCountdownText.replace('{seconds}', String(otpCooldown))
238
251
  : l.sendOtpButton] })] })] }), _jsxs("button", { type: "submit", disabled: isLoading || !otpSent, className: AUTH_PRIMARY_BUTTON_CLASS, children: [isLoading && _jsx(AuthSpinner, {}), isLoading ? l.submittingButton : l.submitButton] }), _jsx("button", { type: "button", onClick: () => switchMode('password'), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.usePasswordSignInText })] })) : (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-email", className: AUTH_FIELD_LABEL_CLASS, children: phonePasswordEnabled ? l.emailOrPhoneLabel : l.emailLabel }), _jsx("input", { id: "login-email",
239
252
  // `text` (not `email`) when a phone number is also accepted, so the
240
253
  // browser doesn't reject a phone-shaped value on native validation.
241
- type: phonePasswordEnabled ? 'text' : 'email', inputMode: phonePasswordEnabled ? 'text' : 'email', placeholder: phonePasswordEnabled ? l.emailOrPhonePlaceholder : l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "username", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { htmlFor: "login-password", className: AUTH_FIELD_LABEL_CLASS, children: l.passwordLabel }), forgotPasswordUrl && (_jsx(LinkComp, { href: forgotPasswordUrl, className: "text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.forgotPasswordText }))] }), _jsx("input", { id: "login-password", type: "password", placeholder: l.passwordPlaceholder, value: password, onChange: (e) => setPassword(e.target.value), required: true, autoComplete: "current-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] }), ssoEnabled && (_jsxs("button", { type: "button", onClick: handleSso, disabled: isLoading || ssoSubmitting, "aria-busy": ssoSubmitting, className: "flex w-full items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent disabled:opacity-50", children: [ssoSubmitting && _jsx(AuthSpinner, {}), l.ssoButton] })), phoneOtpEnabled && (_jsx("button", { type: "button", onClick: () => switchMode('phone-otp'), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.usePhoneOtpText })), ssoEnforced && showPasswordFallback && (_jsx("button", { type: "button", onClick: () => setShowPasswordFallback(false), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.backToSsoText }))] }))) : (_jsxs("div", { className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsx("button", { type: "button", onClick: () => setShowPasswordFallback(true), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.usePasswordText })] }))] })) }), registerUrl && !ssoEnforced && (_jsxs("p", { className: "px-8 text-center text-sm text-muted-foreground", children: [l.noAccountText, ' ', _jsx(LinkComp, { href: registerUrl, className: AUTH_LINK_CLASS, children: l.signUpText })] }))] }));
254
+ type: phonePasswordEnabled ? 'text' : 'email', inputMode: phonePasswordEnabled ? 'text' : 'email', placeholder: phonePasswordEnabled ? l.emailOrPhonePlaceholder : l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "username", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { htmlFor: "login-password", className: AUTH_FIELD_LABEL_CLASS, children: l.passwordLabel }), forgotPasswordUrl && (_jsx(LinkComp, { href: forgotPasswordUrl, className: "text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.forgotPasswordText }))] }), _jsxs("div", { className: "relative", children: [_jsx("input", { id: "login-password", type: passwordVisible ? 'text' : 'password', placeholder: l.passwordPlaceholder, value: password, onChange: (e) => setPassword(e.target.value), required: true, autoComplete: "current-password", disabled: isLoading, className: `${AUTH_INPUT_CLASS} pr-10` }), _jsx("button", { type: "button", "data-testid": "login-password-toggle", onClick: () => setPasswordVisible((v) => !v), "aria-label": passwordVisible ? l.hidePasswordText : l.showPasswordText, "aria-controls": "login-password", disabled: isLoading, className: "absolute right-1.5 top-1/2 inline-flex h-7 w-7 -translate-y-1/2 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 disabled:pointer-events-none disabled:opacity-50", children: passwordVisible ? _jsx(EyeOffIcon, {}) : _jsx(EyeIcon, {}) })] })] }), _jsxs("button", { type: "submit", disabled: isLoading, className: AUTH_PRIMARY_BUTTON_CLASS, children: [isLoading && _jsx(AuthSpinner, {}), isLoading ? l.submittingButton : l.submitButton] }), ssoEnabled && (_jsxs("button", { type: "button", onClick: handleSso, disabled: isLoading || ssoSubmitting, "aria-busy": ssoSubmitting, className: "flex h-10 w-full items-center justify-center gap-2 rounded-lg border border-input bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent disabled:opacity-50", children: [ssoSubmitting && _jsx(AuthSpinner, {}), l.ssoButton] })), phoneOtpEnabled && (_jsx("button", { type: "button", onClick: () => switchMode('phone-otp'), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.usePhoneOtpText })), ssoEnforced && showPasswordFallback && (_jsx("button", { type: "button", onClick: () => setShowPasswordFallback(false), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.backToSsoText }))] }))) : (_jsxs("div", { className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsx("button", { type: "button", onClick: () => setShowPasswordFallback(true), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.usePasswordText })] }))] })) }), registerUrl && !ssoEnforced && (_jsxs("p", { className: "px-8 text-center text-[13px] text-muted-foreground", children: [l.noAccountText, ' ', _jsx(LinkComp, { href: registerUrl, className: AUTH_LINK_CLASS, children: l.signUpText })] }))] }));
242
255
  }
@@ -15,6 +15,12 @@ export interface SocialSignInButtonsProps {
15
15
  errorCallbackURL?: string;
16
16
  /** Divider text shown between social buttons and the email form (defaults to "or continue with email") */
17
17
  dividerText?: string;
18
+ /**
19
+ * Omit the divider under the buttons. For a host that draws no email form
20
+ * beneath them at that moment, e.g. `LoginForm` under SSO-only mode until
21
+ * the password form is revealed. Defaults to false: the divider renders.
22
+ */
23
+ hideDivider?: boolean;
18
24
  /**
19
25
  * Provider button label, for i18n. `{provider}` is replaced with the
20
26
  * provider's display name, so a translation places the name where its
@@ -32,5 +38,5 @@ export interface SocialSignInButtonsProps {
32
38
  *
33
39
  * Returns `null` while loading or when the server reports no providers.
34
40
  */
35
- export declare function SocialSignInButtons({ mode, callbackURL, errorCallbackURL, dividerText, buttonText, onProvidersResolved, }: SocialSignInButtonsProps): React.JSX.Element | null;
41
+ export declare function SocialSignInButtons({ mode, callbackURL, errorCallbackURL, dividerText, hideDivider, buttonText, onProvidersResolved, }: SocialSignInButtonsProps): React.JSX.Element | null;
36
42
  //# 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,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"}
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;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;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,WAAmB,EACnB,UAAU,EACV,mBAAmB,GACpB,EAAE,wBAAwB,4BA6F1B"}
@@ -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', buttonText, onProvidersResolved, }) {
51
+ export function SocialSignInButtons({ mode = 'sign-in', callbackURL, errorCallbackURL, dividerText = 'or continue with email', hideDivider = false, buttonText, onProvidersResolved, }) {
52
52
  const { getAuthConfig, signInWithProvider } = useAuth();
53
53
  const [providers, setProviders] = useState([]);
54
54
  const [loading, setLoading] = useState(true);
@@ -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 }), 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 }) })] })] }));
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))), hideDivider ? null : (_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
  }
@@ -9,16 +9,18 @@
9
9
  * ADR-0069 — client side of the authentication-policy session gate.
10
10
  *
11
11
  * The ObjectStack backend returns `403 { error: { code: 'MFA_REQUIRED' |
12
- * 'PASSWORD_EXPIRED', message } }` from protected endpoints when a logged-in
13
- * user must remediate. The authenticated fetch wrapper detects this on EVERY
12
+ * 'PASSWORD_EXPIRED' | 'PASSWORD_RESET_REQUIRED', message } }` from protected
13
+ * endpoints when a logged-in user must remediate. `PASSWORD_RESET_REQUIRED` is
14
+ * an administrator-forced password change, distinct on the wire from natural
15
+ * expiry (objectstack#23287 ruling C′). The authenticated fetch wrapper detects this on EVERY
14
16
  * API response and emits it here; `AuthProvider` subscribes and raises a
15
17
  * full-screen remediation overlay. Decoupling via a tiny module-level emitter
16
18
  * keeps the plain fetch wrapper free of React.
17
19
  */
18
20
  /** A triggered auth-policy gate the user must clear before continuing. */
19
21
  export interface AuthGateInfo {
20
- /** Stable machine code, e.g. `MFA_REQUIRED` / `PASSWORD_EXPIRED`. */
21
- code: 'MFA_REQUIRED' | 'PASSWORD_EXPIRED' | string;
22
+ /** Stable machine code: one of the codes `detectAuthGate` recognises. */
23
+ code: 'MFA_REQUIRED' | 'PASSWORD_EXPIRED' | 'PASSWORD_RESET_REQUIRED' | string;
22
24
  /** Human-facing message from the server (may be empty). */
23
25
  message: string;
24
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"auth-gate-events.d.ts","sourceRoot":"","sources":["../src/auth-gate-events.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;GASG;AAEH,0EAA0E;AAC1E,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,IAAI,EAAE,cAAc,GAAG,kBAAkB,GAAG,MAAM,CAAC;IACnD,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,QAAQ,GAAG,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;AAG7C,eAAO,MAAM,cAAc;IACzB,qEAAqE;eAC1D,YAAY,GAAG,IAAI;IAK9B,4CAA4C;wBACxB,QAAQ,GAAG,MAAM,IAAI;CAI1C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAUjF"}
1
+ {"version":3,"file":"auth-gate-events.d.ts","sourceRoot":"","sources":["../src/auth-gate-events.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;GAWG;AAEH,0EAA0E;AAC1E,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,IAAI,EAAE,cAAc,GAAG,kBAAkB,GAAG,yBAAyB,GAAG,MAAM,CAAC;IAC/E,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;CACjB;AAaD,KAAK,QAAQ,GAAG,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;AAG7C,eAAO,MAAM,cAAc;IACzB,qEAAqE;eAC1D,YAAY,GAAG,IAAI;IAK9B,4CAA4C;wBACxB,QAAQ,GAAG,MAAM,IAAI;CAI1C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAUjF"}
@@ -5,6 +5,16 @@
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
+ /**
9
+ * The auth-policy codes the backend raises as a remediation gate. Hand-written:
10
+ * the spec vocabulary (`AuthGateCodeSchema`) is not in the `@objectstack/spec`
11
+ * this package builds against yet; derive from it once it is.
12
+ */
13
+ const AUTH_GATE_CODES = new Set([
14
+ 'MFA_REQUIRED',
15
+ 'PASSWORD_EXPIRED',
16
+ 'PASSWORD_RESET_REQUIRED',
17
+ ]);
8
18
  const listeners = new Set();
9
19
  export const authGateEvents = {
10
20
  /** Broadcast a gate to all subscribers (the active AuthProvider). */
@@ -33,7 +43,7 @@ export function detectAuthGate(status, body) {
33
43
  if (!err || typeof err !== 'object')
34
44
  return null;
35
45
  const code = err.code;
36
- if (code === 'MFA_REQUIRED' || code === 'PASSWORD_EXPIRED') {
46
+ if (typeof code === 'string' && AUTH_GATE_CODES.has(code)) {
37
47
  const message = err.message;
38
48
  return { code, message: typeof message === 'string' ? message : '' };
39
49
  }
@@ -13,10 +13,15 @@ import React from 'react';
13
13
  *
14
14
  * Consumers can override styling per-form by passing their own children
15
15
  * inside an AuthShell, but the defaults aim to look premium out of the box.
16
+ *
17
+ * Sizes follow the console login artboard (objectui#12600): 40 px (`h-10`)
18
+ * fields and primary button, 13 px / 500 labels, one flat `--primary` fill on
19
+ * the button. Radii are the theme's own `rounded-lg`, so a host theme that
20
+ * re-scales `--radius` re-scales these with it.
16
21
  */
17
- export declare const AUTH_INPUT_CLASS = "flex h-11 w-full rounded-lg border border-input bg-background px-3.5 py-2 text-sm shadow-sm ring-offset-background transition-colors placeholder:text-muted-foreground hover:border-primary/40 focus-visible:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50";
18
- export declare const AUTH_PRIMARY_BUTTON_CLASS = "inline-flex h-11 w-full items-center justify-center gap-2 rounded-lg bg-gradient-to-r from-primary to-primary/85 px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm ring-offset-background transition-[box-shadow,background-color,transform] hover:shadow-md hover:from-primary hover:to-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2 active:scale-[0.99] disabled:pointer-events-none disabled:opacity-60 motion-reduce:transition-none motion-reduce:active:transform-none";
19
- export declare const AUTH_FIELD_LABEL_CLASS = "text-sm font-medium leading-none text-foreground";
22
+ export declare const AUTH_INPUT_CLASS = "flex h-10 w-full rounded-lg border border-input bg-background px-3.5 py-2 text-sm shadow-sm ring-offset-background transition-colors placeholder:text-muted-foreground hover:border-primary/40 focus-visible:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50";
23
+ export declare const AUTH_PRIMARY_BUTTON_CLASS = "inline-flex h-10 w-full items-center justify-center gap-2 rounded-lg bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm ring-offset-background transition-[box-shadow,background-color,transform] hover:bg-primary/90 hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2 active:scale-[0.99] disabled:pointer-events-none disabled:opacity-60 motion-reduce:transition-none motion-reduce:active:transform-none";
24
+ export declare const AUTH_FIELD_LABEL_CLASS = "text-[13px] font-medium leading-none text-foreground";
20
25
  export declare const AUTH_LINK_CLASS = "font-medium text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:underline";
21
26
  /** Decorative spinner shown while a submit is pending. */
22
27
  export declare function AuthSpinner(): React.JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"authStyles.d.ts","sourceRoot":"","sources":["../src/authStyles.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,0XAC4V,CAAC;AAE1X,eAAO,MAAM,yBAAyB,oiBAC6f,CAAC;AAEpiB,eAAO,MAAM,sBAAsB,qDAAqD,CAAC;AAEzF,eAAO,MAAM,eAAe,mHACsF,CAAC;AAEnH,0DAA0D;AAC1D,wBAAgB,WAAW,sBAyB1B;AAED,8CAA8C;AAC9C,wBAAgB,aAAa,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,qBAiBlE;AAED,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,qBAgBlE;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,qBAgBjE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,KAAK,EACL,WAAW,GACZ,EAAE;IACD,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC/B,qBAgBA;AAED,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,qBAU/D;AAED,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,EAAE,KAAY,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,qBAW/D"}
1
+ {"version":3,"file":"authStyles.d.ts","sourceRoot":"","sources":["../src/authStyles.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB,0XAC4V,CAAC;AAE1X,eAAO,MAAM,yBAAyB,mfAC4c,CAAC;AAEnf,eAAO,MAAM,sBAAsB,yDAAyD,CAAC;AAE7F,eAAO,MAAM,eAAe,mHACsF,CAAC;AAEnH,0DAA0D;AAC1D,wBAAgB,WAAW,sBAyB1B;AAED,8CAA8C;AAC9C,wBAAgB,aAAa,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,qBAiBlE;AAED,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,qBAgBlE;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,qBAgBjE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,KAAK,EACL,WAAW,GACZ,EAAE;IACD,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC/B,qBAgBA;AAED,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,qBAU/D;AAED,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,EAAE,KAAY,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,qBAW/D"}
@@ -6,10 +6,15 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
6
  *
7
7
  * Consumers can override styling per-form by passing their own children
8
8
  * inside an AuthShell, but the defaults aim to look premium out of the box.
9
+ *
10
+ * Sizes follow the console login artboard (objectui#12600): 40 px (`h-10`)
11
+ * fields and primary button, 13 px / 500 labels, one flat `--primary` fill on
12
+ * the button. Radii are the theme's own `rounded-lg`, so a host theme that
13
+ * re-scales `--radius` re-scales these with it.
9
14
  */
10
- export const AUTH_INPUT_CLASS = 'flex h-11 w-full rounded-lg border border-input bg-background px-3.5 py-2 text-sm shadow-sm ring-offset-background transition-colors placeholder:text-muted-foreground hover:border-primary/40 focus-visible:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50';
11
- export const AUTH_PRIMARY_BUTTON_CLASS = 'inline-flex h-11 w-full items-center justify-center gap-2 rounded-lg bg-gradient-to-r from-primary to-primary/85 px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm ring-offset-background transition-[box-shadow,background-color,transform] hover:shadow-md hover:from-primary hover:to-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2 active:scale-[0.99] disabled:pointer-events-none disabled:opacity-60 motion-reduce:transition-none motion-reduce:active:transform-none';
12
- export const AUTH_FIELD_LABEL_CLASS = 'text-sm font-medium leading-none text-foreground';
15
+ export const AUTH_INPUT_CLASS = 'flex h-10 w-full rounded-lg border border-input bg-background px-3.5 py-2 text-sm shadow-sm ring-offset-background transition-colors placeholder:text-muted-foreground hover:border-primary/40 focus-visible:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50';
16
+ export const AUTH_PRIMARY_BUTTON_CLASS = 'inline-flex h-10 w-full items-center justify-center gap-2 rounded-lg bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm ring-offset-background transition-[box-shadow,background-color,transform] hover:bg-primary/90 hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2 active:scale-[0.99] disabled:pointer-events-none disabled:opacity-60 motion-reduce:transition-none motion-reduce:active:transform-none';
17
+ export const AUTH_FIELD_LABEL_CLASS = 'text-[13px] font-medium leading-none text-foreground';
13
18
  export const AUTH_LINK_CLASS = 'font-medium text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:underline';
14
19
  /** Decorative spinner shown while a submit is pending. */
15
20
  export function AuthSpinner() {
@@ -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.js';
8
+ import type { AuthClient, AuthClientConfig, AuthUser, AuthClientSession } 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).
@@ -38,6 +38,20 @@ export declare const TokenStorage: {
38
38
  */
39
39
  subscribeRotation(listener: () => void): () => void;
40
40
  };
41
+ /**
42
+ * Take the preflight's `get-session` answer, once per page load (objectui#12808).
43
+ *
44
+ * Returns it only when it answers what the caller would ask: the same auth URL,
45
+ * and the Bearer still stored is the one the preflight validated (the server
46
+ * prefers the Bearer, so the cookie the preflight omitted cannot change the
47
+ * answer). Parsed exactly as `getSession()` parses the wire body, with the same
48
+ * token sync. Anything else, or a second call, returns `null` and the caller asks
49
+ * the server as before.
50
+ */
51
+ export declare function takePreflightSession(authUrl: string): {
52
+ user: AuthUser;
53
+ session: AuthClientSession;
54
+ } | null;
41
55
  /**
42
56
  * Create an auth client instance backed by the official better-auth client.
43
57
  *
@@ -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,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"}
1
+ {"version":3,"file":"createAuthClient.d.ts","sourceRoot":"","sources":["../src/createAuthClient.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EACV,UAAU,EAAE,gBAAgB,EAAE,QAAQ,EAAE,iBAAiB,EAE1D,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;AAgKF;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,GACd;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAAG,IAAI,CAgBvD;AA8BD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CAksBrE"}
@@ -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 { createAuthClient as createBetterAuthClient } from 'better-auth/client';
8
+ import { createAuthClient as createBetterAuthClient, parseJSON } from 'better-auth/client';
9
9
  import { organizationClient, twoFactorClient } from 'better-auth/client/plugins';
10
10
  import { AUTH_INVITATION_STATUSES, isAuthInvitationStatus } from './invitation-status.js';
11
11
  const TOKEN_STORAGE_KEY = 'auth-session-token';
@@ -202,6 +202,46 @@ function resolveResetPasswordRedirect() {
202
202
  }
203
203
  return '/reset-password';
204
204
  }
205
+ /**
206
+ * The slot the console's pre-React auth preflight (`apps/console/src/lib/
207
+ * auth-preflight.ts`) leaves its `get-session` answer in when the stored Bearer
208
+ * was valid: the auth URL it asked, the token it sent and the body as JSON text. The
209
+ * preflight runs before any bundle chunk that could import this package, so the
210
+ * slot is spelled by hand on both sides; the console's
211
+ * `sessionBootDedup.test.tsx` runs the preflight against this reader.
212
+ */
213
+ const PREFLIGHT_SESSION_KEY = Symbol.for('objectui.authPreflightSession');
214
+ /**
215
+ * Take the preflight's `get-session` answer, once per page load (objectui#12808).
216
+ *
217
+ * Returns it only when it answers what the caller would ask: the same auth URL,
218
+ * and the Bearer still stored is the one the preflight validated (the server
219
+ * prefers the Bearer, so the cookie the preflight omitted cannot change the
220
+ * answer). Parsed exactly as `getSession()` parses the wire body, with the same
221
+ * token sync. Anything else, or a second call, returns `null` and the caller asks
222
+ * the server as before.
223
+ */
224
+ export function takePreflightSession(authUrl) {
225
+ const holder = globalThis;
226
+ const slot = holder[PREFLIGHT_SESSION_KEY];
227
+ if (!slot || slot.taken)
228
+ return null;
229
+ slot.taken = true;
230
+ if (slot.authUrl !== authUrl || slot.token !== TokenStorage.get())
231
+ return null;
232
+ let payload;
233
+ try {
234
+ payload = parseJSON(slot.body, { strict: false });
235
+ }
236
+ catch {
237
+ return null;
238
+ }
239
+ if (!payload?.user || !payload.session)
240
+ return null;
241
+ if (payload.session.token)
242
+ TokenStorage.set(payload.session.token);
243
+ return { user: payload.user, session: payload.session };
244
+ }
205
245
  /**
206
246
  * Create a fetch wrapper that injects Bearer token from localStorage
207
247
  * and captures updated tokens from the `set-auth-token` response header
@@ -727,10 +767,17 @@ export function createAuthClient(config) {
727
767
  return (data ?? []);
728
768
  },
729
769
  async createOrganization(orgData) {
770
+ // objectui#11908: the creator's zone rides the QUERY (`?timezone=`), the
771
+ // shape the server's create route reads it from; the body stays
772
+ // `{ name, slug, logo }`. better-auth's client proxy lifts
773
+ // `fetchOptions.query` onto the URL and keeps it out of the body. An
774
+ // absent or empty zone sends no parameter at all.
775
+ const { timezone } = orgData;
730
776
  const { data, error } = await betterAuth.organization.create({
731
777
  name: orgData.name,
732
778
  slug: orgData.slug,
733
779
  logo: orgData.logo,
780
+ ...(timezone ? { fetchOptions: { query: { timezone } } } : {}),
734
781
  });
735
782
  if (error)
736
783
  throw toAuthError(error, 'Failed to create organization');
@@ -28,9 +28,10 @@ export interface CreateAuthenticatedFetchOptions {
28
28
  * current page are passed through to the bare global fetch — no
29
29
  * Authorization, X-Tenant-ID, or Accept-Language headers are attached.
30
30
  *
31
- * Use this for fetches whose target URL comes from view metadata
32
- * (`provider: 'api'` data sources): those may point at third-party hosts
33
- * that must never see the platform bearer token.
31
+ * Use this for fetches whose target URL may come from metadata (a
32
+ * `type: 'api'` action's target) or that a host hands to the renderers as
33
+ * `apiFetch`: those may point at third-party hosts that must never see the
34
+ * platform bearer token.
34
35
  */
35
36
  sameOriginOnly?: boolean;
36
37
  }
@@ -1 +1 @@
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"}
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;;;;;;;;;OASG;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"}
@@ -122,7 +122,7 @@ export function createAuthenticatedFetch(options) {
122
122
  //
123
123
  // The console injects the same localStorage bearer from two places: the
124
124
  // AUTH lane (sign-in / get-session / the auth endpoints) and THIS one — the
125
- // adapter, `provider: 'api'` data sources, and every metadata `type: 'api'`
125
+ // adapter, the renderers' `apiFetch`, and every metadata `type: 'api'`
126
126
  // action (`useConsoleActionRuntime`'s `apiHandler`). better-auth's
127
127
  // server-side bearer plugin hands a rotated session token back in
128
128
  // `set-auth-token` on whichever lane the call arrived over. Only the auth
package/dist/types.d.ts CHANGED
@@ -8,6 +8,7 @@
8
8
  import type React from 'react';
9
9
  import type { AuthUser as SpecAuthUser, DelegableScope, DelegableAdminScope } from '@objectstack/spec/contracts';
10
10
  import type { TenancyPosture } from '@objectstack/spec/security';
11
+ import type { AudiencePosture } from '@objectstack/spec/system';
11
12
  import type { AuthInvitationStatus } from './invitation-status.js';
12
13
  /**
13
14
  * Authentication types for @object-ui/auth
@@ -96,6 +97,17 @@ export interface AuthClientSession {
96
97
  * session, which is why the banner costs a normal session nothing.
97
98
  */
98
99
  impersonatedBy?: string;
100
+ /**
101
+ * objectui#12809 — set by better-auth's organization plugin on the
102
+ * `GET /auth/get-session` answer: the id of the organization this session is
103
+ * active in, or `null` when it holds none. `AuthProvider` names the active
104
+ * organization from it and the `organization/list` answer, and asks for the
105
+ * member row at the same time. Absent when the answer did not come from
106
+ * `get-session` (a sign-in response) or the server has no organization
107
+ * plugin; the provider then asks the server for the active organization, as
108
+ * before.
109
+ */
110
+ activeOrganizationId?: string | null;
99
111
  }
100
112
  /** Authentication state */
101
113
  export interface AuthState {
@@ -258,6 +270,23 @@ export interface AuthPublicConfig {
258
270
  * Absent (older server / config not yet fetched) ⇒ no group affordances.
259
271
  */
260
272
  tenancyPosture?: TenancyPosture;
273
+ /**
274
+ * Which audience posture is in force — the deployment's declared answer
275
+ * to "who may self-register here" (`invite_only`, the undeclared default;
276
+ * `email_domain`; `open`). A value, not a flag: the spec lists it in
277
+ * `PUBLIC_AUTH_CONFIG_NON_FLAG_KEYS` beside `tenancyPosture`.
278
+ *
279
+ * It does NOT replace `emailPassword.disableSignUp`, and the server does
280
+ * not force that flag from it: under `invite_only` the sign-up route still
281
+ * admits a pending invitee (and a fresh deployment's first owner), so the
282
+ * two keys together read "sign-up is open to invitees only". A surface
283
+ * that offers a generic sign-up therefore reads both — the console's
284
+ * login and register pages and `@object-ui/app-shell`'s exported default
285
+ * ones do, through app-shell's `decideSignUpOffer` (objectui#11691,
286
+ * objectui#11705). Absent (older server / config not yet fetched) ⇒
287
+ * `disableSignUp` alone decides, as it did before the key existed.
288
+ */
289
+ audiencePosture?: AudiencePosture;
261
290
  };
262
291
  }
263
292
  /** Options when initiating a third-party sign-in */
@@ -343,11 +372,20 @@ export interface AuthClient {
343
372
  signInWithProvider: (providerId: string, options?: SignInWithProviderOptions) => Promise<void>;
344
373
  /** List organizations the current user belongs to */
345
374
  listOrganizations: () => Promise<AuthOrganization[]>;
346
- /** Create a new organization */
375
+ /**
376
+ * Create a new organization.
377
+ *
378
+ * `timezone` (objectui#11908) is the creator's IANA zone, for example the
379
+ * browser's `Intl.DateTimeFormat().resolvedOptions().timeZone`. It travels
380
+ * as the `timezone` QUERY parameter of `POST /organization/create`, never in
381
+ * the body, which stays `{ name, slug, logo }`. Omitted or empty, nothing is
382
+ * sent and the server keeps its default zone; the server judges the value.
383
+ */
347
384
  createOrganization: (data: {
348
385
  name: string;
349
386
  slug: string;
350
387
  logo?: string;
388
+ timezone?: string;
351
389
  }) => Promise<AuthOrganization>;
352
390
  /** Set the active organization for the current session */
353
391
  setActiveOrganization: (orgId: string) => Promise<AuthOrganization | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/auth",
3
- "version": "17.7.0",
3
+ "version": "18.0.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Authentication system for Object UI with AuthProvider, useAuth hook, AuthGuard, and form components.",
@@ -30,7 +30,7 @@
30
30
  "react": "^18.0.0 || ^19.0.0"
31
31
  },
32
32
  "dependencies": {
33
- "@objectstack/spec": "^17.0.0",
33
+ "@objectstack/spec": "^18.0.0",
34
34
  "better-auth": "^1.7.2"
35
35
  },
36
36
  "devDependencies": {