tempest-react-sdk 0.80.0 → 0.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +35 -4
  2. package/bin/lib/component/generate.test.mjs +13 -1
  3. package/bin/lib/openapi/generate.hostile.test.mjs +13 -1
  4. package/bin/lib/openapi/generate.test.mjs +13 -1
  5. package/dist/auth/create-tempest-auth.cjs +1 -1
  6. package/dist/auth/create-tempest-auth.cjs.map +1 -1
  7. package/dist/auth/create-tempest-auth.js +172 -103
  8. package/dist/auth/create-tempest-auth.js.map +1 -1
  9. package/dist/br/boleto.cjs +1 -1
  10. package/dist/br/boleto.cjs.map +1 -1
  11. package/dist/br/boleto.js +2 -1
  12. package/dist/br/boleto.js.map +1 -1
  13. package/dist/br.d.ts +22 -3
  14. package/dist/components/AuthForm/AuthFieldControl.cjs +2 -0
  15. package/dist/components/AuthForm/AuthFieldControl.cjs.map +1 -0
  16. package/dist/components/AuthForm/AuthFieldControl.js +85 -0
  17. package/dist/components/AuthForm/AuthFieldControl.js.map +1 -0
  18. package/dist/components/AuthForm/AuthForm.cjs +2 -0
  19. package/dist/components/AuthForm/AuthForm.cjs.map +1 -0
  20. package/dist/components/AuthForm/AuthForm.js +83 -0
  21. package/dist/components/AuthForm/AuthForm.js.map +1 -0
  22. package/dist/components/AuthForm/AuthForm.module.cjs +3 -0
  23. package/dist/components/AuthForm/AuthForm.module.cjs.map +1 -0
  24. package/dist/components/AuthForm/AuthForm.module.js +14 -0
  25. package/dist/components/AuthForm/AuthForm.module.js.map +1 -0
  26. package/dist/components/AuthForm/AuthLinks.cjs +2 -0
  27. package/dist/components/AuthForm/AuthLinks.cjs.map +1 -0
  28. package/dist/components/AuthForm/AuthLinks.js +29 -0
  29. package/dist/components/AuthForm/AuthLinks.js.map +1 -0
  30. package/dist/components/AuthForm/ForgotPasswordForm.cjs +2 -0
  31. package/dist/components/AuthForm/ForgotPasswordForm.cjs.map +1 -0
  32. package/dist/components/AuthForm/ForgotPasswordForm.js +32 -0
  33. package/dist/components/AuthForm/ForgotPasswordForm.js.map +1 -0
  34. package/dist/components/AuthForm/LoginForm.cjs +2 -0
  35. package/dist/components/AuthForm/LoginForm.cjs.map +1 -0
  36. package/dist/components/AuthForm/LoginForm.js +39 -0
  37. package/dist/components/AuthForm/LoginForm.js.map +1 -0
  38. package/dist/components/AuthForm/ResetPasswordForm.cjs +2 -0
  39. package/dist/components/AuthForm/ResetPasswordForm.cjs.map +1 -0
  40. package/dist/components/AuthForm/ResetPasswordForm.js +39 -0
  41. package/dist/components/AuthForm/ResetPasswordForm.js.map +1 -0
  42. package/dist/components/AuthForm/SignUpForm.cjs +2 -0
  43. package/dist/components/AuthForm/SignUpForm.cjs.map +1 -0
  44. package/dist/components/AuthForm/SignUpForm.js +32 -0
  45. package/dist/components/AuthForm/SignUpForm.js.map +1 -0
  46. package/dist/components/AuthForm/auth-defaults.cjs +2 -0
  47. package/dist/components/AuthForm/auth-defaults.cjs.map +1 -0
  48. package/dist/components/AuthForm/auth-defaults.js +54 -0
  49. package/dist/components/AuthForm/auth-defaults.js.map +1 -0
  50. package/dist/components/AuthForm/auth-schemas.cjs +2 -0
  51. package/dist/components/AuthForm/auth-schemas.cjs.map +1 -0
  52. package/dist/components/AuthForm/auth-schemas.js +26 -0
  53. package/dist/components/AuthForm/auth-schemas.js.map +1 -0
  54. package/dist/components/AuthPage/AuthPage.cjs +2 -0
  55. package/dist/components/AuthPage/AuthPage.cjs.map +1 -0
  56. package/dist/components/AuthPage/AuthPage.js +91 -0
  57. package/dist/components/AuthPage/AuthPage.js.map +1 -0
  58. package/dist/components/AuthPage/AuthPage.module.cjs +3 -0
  59. package/dist/components/AuthPage/AuthPage.module.cjs.map +1 -0
  60. package/dist/components/AuthPage/AuthPage.module.js +24 -0
  61. package/dist/components/AuthPage/AuthPage.module.js.map +1 -0
  62. package/dist/components/FilterBar/filter-apply.cjs +1 -1
  63. package/dist/components/FilterBar/filter-apply.cjs.map +1 -1
  64. package/dist/components/FilterBar/filter-apply.js +7 -7
  65. package/dist/forms/index.js +7 -7
  66. package/dist/forms/masked-inputs.cjs +1 -1
  67. package/dist/forms/masked-inputs.cjs.map +1 -1
  68. package/dist/forms/masked-inputs.js +15 -15
  69. package/dist/http/api-client.cjs +1 -1
  70. package/dist/http/api-client.cjs.map +1 -1
  71. package/dist/http/api-client.js +103 -100
  72. package/dist/http/api-client.js.map +1 -1
  73. package/dist/http/resumable-upload.cjs +1 -1
  74. package/dist/http/resumable-upload.cjs.map +1 -1
  75. package/dist/http/resumable-upload.js +97 -97
  76. package/dist/http/resumable-upload.js.map +1 -1
  77. package/dist/http/upload-with-progress.cjs +1 -1
  78. package/dist/http/upload-with-progress.cjs.map +1 -1
  79. package/dist/http/upload-with-progress.js +12 -12
  80. package/dist/http/use-describe-api-error.cjs +1 -1
  81. package/dist/http/use-describe-api-error.cjs.map +1 -1
  82. package/dist/http/use-describe-api-error.js +9 -9
  83. package/dist/offline/create-offline-sync.cjs +1 -1
  84. package/dist/offline/create-offline-sync.cjs.map +1 -1
  85. package/dist/offline/create-offline-sync.js +78 -56
  86. package/dist/offline/create-offline-sync.js.map +1 -1
  87. package/dist/styles/AuthForm.css +2 -0
  88. package/dist/styles/AuthPage.css +2 -0
  89. package/dist/styles/component/AuthForm.css +9 -0
  90. package/dist/styles/component/AuthPage.css +29 -0
  91. package/dist/styles/forms.css +36 -0
  92. package/dist/styles/manifest.json +63 -0
  93. package/dist/styles.css +1 -1
  94. package/dist/sw/background-sync.cjs +1 -1
  95. package/dist/sw/background-sync.cjs.map +1 -1
  96. package/dist/sw/background-sync.js +124 -106
  97. package/dist/sw/background-sync.js.map +1 -1
  98. package/dist/sw.d.ts +49 -15
  99. package/dist/tempest-react-sdk.cjs +1 -1
  100. package/dist/tempest-react-sdk.d.ts +603 -18
  101. package/dist/tempest-react-sdk.js +373 -365
  102. package/dist/utils/format.cjs +1 -1
  103. package/dist/utils/format.cjs.map +1 -1
  104. package/dist/utils/format.js +25 -25
  105. package/dist/utils/numbers.cjs +1 -1
  106. package/dist/utils/numbers.cjs.map +1 -1
  107. package/dist/utils/numbers.js +7 -7
  108. package/package.json +1 -1
  109. package/template-pwa/src/sw.ts +10 -6
@@ -15,6 +15,7 @@ import { ComponentType } from 'react';
15
15
  import { CompositionEventHandler } from 'react';
16
16
  import { Control } from 'react-hook-form';
17
17
  import { Controller } from 'react-hook-form';
18
+ import { ControllerFieldState } from 'react-hook-form';
18
19
  import { ControllerRenderProps } from 'react-hook-form';
19
20
  import { createBrowserRouter } from 'react-router';
20
21
  import { createHashRouter } from 'react-router';
@@ -870,7 +871,10 @@ export declare interface ApiClientConfig {
870
871
  * Never logs a body, a header, or the query string — a bearer token in
871
872
  * `Authorization`, a password in a login payload and an `access_token` query
872
873
  * param would all end up in whatever the sink writes to. What is logged is
873
- * the method, the path as the call site wrote it, and the numbers.
874
+ * the method, the path and the numbers. The path is cut at the first `?` or
875
+ * `#`, and an absolute URL loses its `user:password@`, so a query written
876
+ * into the path (`"/files?access_token=…"`) or the signature of a presigned
877
+ * URL stays out just like `params` does.
874
878
  */
875
879
  logger?: ApiClientLogger;
876
880
  /**
@@ -1783,6 +1787,152 @@ export declare interface AudioRecording {
1783
1787
  durationMs: number;
1784
1788
  }
1785
1789
 
1790
+ /**
1791
+ * An e-mail field: trimmed and lower-cased *before* it is validated.
1792
+ *
1793
+ * The order is the point. Validating first rejects `" ana@x.com"` pasted with a
1794
+ * trailing space from a password manager, and a backend that compares e-mails
1795
+ * case-sensitively creates a second account for `Ana@x.com`. An empty value gets
1796
+ * its own sentence instead of "e-mail inválido", which reads like an accusation
1797
+ * on a field the user simply has not reached yet.
1798
+ *
1799
+ * @returns A schema producing the normalized address.
1800
+ */
1801
+ export declare function authEmail(): z.ZodPipe<z.ZodString, z.ZodEmail>;
1802
+
1803
+ /**
1804
+ * One entry of an auth form's `fields` list.
1805
+ *
1806
+ * The form is generated from this list, so the app declares *which* fields and
1807
+ * *how they read* — never the markup, the wiring to react-hook-form or the error
1808
+ * slot.
1809
+ *
1810
+ * @typeParam TName - The schema's keys, so a typo in `name` fails to compile.
1811
+ */
1812
+ export declare interface AuthField<TName extends string = string> {
1813
+ /** Key in the schema and in the submitted values. */
1814
+ name: TName;
1815
+ /** Visible label. Rich content works for `checkbox` (a terms link); keep it text for `pin`. */
1816
+ label: ReactNode;
1817
+ /** Control used to render it. Default `"text"`. */
1818
+ type?: AuthFieldType;
1819
+ /** Placeholder shown while the field is empty. */
1820
+ placeholder?: string;
1821
+ /**
1822
+ * `autocomplete` token. Defaults per type: `email` → `"email"`, `password` →
1823
+ * `"current-password"`, `phone` → `"tel"`. Sign-up and reset presets pass
1824
+ * `"new-password"` so password managers offer to generate one.
1825
+ */
1826
+ autoComplete?: string;
1827
+ /** Help text under the field, replaced by the error when there is one. */
1828
+ helperText?: ReactNode;
1829
+ /** Marks the control as required (visual hint + native attribute). */
1830
+ required?: boolean;
1831
+ /** `password` only: show the strength meter under the field. */
1832
+ showStrength?: boolean;
1833
+ /** `pin` only: number of cells. Default `6`. */
1834
+ length?: number;
1835
+ /** Render the control yourself — for a field none of the types covers. */
1836
+ render?: (props: AuthFieldRenderProps) => ReactNode;
1837
+ }
1838
+
1839
+ /** The field names a schema accepts. */
1840
+ export declare type AuthFieldName<TSchema extends z.ZodTypeAny> = Extract<keyof z.infer<TSchema>, string>;
1841
+
1842
+ /** What a field's `render` receives: the react-hook-form binding plus the field's own config. */
1843
+ export declare interface AuthFieldRenderProps {
1844
+ /** `name`, `value`, `onChange`, `onBlur` and `ref` — spread or wire them into the control. */
1845
+ field: ControllerRenderProps<FieldValues, string>;
1846
+ /** The field's validation state, including the server error mapped onto it. */
1847
+ fieldState: ControllerFieldState;
1848
+ /** The current error message, already resolved from `fieldState`. */
1849
+ error?: string;
1850
+ /** The config entry this field was declared with. */
1851
+ config: AuthField;
1852
+ }
1853
+
1854
+ /**
1855
+ * Which SDK control renders a field.
1856
+ *
1857
+ * `text` and `email` → `Input`, `password` → `PasswordInput`, `phone` / `cpf` /
1858
+ * `cnpj` → the masked inputs, `checkbox` → `Checkbox`, `pin` → `PinInput`. The
1859
+ * list is closed on purpose: these are the controls an auth screen uses, and
1860
+ * anything else goes through `render`.
1861
+ */
1862
+ export declare type AuthFieldType = "text" | "email" | "password" | "phone" | "cpf" | "cnpj" | "checkbox" | "pin";
1863
+
1864
+ /**
1865
+ * A complete auth form generated from a list of field configs and a zod schema.
1866
+ *
1867
+ * Every hand-built login and sign-up screen repeated the same wiring: a
1868
+ * `useZodForm`, one labelled input per field with its error slot, a password eye,
1869
+ * a submit button disabled while the request runs, and a `catch` that copied the
1870
+ * 422's field messages back onto the inputs. The app now declares *which* fields
1871
+ * and *what happens on submit*; the rest is here, built on the SDK's own controls
1872
+ * and its forms layer (`useZodForm` + `FormProvider` + `FormField`).
1873
+ *
1874
+ * Errors thrown by `onSubmit` are shown, never rethrown — a rethrow from a submit
1875
+ * handler is an unhandled rejection with nowhere to go. A `TempestApiError` whose
1876
+ * `fields` name fields of this form marks them; anything else, and any field
1877
+ * message that matched no declared field, goes to an `Alert` above the fields,
1878
+ * worded by `describeApiError`. Pass `onError` to log.
1879
+ *
1880
+ * @example
1881
+ * const schema = z.object({ email: z.email("E-mail inválido") });
1882
+ * <AuthForm
1883
+ * schema={schema}
1884
+ * fields={[{ name: "email", type: "email", label: "E-mail" }]}
1885
+ * submitLabel="Continuar"
1886
+ * onSubmit={async (values) => { await api.post("/auth/magic-link", { body: values }); }}
1887
+ * />
1888
+ */
1889
+ export declare function AuthForm<TSchema extends z.ZodTypeAny>({ schema, fields, onSubmit, submitLabel, defaultValues, beforeSubmit, afterSubmit, social, labels, errorOptions, onError, className, }: AuthFormProps<TSchema>): ReactNode;
1890
+
1891
+ /** Fixed sentences of {@link AuthFormProps}, PT-BR by default. */
1892
+ export declare interface AuthFormLabels {
1893
+ /** Text of the divider drawn above the `social` slot. Default `"ou"`. */
1894
+ divider: string;
1895
+ /**
1896
+ * Fallback sentence of the error alert, when the thrown error carries nothing
1897
+ * better. Default `"Não foi possível concluir agora. Tente de novo."`.
1898
+ */
1899
+ error: string;
1900
+ }
1901
+
1902
+ export declare interface AuthFormProps<TSchema extends z.ZodTypeAny> {
1903
+ /** Zod schema validating the values; its messages are what each field shows. */
1904
+ schema: TSchema;
1905
+ /** The fields, in display order. */
1906
+ fields: readonly AuthField<AuthFieldName<TSchema>>[];
1907
+ /**
1908
+ * Called with the validated values. Throw to fail: a `TempestApiError` whose
1909
+ * `fields` name fields of this form marks those fields; any other error shows
1910
+ * an alert above the form.
1911
+ */
1912
+ onSubmit: (values: z.infer<TSchema>) => Promise<void> | void;
1913
+ /** Submit button content. Default `"Enviar"`. */
1914
+ submitLabel?: ReactNode;
1915
+ /** Initial values. Fields left out start as `""` (`false` for checkboxes). */
1916
+ defaultValues?: Partial<z.input<TSchema>>;
1917
+ /** Content between the fields and the submit button — the "forgot password" link. */
1918
+ beforeSubmit?: ReactNode;
1919
+ /** Content after the submit button — the "no account? sign up" line. */
1920
+ afterSubmit?: ReactNode;
1921
+ /** Social sign-in buttons. Rendered under a divider reading `labels.divider`. */
1922
+ social?: ReactNode;
1923
+ /** Overrides for the fixed sentences. */
1924
+ labels?: Partial<AuthFormLabels>;
1925
+ /** Passed to `describeApiError` to word the alert — map error `codes`, `statuses`. */
1926
+ errorOptions?: DescribeApiErrorOptions;
1927
+ /** Called with every error `onSubmit` threw, after it is shown — for logging. */
1928
+ onError?: (error: unknown) => void;
1929
+ /** Class name for the `<form>`. */
1930
+ className?: string;
1931
+ }
1932
+
1933
+ /** The value object a schema produces, as react-hook-form sees it. */
1934
+ export declare type AuthFormValues<TSchema extends z.ZodTypeAny> = z.infer<TSchema> & FieldValues;
1935
+
1786
1936
  /**
1787
1937
  * Router-agnostic auth gate. The caller decides what to render in either
1788
1938
  * branch — typically `<Outlet />` for protected layouts and `<Navigate />` for
@@ -1807,6 +1957,122 @@ export declare interface AuthGuardProps {
1807
1957
  fallback: ReactNode;
1808
1958
  }
1809
1959
 
1960
+ /**
1961
+ * The layout shell of a sign-in, sign-up or password-recovery screen.
1962
+ *
1963
+ * Every app was hand-building the same page around its form: a colored top with
1964
+ * the logo and a back button over a white sheet with rounded top corners on
1965
+ * mobile, a 50/50 brand panel and form on desktop, a "Bem-vindo!" heading. This
1966
+ * component is that page, so the app passes only the brand and the form.
1967
+ *
1968
+ * The switch between the two layouts is a JavaScript media query, not a CSS
1969
+ * `@media` rule, because the breakpoint is a prop: a CSS media query cannot read a
1970
+ * custom property. `useMediaQuery` evaluates synchronously on the first render, so
1971
+ * a client-rendered page does not flash the wrong layout.
1972
+ *
1973
+ * @example
1974
+ * <AuthPage brand={<img src="/logo.svg" alt="Acme" />} back="/" title="Bem-vindo!">
1975
+ * <LoginForm onSubmit={signIn} links={{ forgotPassword: "/recuperar", signUp: "/cadastro" }} />
1976
+ * </AuthPage>
1977
+ */
1978
+ export declare function AuthPage({ brand, title, subtitle, aside, variant, breakpoint, back, footer, headingLevel, as, children, className, style, ...props }: AuthPageProps): ReactNode;
1979
+
1980
+ /** The brand panel of a `split` page — the colored half on desktop, the colored top on mobile. */
1981
+ export declare interface AuthPageAside {
1982
+ /**
1983
+ * Any CSS `background` value: a color, a token, a gradient, an image.
1984
+ * Defaults to `var(--tempest-primary)`, so a themed app gets its brand color
1985
+ * without passing anything.
1986
+ */
1987
+ background?: string;
1988
+ /**
1989
+ * Text color over that background. Defaults to `var(--tempest-text-on-primary)`,
1990
+ * which is only right while the background is the primary color — set it
1991
+ * together with a custom `background` so the back button and the app name
1992
+ * keep their contrast.
1993
+ */
1994
+ color?: string;
1995
+ /** Extra content under the brand on the panel: a tagline, an illustration. */
1996
+ content?: ReactNode;
1997
+ }
1998
+
1999
+ /** The back action, as an object when the label or the behavior is not the default. */
2000
+ export declare interface AuthPageBackAction {
2001
+ /** Route to navigate to, rendered as a router `Link`. */
2002
+ to?: string;
2003
+ /** Visible label (and accessible name). Default `"Voltar"`. */
2004
+ label?: string;
2005
+ /** Click handler — used alone (a `<button>`) or together with `to`. */
2006
+ onClick?: () => void;
2007
+ }
2008
+
2009
+ /** Heading level of the page title. */
2010
+ export declare type AuthPageHeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
2011
+
2012
+ export declare interface AuthPageProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
2013
+ /** Logo and/or app name, shown on the brand panel (split) or at the top of the card. */
2014
+ brand?: ReactNode;
2015
+ /** Page title, rendered as a heading — e.g. `"Bem-vindo!"`. */
2016
+ title?: ReactNode;
2017
+ /** Line under the title — e.g. `"Entre com sua conta para continuar"`. */
2018
+ subtitle?: ReactNode;
2019
+ /** Brand panel colors and extra content. */
2020
+ aside?: AuthPageAside;
2021
+ /**
2022
+ * `split` (default): colored top + rounded white sheet below `breakpoint`,
2023
+ * 50/50 brand panel and form at or above it. `card`: one centered card at
2024
+ * every width — the internal-panel login.
2025
+ */
2026
+ variant?: AuthPageVariant;
2027
+ /**
2028
+ * Viewport width, in px, at which `split` turns into two columns. Default
2029
+ * `768`, the width every hand-built auth screen this replaces switched at —
2030
+ * deliberately not the `1024` of `useBreakpoint`, which is about navigation
2031
+ * chrome, not about whether a form fits beside a brand panel.
2032
+ */
2033
+ breakpoint?: number;
2034
+ /** Back action: a route string, or an object with `to`/`label`/`onClick`. Omit to hide it. */
2035
+ back?: string | AuthPageBackAction;
2036
+ /** Content under the form, inside the sheet or card — legal text, a secondary link. */
2037
+ footer?: ReactNode;
2038
+ /** Heading level of `title`. Default `1`, since the auth screen is usually the whole page. */
2039
+ headingLevel?: AuthPageHeadingLevel;
2040
+ /**
2041
+ * Root element. Default `"main"`, the page's main landmark. Use `"div"` when
2042
+ * the page is rendered inside a layout that already owns a `<main>` — two
2043
+ * nested main landmarks are an accessibility violation.
2044
+ */
2045
+ as?: "main" | "div";
2046
+ /** The form — usually an `AuthForm` or one of its presets. */
2047
+ children?: ReactNode;
2048
+ }
2049
+
2050
+ /** How the page is laid out: brand panel beside the form, or one centered card. */
2051
+ export declare type AuthPageVariant = "split" | "card";
2052
+
2053
+ /**
2054
+ * A password field with the minimum length every Tempest backend enforces.
2055
+ *
2056
+ * @param message - Sentence shown below 8 characters.
2057
+ * @returns The password schema.
2058
+ */
2059
+ export declare function authPassword(message?: string): z.ZodString;
2060
+
2061
+ /**
2062
+ * Props every preset (`LoginForm`, `SignUpForm`, …) shares.
2063
+ *
2064
+ * `schema` and `fields` become optional — the preset ships both — and the slots
2065
+ * around the submit button are the preset's to fill, from its `links`.
2066
+ *
2067
+ * @typeParam TSchema - The schema in use; the preset's default when none is passed.
2068
+ */
2069
+ export declare interface AuthPresetProps<TSchema extends z.ZodTypeAny> extends Omit<AuthFormProps<TSchema>, "schema" | "fields" | "labels" | "beforeSubmit" | "afterSubmit"> {
2070
+ /** Replaces the preset's schema. Pair it with `fields` when it adds or renames keys. */
2071
+ schema?: TSchema;
2072
+ /** Replaces the preset's field list. */
2073
+ fields?: readonly AuthField<AuthFieldName<TSchema>>[];
2074
+ }
2075
+
1810
2076
  export declare interface AuthState<TUser> {
1811
2077
  user: TUser | null;
1812
2078
  token: string | null;
@@ -5252,6 +5518,17 @@ export declare interface CreateStorePersistOptions<T> {
5252
5518
  * without a working revocation, that boot `refresh()` restores the previous
5253
5519
  * account for whoever uses the browser next.
5254
5520
  *
5521
+ * With `storage: "local"` the session belongs to the **origin**, not the tab:
5522
+ * every tab reads and writes the same keys and follows what another tab wrote
5523
+ * — on the `storage` event and, before any refresh, `logout()` or ending of
5524
+ * the session, by comparing the stored session with the one it holds. A
5525
+ * rotation elsewhere is adopted; a logout or another account's login
5526
+ * elsewhere ends the session here too, with `onSessionEnd` told it happened
5527
+ * `elsewhere`. Before 0.81.0 a tab left open after logout kept account A and,
5528
+ * on its next `401`, redeemed account B's refresh token from the shared
5529
+ * storage, persisting `{ user: A, token: B }` (#524). `storage: "session"` is
5530
+ * per tab and behaves as before.
5531
+ *
5255
5532
  * Refreshes are collapsed per rotation, not just per overlap: a `401` whose
5256
5533
  * request left with a token that has since been replaced in the same session
5257
5534
  * replays with the new token and refreshes nothing. Three expired requests take
@@ -6554,6 +6831,9 @@ export declare function deepMerge<T>(target: T, source: Partial<T>): T;
6554
6831
  */
6555
6832
  export declare const DEFAULT_API_ERROR_STRINGS: ApiErrorStrings;
6556
6833
 
6834
+ /** PT-BR defaults of {@link AuthFormLabels}. */
6835
+ export declare const DEFAULT_AUTH_FORM_LABELS: AuthFormLabels;
6836
+
6557
6837
  /**
6558
6838
  * What a scanner looks for when you do not say.
6559
6839
  *
@@ -7890,6 +8170,51 @@ declare type FloatingActionButtonVariant = "primary" | "surface";
7890
8170
  */
7891
8171
  export declare function For<T>({ each, children, fallback }: ForProps<T>): ReactNode;
7892
8172
 
8173
+ /** Default fields of `ForgotPasswordForm`: the e-mail, with a line saying what happens next. */
8174
+ export declare const FORGOT_PASSWORD_FIELDS: readonly AuthField<"email">[];
8175
+
8176
+ /**
8177
+ * "Forgot password" form: the e-mail the reset link goes to.
8178
+ *
8179
+ * The confirmation screen after a successful submit is the app's call — most
8180
+ * backends answer the same whether or not the address exists, so the copy
8181
+ * belongs next to the backend's policy, not here.
8182
+ *
8183
+ * @example
8184
+ * const [sent, setSent] = useState(false);
8185
+ * <ForgotPasswordForm
8186
+ * onSubmit={async (values) => { await api.post("/auth/forgot-password", { body: values }); setSent(true); }}
8187
+ * links={{ signIn: "/login" }}
8188
+ * />
8189
+ */
8190
+ export declare function ForgotPasswordForm<TSchema extends z.ZodTypeAny = typeof forgotPasswordSchema>({ schema, fields, links, labels, submitLabel, ...props }: ForgotPasswordFormProps<TSchema>): ReactNode;
8191
+
8192
+ /** Sentences of {@link ForgotPasswordForm}, PT-BR by default. */
8193
+ export declare interface ForgotPasswordFormLabels extends AuthFormLabels {
8194
+ /** Default `"Lembrou a senha?"`. */
8195
+ signInPrompt: string;
8196
+ /** Default `"Entrar"`. */
8197
+ signIn: string;
8198
+ }
8199
+
8200
+ /** Routes the forgot-password form links to. */
8201
+ export declare interface ForgotPasswordFormLinks {
8202
+ /** "Entrar" link, under the form. */
8203
+ signIn?: string;
8204
+ }
8205
+
8206
+ export declare interface ForgotPasswordFormProps<TSchema extends z.ZodTypeAny = typeof forgotPasswordSchema> extends AuthPresetProps<TSchema> {
8207
+ /** Where the links go. */
8208
+ links?: ForgotPasswordFormLinks;
8209
+ /** Overrides for the fixed sentences. */
8210
+ labels?: Partial<ForgotPasswordFormLabels>;
8211
+ }
8212
+
8213
+ /** Default schema of `ForgotPasswordForm`: the e-mail the reset link goes to. */
8214
+ export declare const forgotPasswordSchema: z.ZodObject<{
8215
+ email: z.ZodPipe<z.ZodString, z.ZodEmail>;
8216
+ }, z.core.$strip>;
8217
+
7893
8218
  /**
7894
8219
  * Form wrapper with a built-in layout variant. Replaces ad-hoc `<form>` +
7895
8220
  * `<Stack>` / `<Grid>` boilerplate; pair with [[FormRow]], [[FormSection]],
@@ -8946,6 +9271,43 @@ export declare interface InstallBackgroundSyncOptions {
8946
9271
  * persisting and replaying every header, credentials included.
8947
9272
  */
8948
9273
  credentialHeaders?: readonly string[];
9274
+ /**
9275
+ * Origins besides the worker's own that a replayed request may carry a
9276
+ * credential header to — typically the API host when it is not the app's
9277
+ * origin (`["https://api.acme.com"]`). Default `[]`: only the worker's origin.
9278
+ *
9279
+ * A credential re-applied at replay comes from the page, so it is the app's
9280
+ * credential, whatever the request originally carried under the same header
9281
+ * name. Before 0.81.0 the worker checked only the name, and a mutation to a
9282
+ * third party that failed offline carrying that party's `Authorization` was
9283
+ * replayed to it with the app's bearer (#523). Now, with the rule
9284
+ * `isTrustedCredentialTarget` enforces on the live `ApiClient`:
9285
+ * - an entry that carried a credential header to an origin outside this
9286
+ * scope is dropped before `beforeReplay` runs — re-sending it without the
9287
+ * credential would be a request the app never made, and with the app's
9288
+ * credential, a leak;
9289
+ * - a request returned by `beforeReplay` (custom or default) that carries a
9290
+ * header from `credentialHeaders` to an origin outside this scope is
9291
+ * dropped instead of sent.
9292
+ *
9293
+ * Both drops warn once per origin per replay in development builds. Entries
9294
+ * with no credential header are not affected: the browser attaches that
9295
+ * origin's own cookies, as it did on the original attempt.
9296
+ */
9297
+ trustedOrigins?: readonly string[];
9298
+ /**
9299
+ * How an `"unknown"` owner is handled on an entry with no stripped
9300
+ * credentials (see {@link BackgroundSyncOwnerPolicy}). Default `"strict"`.
9301
+ *
9302
+ * `"lenient"` restores the replay-as-is of 0.77.0 and earlier for an app without sign-in,
9303
+ * where no page ever reports a principal. Do not use it with a cookie
9304
+ * session: the browser attaches on replay the cookie of whoever is signed in
9305
+ * at that moment, so a mutation queued by A whose owner was never stamped
9306
+ * (issuing tab closed, empty `clientId`, stamp lost, legacy entry) goes out
9307
+ * with B's session. Entries with stripped credentials ask the pages either
9308
+ * way. Ignored when a custom `beforeReplay` is given.
9309
+ */
9310
+ ownerPolicy?: BackgroundSyncOwnerPolicy;
8949
9311
  /**
8950
9312
  * Prepare each queued request right before it is replayed: return the
8951
9313
  * request to send (typically with the current credentials applied) or
@@ -8973,20 +9335,11 @@ export declare interface InstallBackgroundSyncOptions {
8973
9335
  * `maxRetentionMinutes` (and warns once per replay in development builds) —
8974
9336
  * so a page that never calls {@link provideBackgroundSyncCredentials} leaves
8975
9337
  * every entry it queued `"unknown"`, and none of them is replayed.
8976
- */
8977
- /**
8978
- * How an `"unknown"` owner is handled on an entry with no stripped
8979
- * credentials (see {@link BackgroundSyncOwnerPolicy}). Default `"strict"`.
8980
9338
  *
8981
- * `"lenient"` restores the replay-as-is of 0.77.0 and earlier for an app without sign-in,
8982
- * where no page ever reports a principal. Do not use it with a cookie
8983
- * session: the browser attaches on replay the cookie of whoever is signed in
8984
- * at that moment, so a mutation queued by A whose owner was never stamped
8985
- * (issuing tab closed, empty `clientId`, stamp lost, legacy entry) goes out
8986
- * with B's session. Entries with stripped credentials ask the pages either
8987
- * way. Ignored when a custom `beforeReplay` is given.
9339
+ * Whatever the hook returns is still held to `trustedOrigins`: a credential
9340
+ * header bound for an origin outside the worker's own and `trustedOrigins` is
9341
+ * never sent.
8988
9342
  */
8989
- ownerPolicy?: BackgroundSyncOwnerPolicy;
8990
9343
  beforeReplay?: (request: Request, context: BackgroundSyncReplayContext) => Request | null | Promise<Request | null>;
8991
9344
  }
8992
9345
 
@@ -10320,6 +10673,64 @@ export declare interface LoggerSink {
10320
10673
  (entry: LogEntry): void;
10321
10674
  }
10322
10675
 
10676
+ /**
10677
+ * Default fields of `LoginForm`: e-mail and password.
10678
+ *
10679
+ * Exported, like the other presets' lists, so an app extends the defaults
10680
+ * (`[...LOGIN_FIELDS, { name: "remember", type: "checkbox", … }]`) instead of
10681
+ * retyping them.
10682
+ */
10683
+ export declare const LOGIN_FIELDS: readonly AuthField<"email" | "password">[];
10684
+
10685
+ /**
10686
+ * Sign-in form: e-mail and password, "forgot password" link, sign-up line and a
10687
+ * slot for social buttons.
10688
+ *
10689
+ * `AuthForm` with the defaults every app wrote by hand: the e-mail trimmed and
10690
+ * lower-cased before validation, `current-password` autocomplete so the saved
10691
+ * password is offered, and the two links in the place users look for them. What
10692
+ * happens on success — storing the session, redirecting — stays in `onSubmit`.
10693
+ *
10694
+ * @example
10695
+ * <LoginForm
10696
+ * onSubmit={async (values) => { await auth.login(values); navigate("/"); }}
10697
+ * links={{ forgotPassword: "/recuperar-senha", signUp: "/cadastro" }}
10698
+ * social={<GoogleSignIn component={GoogleLogin} onSuccess={signInWithGoogle} />}
10699
+ * />
10700
+ */
10701
+ export declare function LoginForm<TSchema extends z.ZodTypeAny = typeof loginSchema>({ schema, fields, links, labels, submitLabel, ...props }: LoginFormProps<TSchema>): ReactNode;
10702
+
10703
+ /** Sentences of {@link LoginForm}, PT-BR by default. */
10704
+ export declare interface LoginFormLabels extends AuthFormLabels {
10705
+ /** Default `"Esqueceu a senha?"`. */
10706
+ forgotPassword: string;
10707
+ /** Default `"Não tem uma conta?"`. */
10708
+ signUpPrompt: string;
10709
+ /** Default `"Cadastre-se"`. */
10710
+ signUp: string;
10711
+ }
10712
+
10713
+ /** Routes the login form links to. Each link is rendered only when its route is set. */
10714
+ export declare interface LoginFormLinks {
10715
+ /** "Esqueceu a senha?" link, above the submit button. */
10716
+ forgotPassword?: string;
10717
+ /** "Cadastre-se" link, under the form. */
10718
+ signUp?: string;
10719
+ }
10720
+
10721
+ export declare interface LoginFormProps<TSchema extends z.ZodTypeAny = typeof loginSchema> extends AuthPresetProps<TSchema> {
10722
+ /** Where the links go. */
10723
+ links?: LoginFormLinks;
10724
+ /** Overrides for the fixed sentences. */
10725
+ labels?: Partial<LoginFormLabels>;
10726
+ }
10727
+
10728
+ /** Default schema of `LoginForm`: normalized e-mail + password of at least 8 characters. */
10729
+ export declare const loginSchema: z.ZodObject<{
10730
+ email: z.ZodPipe<z.ZodString, z.ZodEmail>;
10731
+ password: z.ZodString;
10732
+ }, z.core.$strip>;
10733
+
10323
10734
  export declare type LogLevel = "debug" | "info" | "warn" | "error";
10324
10735
 
10325
10736
  /**
@@ -11703,9 +12114,22 @@ export declare interface OfflineSync<TPayload> {
11703
12114
  pendingCount: () => Promise<number>;
11704
12115
  /** The queued mutations in FIFO order. */
11705
12116
  listPending: () => Promise<OutboxEntry<TPayload>[]>;
11706
- /** Drop every queued mutation (e.g. on logout). */
12117
+ /**
12118
+ * Drop every queued mutation (e.g. on logout).
12119
+ *
12120
+ * Also ends the current session for any `flush` already in flight: that run
12121
+ * delivers no further entry, pulls and applies nothing more and writes no
12122
+ * watermark, and resolves with `interrupted: true`. A `flush` called after this
12123
+ * starts a fresh run instead of joining the abandoned one.
12124
+ */
11707
12125
  clearOutbox: () => Promise<void>;
11708
- /** Reset the pull watermark (e.g. on logout / account switch). */
12126
+ /**
12127
+ * Reset the pull watermark (e.g. on logout / account switch).
12128
+ *
12129
+ * Ends the current session for an in-flight `flush` exactly like
12130
+ * {@link OfflineSync.clearOutbox}, so the run cannot write the ended
12131
+ * session's watermark back after the reset.
12132
+ */
11709
12133
  resetWatermark: () => void;
11710
12134
  /** Read the current reactive {@link SyncState} snapshot synchronously. */
11711
12135
  getState: () => SyncState;
@@ -13105,9 +13529,15 @@ export declare function projectMercator(coord: Coordinate): MercatorPoint;
13105
13529
  * keeps an entry pending when one it stripped is missing), or `null` when there
13106
13530
  * is no session — the worker then drops the entry instead of replaying it
13107
13531
  * anonymously. A throw from `getHeaders` or `getPrincipal` is answered as an
13108
- * explicit `{ error: true }`. The worker only applies headers whose names the
13109
- * original request carried, so returning `Authorization` for every URL never
13110
- * leaks it to a URL that did not receive it in the first place.
13532
+ * explicit `{ error: true }`.
13533
+ *
13534
+ * The worker applies only the header names the original request carried, and
13535
+ * only to the worker's own origin or the `trustedOrigins` given to
13536
+ * {@link installBackgroundSync}: an entry bound for any other origin is dropped
13537
+ * without asking this page. Matching the name is not enough on its own — a
13538
+ * request to a third party carries *that party's* `Authorization`, and until
13539
+ * 0.81.0 its replay received the app's bearer (#523). `getHeaders` still gets
13540
+ * the URL, for an app whose trusted origins need different credentials.
13111
13541
  *
13112
13542
  * Pass `getPrincipal` to bind each entry to whoever queued it: the worker asks
13113
13543
  * the issuing tab right after queueing, asks every tab again before replaying,
@@ -13957,6 +14387,68 @@ export declare interface RequestOptions extends Omit<RequestInit, "body"> {
13957
14387
  */
13958
14388
  export declare function requestPersistentStorage(): Promise<boolean>;
13959
14389
 
14390
+ /** Default fields of `ResetPasswordForm`: new password (with strength meter) and confirmation. */
14391
+ export declare const RESET_PASSWORD_FIELDS: readonly AuthField<"password" | "confirmPassword">[];
14392
+
14393
+ /**
14394
+ * "Choose a new password" form: password and confirmation, with the mismatch
14395
+ * reported under the confirmation field.
14396
+ *
14397
+ * The reset token stays out of the fields: it comes from the URL, and the app
14398
+ * adds it in `onSubmit` — `{ ...values, token }` — where it also decides what an
14399
+ * expired token looks like.
14400
+ *
14401
+ * @example
14402
+ * const [params] = useSearchParams();
14403
+ * <ResetPasswordForm
14404
+ * hints={["Pelo menos 8 caracteres"]}
14405
+ * onSubmit={async (values) => {
14406
+ * await api.post("/auth/reset-password", { body: { ...values, token: params.get("token") } });
14407
+ * }}
14408
+ * />
14409
+ */
14410
+ export declare function ResetPasswordForm<TSchema extends z.ZodTypeAny = typeof resetPasswordSchema>({ schema, fields, hints, links, labels, submitLabel, ...props }: ResetPasswordFormProps<TSchema>): ReactNode;
14411
+
14412
+ /** Sentences of {@link ResetPasswordForm}, PT-BR by default. */
14413
+ export declare interface ResetPasswordFormLabels extends AuthFormLabels {
14414
+ /** Default `"Lembrou a senha?"`. */
14415
+ signInPrompt: string;
14416
+ /** Default `"Entrar"`. */
14417
+ signIn: string;
14418
+ /** Accessible name of the hints list. Default `"Requisitos da senha"`. */
14419
+ hints: string;
14420
+ }
14421
+
14422
+ /** Routes the reset-password form links to. */
14423
+ export declare interface ResetPasswordFormLinks {
14424
+ /** "Entrar" link, under the form. */
14425
+ signIn?: string;
14426
+ }
14427
+
14428
+ export declare interface ResetPasswordFormProps<TSchema extends z.ZodTypeAny = typeof resetPasswordSchema> extends AuthPresetProps<TSchema> {
14429
+ /**
14430
+ * Password requirements listed above the submit button ("Pelo menos 8
14431
+ * caracteres", "Uma letra maiúscula"). Kept as text the app writes, because
14432
+ * only the backend knows its rules.
14433
+ */
14434
+ hints?: ReactNode[];
14435
+ /** Where the links go. */
14436
+ links?: ResetPasswordFormLinks;
14437
+ /** Overrides for the fixed sentences. */
14438
+ labels?: Partial<ResetPasswordFormLabels>;
14439
+ }
14440
+
14441
+ /**
14442
+ * Default schema of `ResetPasswordForm`: new password and its confirmation.
14443
+ *
14444
+ * The mismatch is reported on `confirmPassword` (`path`), so the message lands
14445
+ * under the field the user has to fix rather than in a form-level alert.
14446
+ */
14447
+ export declare const resetPasswordSchema: z.ZodObject<{
14448
+ password: z.ZodString;
14449
+ confirmPassword: z.ZodString;
14450
+ }, z.core.$strip>;
14451
+
13960
14452
  /**
13961
14453
  * A two-pane split layout with a draggable divider. The first pane is sized via
13962
14454
  * `flex-basis` as a percentage; the second pane fills the rest. Drag the divider
@@ -15593,6 +16085,9 @@ export declare interface SidebarSeparator {
15593
16085
  key: string;
15594
16086
  }
15595
16087
 
16088
+ /** Default fields of `SignUpForm`: name, e-mail and a password with strength meter. */
16089
+ export declare const SIGN_UP_FIELDS: readonly AuthField<"name" | "email" | "password">[];
16090
+
15596
16091
  /**
15597
16092
  * Signature capture on a canvas — the "sign here" field of a delivery receipt,
15598
16093
  * a service order, a term of acceptance.
@@ -15664,6 +16159,59 @@ export declare interface SignaturePadProps {
15664
16159
  className?: string;
15665
16160
  }
15666
16161
 
16162
+ /**
16163
+ * Sign-up form: name, e-mail and password by default, plus the "Já tem uma conta?"
16164
+ * line.
16165
+ *
16166
+ * Apps differ most here — a phone, a CPF, a terms checkbox — so the usual call
16167
+ * passes `fields` and a `schema` built with `signUpSchema.extend({...})`. The
16168
+ * password defaults to `new-password` autocomplete, which is what makes a
16169
+ * password manager offer to generate one.
16170
+ *
16171
+ * @example
16172
+ * <SignUpForm
16173
+ * schema={signUpSchema.extend({ terms: z.literal(true, "Aceite os termos") })}
16174
+ * fields={[...SIGN_UP_FIELDS, { name: "terms", type: "checkbox", label: "Aceito os termos" }]}
16175
+ * onSubmit={async (values) => { await api.post("/auth/register", { body: values }); }}
16176
+ * links={{ signIn: "/login" }}
16177
+ * />
16178
+ */
16179
+ export declare function SignUpForm<TSchema extends z.ZodTypeAny = typeof signUpSchema>({ schema, fields, links, labels, submitLabel, ...props }: SignUpFormProps<TSchema>): ReactNode;
16180
+
16181
+ /** Sentences of {@link SignUpForm}, PT-BR by default. */
16182
+ export declare interface SignUpFormLabels extends AuthFormLabels {
16183
+ /** Default `"Já tem uma conta?"`. */
16184
+ signInPrompt: string;
16185
+ /** Default `"Entrar"`. */
16186
+ signIn: string;
16187
+ }
16188
+
16189
+ /** Routes the sign-up form links to. */
16190
+ export declare interface SignUpFormLinks {
16191
+ /** "Entrar" link, under the form. */
16192
+ signIn?: string;
16193
+ }
16194
+
16195
+ export declare interface SignUpFormProps<TSchema extends z.ZodTypeAny = typeof signUpSchema> extends AuthPresetProps<TSchema> {
16196
+ /** Where the links go. */
16197
+ links?: SignUpFormLinks;
16198
+ /** Overrides for the fixed sentences. */
16199
+ labels?: Partial<SignUpFormLabels>;
16200
+ }
16201
+
16202
+ /**
16203
+ * Default schema of `SignUpForm`: name, e-mail and password.
16204
+ *
16205
+ * Exported so an app adds its own fields with `.extend()` instead of rewriting
16206
+ * the three it shares with every other app — see the phone and terms example in
16207
+ * the docs.
16208
+ */
16209
+ export declare const signUpSchema: z.ZodObject<{
16210
+ name: z.ZodString;
16211
+ email: z.ZodPipe<z.ZodString, z.ZodEmail>;
16212
+ password: z.ZodString;
16213
+ }, z.core.$strip>;
16214
+
15667
16215
  /** Loading placeholder block. Use `variant="text"` for inline lines, `circle` for avatars. */
15668
16216
  export declare function Skeleton({ variant, width, height, className, style }: SkeletonProps): JSX.Element;
15669
16217
 
@@ -16169,6 +16717,16 @@ export declare interface SyncRunSummary {
16169
16717
  skipped: boolean;
16170
16718
  /** Last delivery error message seen this run, or `null` when none failed. */
16171
16719
  lastError: string | null;
16720
+ /**
16721
+ * `true` when {@link OfflineSync.clearOutbox} or {@link OfflineSync.resetWatermark}
16722
+ * ended the session while this run was in flight, so it stopped early.
16723
+ *
16724
+ * The counts cover only what happened before the stop: a delivery already in
16725
+ * progress at logout is still counted, but no later entry was sent, no further
16726
+ * page was pulled or applied, and the watermark was not written. Absent on a
16727
+ * run that went to completion.
16728
+ */
16729
+ interrupted?: true;
16172
16730
  }
16173
16731
 
16174
16732
  /**
@@ -16462,6 +17020,17 @@ export declare interface TempestAuth<TUser, TCredentials> {
16462
17020
  refresh: () => Promise<void>;
16463
17021
  /** The current access token, or null. */
16464
17022
  getToken: () => string | null;
17023
+ /**
17024
+ * Stop following the other tabs: removes the `storage` listener this
17025
+ * preset adds to `window`. Idempotent.
17026
+ *
17027
+ * An app keeps one preset for the page's lifetime and never needs it; it
17028
+ * exists for tests and hot-module reload, which build several presets in
17029
+ * one window. A disposed preset still compares the shared storage with
17030
+ * its session before every refresh, so it never redeems another tab's
17031
+ * refresh token.
17032
+ */
17033
+ dispose: () => void;
16465
17034
  }
16466
17035
 
16467
17036
  /**
@@ -16558,6 +17127,22 @@ declare interface TempestSessionEnd<TUser> {
16558
17127
  * call to fail and keep the local half of the teardown independent of it.
16559
17128
  */
16560
17129
  api: ApiClient;
17130
+ /**
17131
+ * Whether another tab of the origin ended or replaced the session, and this
17132
+ * tab is only catching up (#524). With `storage: "local"` the session's
17133
+ * keys are shared by every tab, so a `logout()` or a `login()` in one tab
17134
+ * ends the session in all of them: `reason` is `"logout"` when the other
17135
+ * tab left no session behind and `"switch"` when it installed another
17136
+ * account.
17137
+ *
17138
+ * The other tab already ran this hook for the same session. Teardown that
17139
+ * lives in this tab's memory (an in-memory cache, an open socket) still has
17140
+ * to run here; teardown of state the origin shares (IndexedDB, Cache
17141
+ * Storage, a push subscription) was done there, and on `"switch"` redoing
17142
+ * it here would wipe what the new account already wrote — skip it when
17143
+ * this is `true`.
17144
+ */
17145
+ elsewhere: boolean;
16561
17146
  }
16562
17147
 
16563
17148
  /** The token envelope returned by a Tempest FastAPI SDK login/refresh route. */