Pyric
Navigate

API reference

@pyric/ui/auth

51 published symbols from @pyric/ui

Generated from the TypeScript declarations shipped at this import path.

Classes

AuthFlowController

Constructors

Constructor
new AuthFlowController(auth: Auth): AuthFlowController;
Parameters
ParameterType
authAuth
Returns

AuthFlowController

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
ParameterType
specNewIdentitySpec
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
ParameterType
uidstring
Returns

void

resolver()
resolver(): AuthFlowResolver;

The resolver to hand to sandbox.setAuthFlowResolver. Popup and redirect share one implementation (the sandbox has no navigation).

Returns

AuthFlowResolver

snapshot()
snapshot(): HelperState;
Returns

HelperState

subscribe()
subscribe(fn: () => void): () => void;
Parameters
ParameterType
fn() => void
Returns
(): void;
Returns

void

uninstall()
uninstall(): void;
Returns

void

Interfaces

AuthProviderConfigEntry

One provider’s current enablement, as the hook exposes it.

Properties

PropertyType
enabledboolean
providerIdstring

AuthProviderTogglesProps

Properties

PropertyTypeDescription
className?string-
configAuthProviderConfigEntry[]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) => voidFired when a toggle (known or custom) flips.

AuthSignInHelperProps

Properties

PropertyTypeDescription
className?string-
description?ReactNodeOptional 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) => voidCreate + sign in as a new identity (wire to the hook’s add).
onCancel() => voidDismiss the flow (wire to the hook’s cancel). Rejects the app’s sign-in promise with auth/popup-closed-by-user.
onPick(uid: string) => voidSettle 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; }) => ReactNodeOptional 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.
stateHelperStateSnapshot from useAuthFlowHelper. Renders nothing while state.request is null.
title?ReactNodeHeading text. Default: Sign in with <provider label>.

AuthUserEditorErrors

Properties

PropertyType
claims?string
email?string
password?string

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

PropertyType
claimsTextstring
disabledboolean
displayNamestring
emailstring
emailVerifiedboolean
passwordstring
phoneNumberstring
photoUrlstring
providerIdsstring[]

AuthUserEditorState

Properties

PropertyTypeDescription
fieldsAuthUserEditorFields-
initialAuthUserEditorFieldsWhat reset returns to; dirtiness is measured against this.

AuthUserFormField

What the AuthUserFormProps.renderField slot receives per field.

Properties

PropertyTypeDescription
defaultRender() => ReactNodeThe default rendering (label wrapper + label text + input + error). Call it to keep the stock layout for fields you don’t customize.
errorstringCurrent validation message for this field, or null.
inputReactNodeThe wired, controlled input element (carries data-pyric-field). Place it anywhere; state/validation stay connected.
kind"text" | "checkbox" | "group"`‘text'
labelstringThe visible label text the default rendering uses.
nameAuthUserFormFieldName-

AuthUserFormProps

Properties

PropertyTypeDescription
cancelLabel?string-
children?ReactNodeExtra content rendered before the action row (e.g. an error from a failed createUser call).
className?string-
initial?AuthUserRecordExisting record → edit mode (delta payloads); omit → create mode.
onCancel?() => void-
onSubmit(submit: AuthUserFormSubmit) => voidReceives the validated payload. Wire create to useAuthUsers().createUser and edit to updateUser.
renderField?(field: AuthUserFormField) => ReactNodePer-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

PropertyTypeDescription
className?string-
emptyState?ReactNodeZero state when the project has no users at all.
error?Error-
filter?stringThe active filter text. Distinguishes the “no users yet” zero state (empty filter) from “no results” (non-empty).
formatCreatedAt?(iso: string) => ReactNodeTimestamp formatter for Created. Default: locale date, em dash for null.
formatLastLoginAt?(iso: string) => ReactNodeTimestamp formatter for Signed In. Kept separate because a missing login means “never”, while a missing/invalid creation time is malformed data.
isLoading?boolean-
noResultsState?ReactNodeZero state when the filter matches nothing.
onSelect?(user: AuthUserRecord) => voidFired when the identifier cell is clicked. When omitted, the identifier renders as plain text.
renderActions?(user: AuthUserRecord) => ReactNodePer-row action slot (edit / disable / delete menu). Rendered in a trailing cell; column header is added when this is provided.
renderActionsHeader?ReactNodeOptional content for the trailing actions column header (for example, a select-all checkbox). Only rendered with renderActions.
renderIdentifier?(user: AuthUserRecord) => ReactNodeIdentifier-cell override. Default: email, else phone, else anonymous, else the uid.
renderProviders?(user: AuthUserRecord) => ReactNodeProviders-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) => ReactNodePer-row selection control. Rendered in the leading cell so bulk selection stays visually separate from trailing row actions.
renderSelectionHeader?ReactNodeOptional content for the leading selection column header (for example, a select-all checkbox). Only rendered with renderSelection.
rowHeight?number | (index: number) => numberEstimated row height when virtualizing. Default 44.
usersAuthUserRecord[]Rows to render — usually useAuthUsers().users.
virtualizedHeight?string | numberScroll-container height when virtualized. Default '60vh'.
virtualizeThreshold?numberAbove this row count, rows render through <VirtualList>. Default 100. Infinity disables.

ClaimsFieldProps

Properties

PropertyTypeDescription
className?string-
error?stringValidation message (from validateSerializedClaims / useAuthUserEditor().errors.claims). Renders a role="alert" paragraph and marks the textarea invalid.
hint?ReactNodeHelper text under the field (rules-usage hint by default).
onChange(text: string) => void-
placeholder?string-
valuestringRaw claims JSON text.

ClearUsersWithConfirmProps

Properties

PropertyTypeDescription
body?ReactNode-
className?string-
confirmLabel?string-
count?numberCurrent user count, interpolated into the default body.
onClear() => voidRuns after the user confirms. Wire to useAuthUsers().clearUsers.
renderTrigger?(props: TriggerProps) => ReactNode-
title?string-

DeleteUserWithConfirmProps

Properties

PropertyTypeDescription
body?ReactNode-
className?string-
confirmLabel?string-
onDelete(uid: string) => voidRuns after the user confirms. Wire to useAuthUsers().deleteUser.
renderTrigger?(props: TriggerProps) => ReactNodeTrigger override; default is a plain destructive <button>.
title?string-
userAuthUserRecord-

HelperState

Snapshot the helper UI renders from.

Properties

PropertyTypeDescription
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).
requestAuthFlowRequestThe 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

PropertyTypeDescription
customClaims?Record<string, unknown>Parsed custom claims (the emulator’s customAttributes).
displayName?string-
emailstring-

UseAuthFlowHelperResult

Properties

PropertyTypeDescription
add(spec: NewIdentitySpec) => voidCreate + sign in as a new identity (seeds it for next time).
cancel() => voidDismiss — rejects the app’s sign-in promise with auth/popup-closed-by-user (faithful to firebase/auth).
pick(uid: string) => voidSettle the flow with an existing identity (by uid).
stateHelperStateRender snapshot: the in-flight request (or null) + pickable identities.

UseAuthProviderConfigResult

Properties

PropertyTypeDescription
configAuthProviderConfigEntry[]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.
errorError-
isEnabled(providerId: string) => booleanConvenience lookup: true for a provider that’s never been toggled.
isLoadingboolean-
refresh() => voidRe-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) => voidToggle 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

PropertyTypeDescription
initial?AuthUserRecordExisting record to edit. Omit for create mode.

UseAuthUserEditorResult

Properties

PropertyTypeDescription
dispatch(action: AuthUserEditorAction) => voidRaw reducer access for advanced consumers.
errorsAuthUserEditorErrorsPer-field validation messages (emulator-UI wording). Empty when valid.
fieldsAuthUserEditorFields-
isDirtyboolean-
isValidboolean-
reset() => voidBack to the initial snapshot.
setField<K>(field: K, value: AuthUserEditorFields[K]) => void-
toCreateRequest() => CreateUserRequestFull payload for createUser (every non-empty field).
toUpdateRequest() => UpdateUserRequestDelta payload for updateUser (only changed fields).

UseAuthUsersResult

Properties

PropertyTypeDescription
clearUsers() => void-
createUser(request: CreateUserRequest) => AuthUserRecord-
deleteUser(uid: string) => void-
errorError-
filterstringCase-insensitive substring match over uid, email, display name and phone number (the emulator UI’s search semantics).
isLoadingboolean-
refresh() => voidRe-list manually. Rarely needed, every mutation (including ones made by the agent or the running app) already triggers subscribeUsers.
setFilter(filter: string) => void-
totalCountnumberUnfiltered count: lets a list distinguish “no users at all” from “no results for this filter”.
updateUser(uid: string, update: UpdateUserRequest) => AuthUserRecord-
usersAuthUserRecord[]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

ParameterType
__namedParameters{ children: ReactNode; value: AuthApi; }
__namedParameters.childrenReactNode
__namedParameters.valueAuthApi

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

ParameterType
__namedParametersAuthProviderTogglesProps

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

ParameterType
__namedParametersAuthSignInHelperProps

Returns

Element


authUserEditorReducer()

function authUserEditorReducer(state: AuthUserEditorState, action: AuthUserEditorAction): AuthUserEditorState;

Parameters

Returns

AuthUserEditorState


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"] with data-pyric-mode, data-pyric-is-dirty, data-pyric-is-valid state attrs
  • every field (text inputs AND checkboxes) is wrapped in a label[data-pyric-field-label="<name>"] carrying a visible span[data-pyric-label-text] — labeled grid layouts are pure CSS (display: grid on 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_IDS from pyric/auth; multiple selectable, entries land on CreateUserRequest.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

ParameterType
__namedParametersAuthUserFormProps

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

ParameterType
__namedParametersAuthUserListProps

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

ParameterType
__namedParametersClaimsFieldProps

Returns

Element


ClearUsersWithConfirm()

function ClearUsersWithConfirm(__namedParameters: ClearUsersWithConfirmProps): Element;

Confirm-gated clear-all (the emulator UI’s “Clear all data”). Requires a <ConfirmProvider> ancestor.

Parameters

ParameterType
__namedParametersClearUsersWithConfirmProps

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

ParameterType
__namedParametersDeleteUserWithConfirmProps

Returns

Element


fieldsFromRecord()

function fieldsFromRecord(record?: AuthUserRecord): AuthUserEditorFields;

Parameters

ParameterType
record?AuthUserRecord

Returns

AuthUserEditorFields


initAuthUserEditorState()

function initAuthUserEditorState(initial?: AuthUserRecord): AuthUserEditorState;

Parameters

ParameterType
initial?AuthUserRecord

Returns

AuthUserEditorState


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

ParameterType
providerIdstring

Returns

string


toCreateRequest()

function toCreateRequest(state: AuthUserEditorState): CreateUserRequest;

Full payload for sandbox.createUser — every non-empty field.

Parameters

ParameterType
stateAuthUserEditorState

Returns

CreateUserRequest


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

ParameterType
stateAuthUserEditorState

Returns

UpdateUserRequest


useAuthApi()

function useAuthApi(): AuthApi;

Read the active auth API bundle (defaults to in-process pyric/auth).

Returns

AuthApi


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

ParameterType
authAuth

Returns

UseAuthFlowHelperResult


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

ParameterType
authAuth

Returns

UseAuthProviderConfigResult


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 useAuthUserscreateUser / updateUser.

Parameters

ParameterType
options?UseAuthUserEditorOptions

Returns

UseAuthUserEditorResult


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

ParameterType
authAuth

Returns

UseAuthUsersResult


validateAuthUserFields()

function validateAuthUserFields(fields: AuthUserEditorFields): AuthUserEditorErrors;

Parameters

ParameterType
fieldsAuthUserEditorFields

Returns

AuthUserEditorErrors


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

ParameterType
textstring

Returns

ClaimsValidationResult