Classes
AuthFlowController
Constructors
Constructor
new AuthFlowController(auth: Auth): AuthFlowController;
Parameters
| Parameter | Type |
|---|---|
auth | Auth |
Returns
Methods
add()
add(spec: NewIdentitySpec): void;
Add + sign in as a new identity. The backend creates the identity (so claims resolve in rules and it shows up in the picker next time) and mints the credential in one step.
Credential creation happens BEFORE take’s emit: subscribers
recompute the snapshot synchronously on emit, so creating after would
publish a stale identity list (a useSyncExternalStore consumer
would miss the new account until the next unrelated emit).
Parameters
| Parameter | Type |
|---|---|
spec | NewIdentitySpec |
Returns
void
cancel()
cancel(): void;
Dismiss — rejects with the faithful auth/popup-closed-by-user.
Returns
void
install()
install(): void;
Wire this controller’s resolver into the auth handle. Paired with uninstall for use in a React effect (install in the body, uninstall in the cleanup) — StrictMode-safe.
Returns
void
pick()
pick(uid: string): void;
Pick an existing identity (by uid). The backend mints the credential (and records the provider on the identity).
Parameters
| Parameter | Type |
|---|---|
uid | string |
Returns
void
resolver()
resolver(): AuthFlowResolver;
The resolver to hand to sandbox.setAuthFlowResolver. Popup and
redirect share one implementation (the sandbox has no navigation).
Returns
snapshot()
snapshot(): HelperState;
Returns
subscribe()
subscribe(fn: () => void): () => void;
Parameters
| Parameter | Type |
|---|---|
fn | () => void |
Returns
(): void;
Returns
void
uninstall()
uninstall(): void;
Returns
void
Interfaces
AuthProviderConfigEntry
One provider’s current enablement, as the hook exposes it.
Properties
AuthProviderTogglesProps
Properties
| Property | Type | Description |
|---|---|---|
className? | string | - |
config | AuthProviderConfigEntry[] | Current config — usually useAuthProviderConfig(auth).config. |
error? | Error | - |
isLoading? | boolean | - |
knownProviderIds? | readonly string[] | Always-shown rows, in this order. Default: DEFAULT_KNOWN_PROVIDER_IDS. |
onToggle | (providerId: string, enabled: boolean) => void | Fired when a toggle (known or custom) flips. |
AuthSignInHelperProps
Properties
| Property | Type | Description |
|---|---|---|
className? | string | - |
description? | ReactNode | Optional helper text rendered under the title ([data-pyric-helper-description]). Default: none. |
initialValues? | { claims?: string; displayName?: string; email?: string; } | Prefill for the add-account form (e.g. a host-suggested email). Read once on mount; claims is the raw textarea JSON text. |
initialValues.claims? | string | - |
initialValues.displayName? | string | - |
initialValues.email? | string | - |
onAdd | (spec: NewIdentitySpec) => void | Create + sign in as a new identity (wire to the hook’s add). |
onCancel | () => void | Dismiss the flow (wire to the hook’s cancel). Rejects the app’s sign-in promise with auth/popup-closed-by-user. |
onPick | (uid: string) => void | Settle with an existing identity (wire to the hook’s pick). |
renderAccount? | (identity: { customClaims: Record<string, unknown>; displayName: string; email: string; isAnonymous: boolean; providerId: string; providerUserInfo: ProviderUserInfo[]; uid: string; }) => ReactNode | Optional renderer for an account row’s content. Default renders the display name (or email, or uid) plus the email when both exist. The row button + data attributes stay owned by the component; this slot only fills the button’s children. |
state | HelperState | Snapshot from useAuthFlowHelper. Renders nothing while state.request is null. |
title? | ReactNode | Heading text. Default: Sign in with <provider label>. |
AuthUserEditorErrors
Properties
AuthUserEditorFields
Editable field set. claimsText is the raw textarea JSON.
providerIds are the linked FEDERATED providers (google.com,
apple.com, …) — password is credential-derived (the password
field) and never appears here.
Properties
| Property | Type |
|---|---|
claimsText | string |
disabled | boolean |
displayName | string |
email | string |
emailVerified | boolean |
password | string |
phoneNumber | string |
photoUrl | string |
providerIds | string[] |
AuthUserEditorState
Properties
| Property | Type | Description |
|---|---|---|
fields | AuthUserEditorFields | - |
initial | AuthUserEditorFields | What reset returns to; dirtiness is measured against this. |
AuthUserFormField
What the AuthUserFormProps.renderField slot receives per field.
Properties
| Property | Type | Description |
|---|---|---|
defaultRender | () => ReactNode | The default rendering (label wrapper + label text + input + error). Call it to keep the stock layout for fields you don’t customize. |
error | string | Current validation message for this field, or null. |
input | ReactNode | The wired, controlled input element (carries data-pyric-field). Place it anywhere; state/validation stay connected. |
kind | "text" | "checkbox" | "group" | `‘text' |
label | string | The visible label text the default rendering uses. |
name | AuthUserFormFieldName | - |
AuthUserFormProps
Properties
| Property | Type | Description |
|---|---|---|
cancelLabel? | string | - |
children? | ReactNode | Extra content rendered before the action row (e.g. an error from a failed createUser call). |
className? | string | - |
initial? | AuthUserRecord | Existing record → edit mode (delta payloads); omit → create mode. |
onCancel? | () => void | - |
onSubmit | (submit: AuthUserFormSubmit) => void | Receives the validated payload. Wire create to useAuthUsers().createUser and edit to updateUser. |
renderField? | (field: AuthUserFormField) => ReactNode | Per-field layout override. Called for each field (see AuthUserFormFieldName order); return your own markup around field.input, or field.defaultRender() to keep the stock label wrapper for that field. Omit the prop for the default layout. |
submitLabel? | string | - |
AuthUserListProps
Properties
| Property | Type | Description |
|---|---|---|
className? | string | - |
emptyState? | ReactNode | Zero state when the project has no users at all. |
error? | Error | - |
filter? | string | The active filter text. Distinguishes the “no users yet” zero state (empty filter) from “no results” (non-empty). |
formatCreatedAt? | (iso: string) => ReactNode | Timestamp formatter for Created. Default: locale date, em dash for null. |
formatLastLoginAt? | (iso: string) => ReactNode | Timestamp formatter for Signed In. Kept separate because a missing login means “never”, while a missing/invalid creation time is malformed data. |
isLoading? | boolean | - |
noResultsState? | ReactNode | Zero state when the filter matches nothing. |
onSelect? | (user: AuthUserRecord) => void | Fired when the identifier cell is clicked. When omitted, the identifier renders as plain text. |
renderActions? | (user: AuthUserRecord) => ReactNode | Per-row action slot (edit / disable / delete menu). Rendered in a trailing cell; column header is added when this is provided. |
renderActionsHeader? | ReactNode | Optional content for the trailing actions column header (for example, a select-all checkbox). Only rendered with renderActions. |
renderIdentifier? | (user: AuthUserRecord) => ReactNode | Identifier-cell override. Default: email, else phone, else anonymous, else the uid. |
renderProviders? | (user: AuthUserRecord) => ReactNode | Providers-cell override. Default: one <span data-pyric-provider-id> per linked provider with its text label (anonymous for anonymous users) — hook icons off the attribute. |
renderSelection? | (user: AuthUserRecord) => ReactNode | Per-row selection control. Rendered in the leading cell so bulk selection stays visually separate from trailing row actions. |
renderSelectionHeader? | ReactNode | Optional content for the leading selection column header (for example, a select-all checkbox). Only rendered with renderSelection. |
rowHeight? | number | (index: number) => number | Estimated row height when virtualizing. Default 44. |
users | AuthUserRecord[] | Rows to render — usually useAuthUsers().users. |
virtualizedHeight? | string | number | Scroll-container height when virtualized. Default '60vh'. |
virtualizeThreshold? | number | Above this row count, rows render through <VirtualList>. Default 100. Infinity disables. |
ClaimsFieldProps
Properties
ClearUsersWithConfirmProps
Properties
DeleteUserWithConfirmProps
Properties
| Property | Type | Description |
|---|---|---|
body? | ReactNode | - |
className? | string | - |
confirmLabel? | string | - |
onDelete | (uid: string) => void | Runs after the user confirms. Wire to useAuthUsers().deleteUser. |
renderTrigger? | (props: TriggerProps) => ReactNode | Trigger override; default is a plain destructive <button>. |
title? | string | - |
user | AuthUserRecord | - |
HelperState
Snapshot the helper UI renders from.
Properties
| Property | Type | Description |
|---|---|---|
identities | { customClaims: Record<string, unknown>; displayName: string; email: string; isAnonymous: boolean; providerId: string; providerUserInfo: ProviderUserInfo[]; uid: string; }[] | Existing identities to pick from (seeded + previously created). |
request | AuthFlowRequest | The in-flight request, or null when the helper is closed. |
NewIdentitySpec
A field set for “add new account” — mirrors the emulator’s add-user form.
Properties
| Property | Type | Description |
|---|---|---|
customClaims? | Record<string, unknown> | Parsed custom claims (the emulator’s customAttributes). |
displayName? | string | - |
email | string | - |
UseAuthFlowHelperResult
Properties
| Property | Type | Description |
|---|---|---|
add | (spec: NewIdentitySpec) => void | Create + sign in as a new identity (seeds it for next time). |
cancel | () => void | Dismiss — rejects the app’s sign-in promise with auth/popup-closed-by-user (faithful to firebase/auth). |
pick | (uid: string) => void | Settle the flow with an existing identity (by uid). |
state | HelperState | Render snapshot: the in-flight request (or null) + pickable identities. |
UseAuthProviderConfigResult
Properties
| Property | Type | Description |
|---|---|---|
config | AuthProviderConfigEntry[] | Every provider this sandbox has an explicit enablement for. Unknown providers (never toggled) are simply absent — isEnabled treats an absent entry as enabled, matching the backend default. |
error | Error | - |
isEnabled | (providerId: string) => boolean | Convenience lookup: true for a provider that’s never been toggled. |
isLoading | boolean | - |
refresh | () => void | Re-read manually. Rarely needed — every mutation (this hook’s own setEnabled, another handle, the agent) already triggers the subscription re-list. |
setEnabled | (providerId: string, enabled: boolean) => void | Toggle a provider on/off. Sync (in-process) failures throw to the caller, same policy as useAuthUsers’s mutation callbacks; an ASYNC (worker-RPC) failure can’t reach a sync caller, so it surfaces on the hook’s error state instead — never an unhandled rejection. |
UseAuthUserEditorOptions
Properties
| Property | Type | Description |
|---|---|---|
initial? | AuthUserRecord | Existing record to edit. Omit for create mode. |
UseAuthUserEditorResult
Properties
| Property | Type | Description |
|---|---|---|
dispatch | (action: AuthUserEditorAction) => void | Raw reducer access for advanced consumers. |
errors | AuthUserEditorErrors | Per-field validation messages (emulator-UI wording). Empty when valid. |
fields | AuthUserEditorFields | - |
isDirty | boolean | - |
isValid | boolean | - |
reset | () => void | Back to the initial snapshot. |
setField | <K>(field: K, value: AuthUserEditorFields[K]) => void | - |
toCreateRequest | () => CreateUserRequest | Full payload for createUser (every non-empty field). |
toUpdateRequest | () => UpdateUserRequest | Delta payload for updateUser (only changed fields). |
UseAuthUsersResult
Properties
| Property | Type | Description |
|---|---|---|
clearUsers | () => void | - |
createUser | (request: CreateUserRequest) => AuthUserRecord | - |
deleteUser | (uid: string) => void | - |
error | Error | - |
filter | string | Case-insensitive substring match over uid, email, display name and phone number (the emulator UI’s search semantics). |
isLoading | boolean | - |
refresh | () => void | Re-list manually. Rarely needed, every mutation (including ones made by the agent or the running app) already triggers subscribeUsers. |
setFilter | (filter: string) => void | - |
totalCount | number | Unfiltered count: lets a list distinguish “no users at all” from “no results for this filter”. |
updateUser | (uid: string, update: UpdateUserRequest) => AuthUserRecord | - |
users | AuthUserRecord[] | Users matching filter (everyone when the filter is empty). |
Type Aliases
AuthApi
type AuthApi = Pick<typeof sandbox,
| "listUsers"
| "subscribeUsers"
| "createUser"
| "updateUser"
| "deleteUser"
| "clearUsers"
| "getAuthProviderConfig"
| "setAuthProviderConfig"
| "subscribeAuthProviderConfig">;
The sandbox auth admin ops useAuthUsers drives, as an INJECTABLE bundle.
WHY (same rationale as @pyric/ui/firestore’s FirestoreApi): the hook defaults
to the in-process pyric/auth sandbox ops, but Pyric Studio’s served mode
drives the SAME ops over a SharedWorker (a parallel client over a MessagePort).
Reading them from this context lets a consumer inject the worker client’s fns
so the hook operates on the live worker user DB without knowing the backend.
The bundle is typed to the in-process signatures; a worker bundle is adapted
(cast) at the Studio boundary. NOTE the worker listUsers is ASYNC (an RPC)
whereas the in-process one is sync, so useAuthUsers tolerates a promise (it
wraps the result in Promise.resolve).
Default = the real pyric/auth sandbox ops, so every existing consumer is
unchanged: no provider needed unless swapping the backend.
AuthUserEditorAction
type AuthUserEditorAction =
| {
field: keyof AuthUserEditorFields;
type: "setField";
value: AuthUserEditorFields[keyof AuthUserEditorFields];
}
| {
type: "reset";
};
AuthUserFormFieldName
type AuthUserFormFieldName =
| "email"
| "password"
| "display-name"
| "phone-number"
| "photo-url"
| "providers"
| "email-verified"
| "disabled";
Field names the AuthUserFormProps.renderField slot receives,
in render order. Claims is NOT a slot field — it stays the standalone
<ClaimsField> (override it by composing useAuthUserEditor).
AuthUserFormSubmit
type AuthUserFormSubmit =
| {
mode: "create";
request: CreateUserRequest;
}
| {
mode: "edit";
request: UpdateUserRequest;
uid: string;
};
What onSubmit receives — discriminated on the form’s mode.
ClaimsValidationResult
type ClaimsValidationResult =
| {
claims: Record<string, unknown> | undefined;
ok: true;
}
| {
message: string;
ok: false;
};
Type Declaration
{
claims: Record<string, unknown> | undefined;
ok: true;
}
claims
claims: Record<string, unknown> | undefined;
ok
ok: true;
claims is undefined when the input was empty/whitespace.
{
message: string;
ok: false;
}
message
message: string;
ok
ok: false;
SandboxIdentity
type SandboxIdentity = ReturnType<typeof listIdentities>[number];
One pickable identity, as reported by sandbox.listIdentities.
Variables
CUSTOM_CLAIMS_MAX_LENGTH
const CUSTOM_CLAIMS_MAX_LENGTH: 1000 = 1000;
Serialized-length cap, matching the emulator’s CUSTOM_ATTRIBUTES_MAX_LENGTH.
DEFAULT_KNOWN_PROVIDER_IDS
const DEFAULT_KNOWN_PROVIDER_IDS: readonly ["password", "anonymous", "google.com", "github.com", "apple.com", "microsoft.com"];
Providers always shown as a toggle row, regardless of whether the backend has an explicit entry for them yet (an unconfigured provider simply reads as disabled — same default the sandbox backend applies).
FORBIDDEN_CUSTOM_CLAIMS
const FORBIDDEN_CUSTOM_CLAIMS: readonly string[];
Reserved JWT/OIDC keys the Auth emulator rejects as custom claims. https://firebase.google.com/docs/auth/admin/create-custom-tokens
PROVIDER_LABELS
const PROVIDER_LABELS: Record<string, string>;
Provider-id → human label mapping, mirroring the provider set the
Firebase emulator UI recognizes (it maps the same ids to icons; a
headless library maps them to text and leaves icons to the consumer
via data-pyric-provider-id).
Functions
AuthApiProvider()
function AuthApiProvider(__namedParameters: {
children: ReactNode;
value: AuthApi;
}): FunctionComponentElement<ProviderProps<AuthApi>>;
Provide an auth API bundle to the subtree. Pyric Studio supplies the
in-process bundle for dev-seed review and the SharedWorker client bundle under
pyric dev --ui.
Parameters
| Parameter | Type |
|---|---|
__namedParameters | { children: ReactNode; value: AuthApi; } |
__namedParameters.children | ReactNode |
__namedParameters.value | AuthApi |
Returns
FunctionComponentElement<ProviderProps<AuthApi>>
AuthProviderToggles()
function AuthProviderToggles(__namedParameters: AuthProviderTogglesProps): Element;
Headless “Sign-in providers” toggle grid — the Authentication → Sign-in
method surface. Known providers (password / anonymous / the built-in OAuth
set) always render as a row; any OTHER provider already present in
config (a custom OAuth id a host previously added) also gets a row. A
free-text field lets a consumer enable an arbitrary OAuth provider id not
in the known set — this is a SECTION, not a dialog: the add row lives
inline, no modal.
Fully headless: styling hangs off data-pyric-*, matching the rest of
@pyric/ui/auth (AuthUserList, AuthUserForm, …). Data + mutation come
from useAuthProviderConfig; this component only renders + fires events.
Parameters
| Parameter | Type |
|---|---|
__namedParameters | AuthProviderTogglesProps |
Returns
Element
AuthSignInHelper()
function AuthSignInHelper(__namedParameters: AuthSignInHelperProps): Element;
Headless emulator-style sign-in helper: an account picker over the sandbox’s known identities plus an add-account form (email, display name, custom-claims JSON with emulator-grade validation messages).
Ships zero styling. Structure is addressable via the
data-pyric-* contract:
- root:
[data-pyric-ui="auth-signin-helper"],[data-pyric-provider-id],[data-pyric-auth-type] - picker:
[data-pyric-account-list]>[data-pyric-account-entry]button[data-pyric-account-pick] - form:
form[data-pyric-add-account-form], fields[data-pyric-field="email" | "display-name" | "claims"],[data-pyric-claims-error](role=alert),button[data-pyric-cancel],button[data-pyric-submit]
Positioning is the consumer’s job — render it inside your own modal
or panel (the flow is host-UI-agnostic; only onCancel carries the
popup-closed semantics).
Parameters
| Parameter | Type |
|---|---|
__namedParameters | AuthSignInHelperProps |
Returns
Element
authUserEditorReducer()
function authUserEditorReducer(state: AuthUserEditorState, action: AuthUserEditorAction): AuthUserEditorState;
Parameters
| Parameter | Type |
|---|---|
state | AuthUserEditorState |
action | AuthUserEditorAction |
Returns
AuthUserForm()
function AuthUserForm(__namedParameters: AuthUserFormProps): Element;
Headless add/edit-user form over useAuthUserEditor — the emulator
UI’s user dialog fields (email, password, display name, phone, photo
URL, verified/disabled toggles, custom claims) with its validation
messages. Zero CSS; structure addressable via data-pyric-*:
- root
form[data-pyric-ui="auth-user-form"]withdata-pyric-mode,data-pyric-is-dirty,data-pyric-is-validstate attrs - every field (text inputs AND checkboxes) is wrapped in a
label[data-pyric-field-label="<name>"]carrying a visiblespan[data-pyric-label-text]— labeled grid layouts are pure CSS (display: gridon the wrappers); label-less designs hide[data-pyric-label-text]and lean on the placeholders - inputs
[data-pyric-field="email" | "password" | "display-name" | "phone-number" | "photo-url" | "email-verified" | "disabled"] - CREATE mode only: a “Sign-in providers” group
(
fieldset[data-pyric-field-label="providers"]wrapping[data-pyric-provider-checklist]) — one checkbox per federated provider the sandbox supports (FEDERATED_PROVIDER_IDSfrompyric/auth; multiple selectable, entries land onCreateUserRequest.providerUserInfo) - claims via the standalone
<ClaimsField> - per-field messages
[data-pyric-field-error="email" | "password"]render INSIDE the field’s label wrapper, after the input button[data-pyric-cancel]/button[data-pyric-submit](submit is disabled while invalid, or pristine in edit mode)
Submit emits payloads only — no sandbox calls — so the same form works for create and edit and the consumer owns error handling.
Parameters
| Parameter | Type |
|---|---|
__namedParameters | AuthUserFormProps |
Returns
Element
AuthUserList()
function AuthUserList(__namedParameters: AuthUserListProps): Element;
Headless users table — the emulator UI’s columns (Identifier,
Provider, Created, Signed In, User UID, actions) over the
data-pyric-* styling contract, with role-based table semantics so
rows can virtualize (a real <table> can’t wrap a scroll container).
The hook (useAuthUsers) owns data + filter state; this component
just renders. Disabled accounts carry data-pyric-user-disabled for
dimmed styling.
Parameters
| Parameter | Type |
|---|---|
__namedParameters | AuthUserListProps |
Returns
Element
ClaimsField()
function ClaimsField(__namedParameters: ClaimsFieldProps): Element;
Headless custom-claims textarea — the emulator UI’s
customAttributes control. Standalone so custom forms can reuse the
exact field (the playground’s sign-in helper and the user form both
render one); validation itself lives in validateSerializedClaims.
Parameters
| Parameter | Type |
|---|---|
__namedParameters | ClaimsFieldProps |
Returns
Element
ClearUsersWithConfirm()
function ClearUsersWithConfirm(__namedParameters: ClearUsersWithConfirmProps): Element;
Confirm-gated clear-all (the emulator UI’s “Clear all data”).
Requires a <ConfirmProvider> ancestor.
Parameters
| Parameter | Type |
|---|---|
__namedParameters | ClearUsersWithConfirmProps |
Returns
Element
DeleteUserWithConfirm()
function DeleteUserWithConfirm(__namedParameters: DeleteUserWithConfirmProps): Element;
Confirm-gated single-user delete (the emulator UI’s row-menu
“Delete user”). Requires a <ConfirmProvider> ancestor.
Parameters
| Parameter | Type |
|---|---|
__namedParameters | DeleteUserWithConfirmProps |
Returns
Element
fieldsFromRecord()
function fieldsFromRecord(record?: AuthUserRecord): AuthUserEditorFields;
Parameters
| Parameter | Type |
|---|---|
record? | AuthUserRecord |
Returns
initAuthUserEditorState()
function initAuthUserEditorState(initial?: AuthUserRecord): AuthUserEditorState;
Parameters
| Parameter | Type |
|---|---|
initial? | AuthUserRecord |
Returns
providerLabel()
function providerLabel(providerId: string): string;
Label for a provider id; falls back to the raw id for custom
OAuthProvider ids the map doesn’t know.
Parameters
| Parameter | Type |
|---|---|
providerId | string |
Returns
string
toCreateRequest()
function toCreateRequest(state: AuthUserEditorState): CreateUserRequest;
Full payload for sandbox.createUser — every non-empty field.
Parameters
| Parameter | Type |
|---|---|
state | AuthUserEditorState |
Returns
toUpdateRequest()
function toUpdateRequest(state: AuthUserEditorState): UpdateUserRequest;
Delta payload for sandbox.updateUser — only fields that changed
from the initial record. A cleared displayName maps to null
(the update API’s clear semantics).
Parameters
| Parameter | Type |
|---|---|
state | AuthUserEditorState |
Returns
useAuthApi()
function useAuthApi(): AuthApi;
Read the active auth API bundle (defaults to in-process pyric/auth).
Returns
useAuthFlowHelper()
function useAuthFlowHelper(auth: Auth): UseAuthFlowHelperResult;
Emulator-style sign-in helper for a sandbox Auth handle.
Installs an AuthFlowController as the handle’s
AuthFlowResolver for the lifetime of the calling component — the
analog of browser getAuth wiring browserPopupRedirectResolver.
While mounted, any signInWithPopup / signInWithRedirect call made
against auth parks on state.request; render an account-picker UI
(e.g. <AuthSignInHelper>) from state and settle with
pick / add / cancel.
Install/uninstall is a paired effect, so the StrictMode double-mount
installs and cleanly uninstalls. Sandbox-only: the controller throws
failed-precondition if auth is prod-backed.
Parameters
| Parameter | Type |
|---|---|
auth | Auth |
Returns
useAuthProviderConfig()
function useAuthProviderConfig(auth: Auth): UseAuthProviderConfigResult;
Live sign-in provider config view over a sandbox Auth handle:
sandbox.getAuthProviderConfig + sandbox.subscribeAuthProviderConfig +
sandbox.setAuthProviderConfig. Mirrors useAuthUsers’s shape exactly
(coarse “something changed, re-list” subscription; sync in-process,
tolerates a promise over the SharedWorker client).
Sandbox-only: throws failed-precondition on a prod-backed handle (the
hook surfaces that via error, same as useAuthUsers).
Parameters
| Parameter | Type |
|---|---|
auth | Auth |
Returns
useAuthUserEditor()
function useAuthUserEditor(options?: UseAuthUserEditorOptions): UseAuthUserEditorResult;
Headless add/edit-user state machine (reducer-based, like
useDocumentEditor): field edits, claims-JSON validation with
emulator-grade messages, dirtiness vs the initial record, and payload
builders for useAuthUsers’ createUser / updateUser.
Parameters
| Parameter | Type |
|---|---|
options? | UseAuthUserEditorOptions |
Returns
useAuthUsers()
function useAuthUsers(auth: Auth): UseAuthUsersResult;
Live user-admin view over a sandbox Auth handle:
sandbox.listUsers + sandbox.subscribeUsers + CRUD actions.
The subscription is coarse (“something changed”): any user-DB mutation (from these actions, the running app’s sign-ups, the agent’s seeding) triggers a re-list, so the view stays live without per-row bookkeeping. Filtering is client-side (the sandbox is in-process; there is no server to push the query to).
Mutation errors (e.g. auth/uid-already-exists) throw to the caller:
handle them at the call site like the firestore hooks’ createDocument.
Sandbox-only: throws failed-precondition on a prod-backed handle (the
hook surfaces that via error).
Parameters
| Parameter | Type |
|---|---|
auth | Auth |
Returns
validateAuthUserFields()
function validateAuthUserFields(fields: AuthUserEditorFields): AuthUserEditorErrors;
Parameters
| Parameter | Type |
|---|---|
fields | AuthUserEditorFields |
Returns
validateSerializedClaims()
function validateSerializedClaims(text: string): ClaimsValidationResult;
Validate the claims textarea’s raw text. Empty input is valid (no claims). Messages match the emulator UI verbatim so users see the same wording in both tools.
Parameters
| Parameter | Type |
|---|---|
text | string |