tempest-react-sdk 0.81.0 → 0.83.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 (194) hide show
  1. package/README.md +9 -10
  2. package/bin/create-tempest-app.e2e.test.mjs +31 -0
  3. package/bin/create-tempest-app.mjs +11 -1
  4. package/bin/lib/doctor/doctor.e2e.test.mjs +29 -0
  5. package/bin/lib/doctor/vitest.mjs +120 -0
  6. package/bin/lib/doctor/vitest.test.mjs +139 -0
  7. package/bin/lib/fs/contain.mjs +7 -0
  8. package/bin/lib/openapi/escape.mjs +68 -4
  9. package/bin/lib/openapi/generate.hostile.test.mjs +228 -0
  10. package/bin/lib/openapi/generate.mjs +119 -15
  11. package/bin/lib/openapi/pattern-risk.mjs +134 -0
  12. package/bin/lib/openapi/pattern-risk.test.mjs +45 -0
  13. package/bin/tempest-gen.test.mjs +100 -0
  14. package/bin/tempest.mjs +24 -8
  15. package/dist/access/use-can.cjs +1 -1
  16. package/dist/access/use-can.cjs.map +1 -1
  17. package/dist/access/use-can.js +25 -28
  18. package/dist/access/use-can.js.map +1 -1
  19. package/dist/auth/create-tempest-auth.cjs +1 -1
  20. package/dist/auth/create-tempest-auth.cjs.map +1 -1
  21. package/dist/auth/create-tempest-auth.js +189 -143
  22. package/dist/auth/create-tempest-auth.js.map +1 -1
  23. package/dist/auth/session-identity.cjs +2 -0
  24. package/dist/auth/session-identity.cjs.map +1 -0
  25. package/dist/auth/session-identity.js +12 -0
  26. package/dist/auth/session-identity.js.map +1 -0
  27. package/dist/br/boleto.cjs.map +1 -1
  28. package/dist/br/boleto.js.map +1 -1
  29. package/dist/components/AuthForm/AuthLinks.cjs +1 -1
  30. package/dist/components/AuthForm/AuthLinks.cjs.map +1 -1
  31. package/dist/components/AuthForm/AuthLinks.js +18 -15
  32. package/dist/components/AuthForm/AuthLinks.js.map +1 -1
  33. package/dist/components/AuthPage/AuthPage.cjs +1 -1
  34. package/dist/components/AuthPage/AuthPage.cjs.map +1 -1
  35. package/dist/components/AuthPage/AuthPage.js +58 -52
  36. package/dist/components/AuthPage/AuthPage.js.map +1 -1
  37. package/dist/components/Breadcrumbs/Breadcrumbs.cjs +1 -1
  38. package/dist/components/Breadcrumbs/Breadcrumbs.cjs.map +1 -1
  39. package/dist/components/Breadcrumbs/Breadcrumbs.js +22 -21
  40. package/dist/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
  41. package/dist/components/Button/Button.cjs +1 -1
  42. package/dist/components/Button/Button.cjs.map +1 -1
  43. package/dist/components/Button/Button.js +41 -40
  44. package/dist/components/Button/Button.js.map +1 -1
  45. package/dist/components/Chat/ChatAttachments.cjs +1 -1
  46. package/dist/components/Chat/ChatAttachments.cjs.map +1 -1
  47. package/dist/components/Chat/ChatAttachments.js +38 -38
  48. package/dist/components/Form/Form.cjs +1 -1
  49. package/dist/components/Form/Form.cjs.map +1 -1
  50. package/dist/components/Form/Form.js +30 -32
  51. package/dist/components/Form/Form.js.map +1 -1
  52. package/dist/components/Layout/Layout.cjs +1 -1
  53. package/dist/components/Layout/Layout.cjs.map +1 -1
  54. package/dist/components/Layout/Layout.js +25 -24
  55. package/dist/components/Layout/Layout.js.map +1 -1
  56. package/dist/components/Layout/gap.cjs +2 -0
  57. package/dist/components/Layout/gap.cjs.map +1 -0
  58. package/dist/components/Layout/gap.js +15 -0
  59. package/dist/components/Layout/gap.js.map +1 -0
  60. package/dist/components/NavigationMenu/NavigationMenu.cjs +1 -1
  61. package/dist/components/NavigationMenu/NavigationMenu.cjs.map +1 -1
  62. package/dist/components/NavigationMenu/NavigationMenu.js +71 -70
  63. package/dist/components/NavigationMenu/NavigationMenu.js.map +1 -1
  64. package/dist/components/Sidebar/Sidebar.cjs.map +1 -1
  65. package/dist/components/Sidebar/Sidebar.js.map +1 -1
  66. package/dist/components/Sidebar/SidebarEntry.cjs +1 -1
  67. package/dist/components/Sidebar/SidebarEntry.cjs.map +1 -1
  68. package/dist/components/Sidebar/SidebarEntry.js +30 -29
  69. package/dist/components/Sidebar/SidebarEntry.js.map +1 -1
  70. package/dist/data/create-data-provider.cjs +1 -1
  71. package/dist/data/create-data-provider.cjs.map +1 -1
  72. package/dist/data/create-data-provider.js +1 -2
  73. package/dist/data/create-data-provider.js.map +1 -1
  74. package/dist/forms/validate-form.cjs +1 -1
  75. package/dist/forms/validate-form.cjs.map +1 -1
  76. package/dist/forms/validate-form.js +6 -1
  77. package/dist/forms/validate-form.js.map +1 -1
  78. package/dist/forms/zod-resolver.cjs +1 -1
  79. package/dist/forms/zod-resolver.cjs.map +1 -1
  80. package/dist/forms/zod-resolver.js +8 -3
  81. package/dist/forms/zod-resolver.js.map +1 -1
  82. package/dist/http/api-client.cjs +1 -1
  83. package/dist/http/api-client.cjs.map +1 -1
  84. package/dist/http/api-client.js +90 -72
  85. package/dist/http/api-client.js.map +1 -1
  86. package/dist/http/credential-scope.cjs +1 -1
  87. package/dist/http/credential-scope.cjs.map +1 -1
  88. package/dist/http/credential-scope.js +33 -9
  89. package/dist/http/credential-scope.js.map +1 -1
  90. package/dist/http/presigned-post.cjs.map +1 -1
  91. package/dist/http/presigned-post.js.map +1 -1
  92. package/dist/http/resumable-upload.cjs +1 -1
  93. package/dist/http/resumable-upload.cjs.map +1 -1
  94. package/dist/http/resumable-upload.js +167 -112
  95. package/dist/http/resumable-upload.js.map +1 -1
  96. package/dist/http/upload-with-progress.cjs +1 -1
  97. package/dist/http/upload-with-progress.cjs.map +1 -1
  98. package/dist/http/upload-with-progress.js +100 -44
  99. package/dist/http/upload-with-progress.js.map +1 -1
  100. package/dist/oauth/GoogleSignIn.cjs +1 -1
  101. package/dist/oauth/GoogleSignIn.cjs.map +1 -1
  102. package/dist/oauth/GoogleSignIn.js +5 -4
  103. package/dist/oauth/GoogleSignIn.js.map +1 -1
  104. package/dist/offline/create-offline-sync.cjs +1 -1
  105. package/dist/offline/create-offline-sync.cjs.map +1 -1
  106. package/dist/offline/create-offline-sync.js +87 -69
  107. package/dist/offline/create-offline-sync.js.map +1 -1
  108. package/dist/query/offline-persistence.cjs +1 -1
  109. package/dist/query/offline-persistence.cjs.map +1 -1
  110. package/dist/query/offline-persistence.js +67 -44
  111. package/dist/query/offline-persistence.js.map +1 -1
  112. package/dist/sse/create-event-stream.cjs +1 -1
  113. package/dist/sse/create-event-stream.cjs.map +1 -1
  114. package/dist/sse/create-event-stream.js +48 -41
  115. package/dist/sse/create-event-stream.js.map +1 -1
  116. package/dist/sse/ticket-event-stream.cjs +1 -1
  117. package/dist/sse/ticket-event-stream.cjs.map +1 -1
  118. package/dist/sse/ticket-event-stream.js +48 -19
  119. package/dist/sse/ticket-event-stream.js.map +1 -1
  120. package/dist/sse/use-event-stream.cjs +1 -1
  121. package/dist/sse/use-event-stream.cjs.map +1 -1
  122. package/dist/sse/use-event-stream.js +19 -14
  123. package/dist/sse/use-event-stream.js.map +1 -1
  124. package/dist/sw/background-sync.cjs +1 -1
  125. package/dist/sw/background-sync.cjs.map +1 -1
  126. package/dist/sw/background-sync.js +10 -8
  127. package/dist/sw/background-sync.js.map +1 -1
  128. package/dist/sw/cache.cjs +1 -1
  129. package/dist/sw/cache.cjs.map +1 -1
  130. package/dist/sw/cache.js +111 -55
  131. package/dist/sw/cache.js.map +1 -1
  132. package/dist/sw/create-push-handler.cjs +1 -1
  133. package/dist/sw/create-push-handler.cjs.map +1 -1
  134. package/dist/sw/create-push-handler.js +20 -10
  135. package/dist/sw/create-push-handler.js.map +1 -1
  136. package/dist/sw.d.ts +65 -14
  137. package/dist/tabular/compact.cjs +1 -1
  138. package/dist/tabular/compact.cjs.map +1 -1
  139. package/dist/tabular/compact.js +35 -16
  140. package/dist/tabular/compact.js.map +1 -1
  141. package/dist/tabular/manifest.cjs +1 -1
  142. package/dist/tabular/manifest.cjs.map +1 -1
  143. package/dist/tabular/manifest.js +33 -15
  144. package/dist/tabular/manifest.js.map +1 -1
  145. package/dist/tabular.d.ts +11 -1
  146. package/dist/tempest-react-sdk.cjs +1 -1
  147. package/dist/tempest-react-sdk.d.ts +543 -70
  148. package/dist/tempest-react-sdk.js +224 -224
  149. package/dist/theme/initial-theme.cjs +4 -4
  150. package/dist/theme/initial-theme.cjs.map +1 -1
  151. package/dist/theme/initial-theme.js +8 -5
  152. package/dist/theme/initial-theme.js.map +1 -1
  153. package/dist/utils/compressed-storage.cjs +1 -1
  154. package/dist/utils/compressed-storage.cjs.map +1 -1
  155. package/dist/utils/compressed-storage.js +13 -7
  156. package/dist/utils/compressed-storage.js.map +1 -1
  157. package/dist/utils/objects.cjs +1 -1
  158. package/dist/utils/objects.cjs.map +1 -1
  159. package/dist/utils/objects.js +13 -7
  160. package/dist/utils/objects.js.map +1 -1
  161. package/dist/utils/safe-url.cjs +1 -1
  162. package/dist/utils/safe-url.cjs.map +1 -1
  163. package/dist/utils/safe-url.js +4 -1
  164. package/dist/utils/safe-url.js.map +1 -1
  165. package/dist/vite/base-url.cjs +1 -1
  166. package/dist/vite/base-url.cjs.map +1 -1
  167. package/dist/vite/base-url.js +5 -1
  168. package/dist/vite/base-url.js.map +1 -1
  169. package/dist/vite/tempest-pwa-dev-sw.cjs +1 -1
  170. package/dist/vite/tempest-pwa-dev-sw.cjs.map +1 -1
  171. package/dist/vite/tempest-pwa-dev-sw.js +96 -31
  172. package/dist/vite/tempest-pwa-dev-sw.js.map +1 -1
  173. package/dist/vite/tempest-pwa-manifest.cjs +2 -2
  174. package/dist/vite/tempest-pwa-manifest.cjs.map +1 -1
  175. package/dist/vite/tempest-pwa-manifest.js +32 -16
  176. package/dist/vite/tempest-pwa-manifest.js.map +1 -1
  177. package/dist/vite.cjs +1 -1
  178. package/dist/vite.d.ts +63 -12
  179. package/dist/vite.js +4 -4
  180. package/dist/webrtc/peer-mesh.cjs +1 -1
  181. package/dist/webrtc/peer-mesh.cjs.map +1 -1
  182. package/dist/webrtc/peer-mesh.js +7 -1
  183. package/dist/webrtc/peer-mesh.js.map +1 -1
  184. package/dist/ws/create-web-socket.cjs +1 -1
  185. package/dist/ws/create-web-socket.cjs.map +1 -1
  186. package/dist/ws/create-web-socket.js +77 -61
  187. package/dist/ws/create-web-socket.js.map +1 -1
  188. package/dist/ws/use-web-socket.cjs +1 -1
  189. package/dist/ws/use-web-socket.cjs.map +1 -1
  190. package/dist/ws/use-web-socket.js +4 -3
  191. package/dist/ws/use-web-socket.js.map +1 -1
  192. package/package.json +1 -1
  193. package/template-pwa/src/pwa.tsx +42 -0
  194. package/template-pwa/src/sw.ts +5 -4
@@ -966,7 +966,20 @@ export declare interface ApiClientConfig {
966
966
  * without it, and is exposed the same way.
967
967
  */
968
968
  csrf?: boolean | CsrfOptions;
969
- /** Default headers merged into every request. */
969
+ /**
970
+ * Default headers merged into every request inside the credential scope.
971
+ *
972
+ * Treated as a credential since 0.82.0 — an `X-Api-Key` set once here is as
973
+ * much a secret as the bearer — so they go only to `baseURL`'s origin and
974
+ * {@link trustedOrigins}. A redirect would move them past that check, and
975
+ * unlike `Authorization` no browser strips them on a cross-origin hop
976
+ * (measured in Chrome 150, #554). So while this is non-empty, an in-scope
977
+ * request goes out with `redirect: "manual"`, and a redirect answering it
978
+ * is thrown as a `TempestApiError` with `code: "REDIRECT_REFUSED"` — the
979
+ * browser hides the `Location`, so the same-origin case cannot be told
980
+ * apart and followed by hand. Call the final URL (FastAPI's trailing-slash
981
+ * `307` is the usual source), or pass `redirect: "follow"` on the call.
982
+ */
970
983
  headers?: Record<string, string>;
971
984
  /** Optional fetch implementation (defaults to globalThis.fetch). */
972
985
  fetcher?: typeof fetch;
@@ -1998,7 +2011,11 @@ export declare interface AuthPageAside {
1998
2011
 
1999
2012
  /** The back action, as an object when the label or the behavior is not the default. */
2000
2013
  export declare interface AuthPageBackAction {
2001
- /** Route to navigate to, rendered as a router `Link`. */
2014
+ /**
2015
+ * Route to navigate to, rendered as a router `Link`. Passes through
2016
+ * `safeLinkUrl`: a destination it rejects is dropped, leaving the button with
2017
+ * `onClick` or, without one, no back action at all.
2018
+ */
2002
2019
  to?: string;
2003
2020
  /** Visible label (and accessible name). Default `"Voltar"`. */
2004
2021
  label?: string;
@@ -2642,6 +2659,12 @@ export declare interface BreadcrumbItem {
2642
2659
  * Hierarchical navigation breadcrumbs. The last item is rendered as plain
2643
2660
  * text with `aria-current="page"`. Items with neither `href` nor `onClick`
2644
2661
  * also render as text (intermediate but non-clickable).
2662
+ *
2663
+ * Each `href` is vetted with `safeLinkUrl`'s allowlist: an item whose URL uses a scheme
2664
+ * outside `http:`/`https:`/`mailto:`/`tel:`/`sms:` loses the `href`, and renders
2665
+ * as text unless it also has an `onClick`. A trail built from API data — the
2666
+ * folder names of a document tree — would otherwise put a clickable
2667
+ * `javascript:` link on the page under React 18, which writes it verbatim.
2645
2668
  */
2646
2669
  export declare function Breadcrumbs({ items, separator, className }: BreadcrumbsProps): JSX.Element;
2647
2670
 
@@ -2789,6 +2812,13 @@ export declare function buildOpenInChromeIntent(): string | null;
2789
2812
  * link gets `aria-disabled="true"`, `role="link"`, `tabIndex={-1}`, no `href`, and
2790
2813
  * its click and middle-click cancelled.
2791
2814
  *
2815
+ * The `href` is vetted first, with `safeLinkUrl`'s allowlist: `http:`, `https:`, `mailto:`,
2816
+ * `tel:`, `sms:` and relative URLs pass, anything else renders as the same inert,
2817
+ * `aria-disabled` link. React 19 blocks a `javascript:` href but the peer range
2818
+ * admits React 18, which writes it verbatim (#447), and a CTA built from API data
2819
+ * should not need the app to remember that. A link to a custom scheme (`whatsapp:`,
2820
+ * an app deep link) goes through {@link ButtonSlot} with the app's own `<a>`.
2821
+ *
2792
2822
  * To style another element — a react-router `Link` — use {@link ButtonSlot}. It is
2793
2823
  * a separate component, not an `asChild` prop, so an app that never uses it does
2794
2824
  * not ship the prop merge and ref composition it needs.
@@ -4177,7 +4207,21 @@ export declare const CPFInput: ForwardRefExoticComponent<Omit<InputProps, "value
4177
4207
  * destination of a credentialed request could come from a value read off the
4178
4208
  * network. A request to another origin still goes out; it goes without the
4179
4209
  * header, and a development build says so once. Declare the exceptions in
4180
- * {@link ApiClientConfig.trustedOrigins}.
4210
+ * {@link ApiClientConfig.trustedOrigins}. Since 0.82.0 the static
4211
+ * {@link ApiClientConfig.headers} follow the same scope, and a `401` from
4212
+ * outside it is thrown without `refresh` or `onUnauthorized` — it answered a
4213
+ * request that never carried this session's credential.
4214
+ *
4215
+ * **Redirects.** The scope is checked against the URL the request starts at;
4216
+ * where a redirect then goes is the transport's call. For `Authorization` that
4217
+ * is safe: browsers strip it on a cross-origin redirect, measured in Chrome 150
4218
+ * for `fetch` and XHR on `301`/`302`/`303`/`307`/`308` (#554). They strip
4219
+ * nothing else, so a request carrying the static {@link ApiClientConfig.headers}
4220
+ * goes out with `redirect: "manual"`, and a redirect answering it is thrown as a
4221
+ * {@link TempestApiError} with `code: "REDIRECT_REFUSED"` instead of being
4222
+ * followed. It cannot be followed by hand: a browser's manual redirect is an
4223
+ * opaque response whose `Location` is unreadable. A `redirect` set on the call
4224
+ * always wins.
4181
4225
  *
4182
4226
  * **CSRF** is off unless you set `csrf`. With it, every unsafe request (anything
4183
4227
  * but `GET`/`HEAD`/`OPTIONS`/`TRACE`) echoes the `csrf_token` cookie in an
@@ -4505,7 +4549,13 @@ export declare function createDataProvider(client: ApiClient, options?: DataProv
4505
4549
  *
4506
4550
  * When `url` is a function it is called before every connection, so a
4507
4551
  * reconnect presents a fresh credential instead of the one that expired. A
4508
- * resolution still pending when `close()` or `reconnect()` runs is discarded.
4552
+ * resolution still pending when `close()` or `reconnect()` runs is discarded, and
4553
+ * one that has not started yet is never made: a stream closed in the same tick
4554
+ * it was created asks for no URL — no ticket request, for the ticket stream.
4555
+ *
4556
+ * Pass `sessionKey` to bind the stream to the session it opened under: once
4557
+ * the key changes, no frame of the previous session reaches `onMessage`, and
4558
+ * the stream reconnects for the new one.
4509
4559
  *
4510
4560
  * @param url - Full SSE endpoint URL, or a function returning it per connection.
4511
4561
  * @param options - Stream configuration and callbacks.
@@ -4573,6 +4623,30 @@ export declare interface CreateEventStreamOptions<T> {
4573
4623
  * URL that never resolved never had an `EventSource`.
4574
4624
  */
4575
4625
  onUrlError?: (error: unknown) => void;
4626
+ /**
4627
+ * Read the current session key; the stream belongs to the session that was
4628
+ * current when it connected.
4629
+ *
4630
+ * The server cannot end the stream for you. The `tempest-fastapi-sdk` SSE
4631
+ * router checks the ticket only when the stream opens, and neither logout
4632
+ * nor refresh-token revocation touches an open stream: it lives until the
4633
+ * client leaves. So a tab that switches from user A to user B without
4634
+ * closing the stream keeps receiving A's events under B.
4635
+ *
4636
+ * With this set, the key is read when each connection starts, again when
4637
+ * its URL resolved, and before every frame is delivered. A frame that
4638
+ * arrives after the key changed is dropped, never delivered, and the stream
4639
+ * reconnects for the session now current — with a fresh ticket, for the
4640
+ * ticket stream. A URL resolved while the key changed is discarded the same
4641
+ * way, since the ticket inside it may belong to either session.
4642
+ *
4643
+ * The check runs when a frame arrives: a stream that stays quiet holds its
4644
+ * connection until the next frame or until `close()`. The hook form closes
4645
+ * it as soon as the key changes.
4646
+ *
4647
+ * Keys are compared with `Object.is`. Leave it out and nothing changes.
4648
+ */
4649
+ sessionKey?: () => SessionKey;
4576
4650
  /**
4577
4651
  * Whether a URL-resolution failure is worth another attempt. Default: always.
4578
4652
  *
@@ -5309,7 +5383,7 @@ export declare interface CreateRefreshQueueOptions {
5309
5383
  * | --- | --- | --- |
5310
5384
  * | Create | `POST {endpoint}` + `Upload-Length`, `Upload-Metadata`, `Idempotency-Key` | `201` + `Location` (the upload URL, absolute or endpoint-relative) |
5311
5385
  * | Probe | `HEAD {uploadUrl}` | `200`/`204` + `Upload-Offset` |
5312
- * | Write | `PATCH {uploadUrl}` + `Upload-Offset`, `Content-Type: application/offset+octet-stream`, chunk body | `204` + the new `Upload-Offset`; `409` when the offset does not match |
5386
+ * | Write | `PATCH {uploadUrl}` + `Upload-Offset`, `Content-Type: application/offset+octet-stream`, chunk body | `204` + the new `Upload-Offset`, past the one sent; `409` when the offset does not match |
5313
5387
  * | Discard | `DELETE {uploadUrl}` | `204` |
5314
5388
  *
5315
5389
  * ## The failure that actually happens
@@ -5526,8 +5600,13 @@ export declare interface CreateStorePersistOptions<T> {
5526
5600
  * elsewhere ends the session here too, with `onSessionEnd` told it happened
5527
5601
  * `elsewhere`. Before 0.81.0 a tab left open after logout kept account A and,
5528
5602
  * 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.
5603
+ * storage, persisting `{ user: A, token: B }` (#524). Whether the stored
5604
+ * session is the held one is decided by a **session lineage** that `login()`
5605
+ * mints and every rotation keeps — not by comparing users, which took two
5606
+ * sign-ins whose user had not loaded yet for the same account (#544). Two tabs
5607
+ * never redeem the same refresh token at once: the redemption runs under an
5608
+ * origin-wide Web Lock when the browser has one. `storage: "session"` is per
5609
+ * tab and behaves as before.
5531
5610
  *
5532
5611
  * Refreshes are collapsed per rotation, not just per overlap: a `401` whose
5533
5612
  * request left with a token that has since been replaced in the same session
@@ -5593,9 +5672,14 @@ export declare interface CreateTempestAuthOptions<TUser> {
5593
5672
  * while it is in flight waits for it, because the logout response clears
5594
5673
  * the auth cookies and would otherwise clear the new account's.
5595
5674
  *
5596
- * Only an explicit `logout()` revokes. On `"switch"` the cookie jar already
5597
- * holds the new account's cookie, and on `"expired"` the server has already
5598
- * refused the session.
5675
+ * An explicit `logout()` revokes, and so does a `"switch"` in body mode:
5676
+ * the replaced session's refresh token is still in the client's hands, and
5677
+ * the tempest-fastapi-sdk revokes by rotation family, so the session the
5678
+ * new login opened is untouched even for the same user. Before 0.82.0 a
5679
+ * switch revoked nothing and the replaced token stayed redeemable until it
5680
+ * expired. A `"switch"` in cookie mode does not revoke — the cookie jar
5681
+ * already holds the new account's cookie — and on `"expired"` the server
5682
+ * has already refused the session.
5599
5683
  *
5600
5684
  * Overlapping sign-outs each send their own revocation, and `login()` waits
5601
5685
  * for all of them — at most 10 seconds, so one that
@@ -5806,9 +5890,23 @@ export declare interface CreateThemeOptions {
5806
5890
  * cookie) on the ticket request, and the ticket in the URL opens that stream
5807
5891
  * and nothing else.
5808
5892
  *
5893
+ * With the `api` of `createTempestAuth` as `client` and no `sessionKey`, the
5894
+ * stream follows that preset's session (since 0.82.0): it closes the moment
5895
+ * the session is replaced or ends, reopens with a fresh ticket for the next
5896
+ * one, stays closed while nobody is signed in, and ignores token rotation.
5897
+ * Any other client binds only through `sessionKey`, checked per frame.
5898
+ *
5899
+ * @example
5900
+ * const stream = createTicketEventStream<Notification>({
5901
+ * client: auth.api,
5902
+ * onMessage: ({ data }) => addNotification(data),
5903
+ * });
5904
+ *
5809
5905
  * @example
5906
+ * // A client createTempestAuth did not build
5810
5907
  * const stream = createTicketEventStream<Notification>({
5811
5908
  * client: api,
5909
+ * sessionKey: () => useAuthStore.getState().user?.id ?? null,
5812
5910
  * onMessage: ({ data }) => addNotification(data),
5813
5911
  * onUrlError: (error) => toast.error(describeApiError(error)),
5814
5912
  * });
@@ -5992,6 +6090,24 @@ export declare interface CreateWebSocketOptions<T> {
5992
6090
  queueWhileClosed?: boolean;
5993
6091
  /** Cap on buffered payloads when `queueWhileClosed` is on. Default: 100. */
5994
6092
  maxQueuedMessages?: number;
6093
+ /**
6094
+ * Who is signed in right now — a stable, non-secret id such as the user id;
6095
+ * `null`/`undefined` when nobody is. Read when a payload is buffered by
6096
+ * `queueWhileClosed` and again when the buffer drains on the next open: a
6097
+ * payload goes out only while the same principal is signed in, and is
6098
+ * dropped otherwise.
6099
+ *
6100
+ * The URL and the protocols are fixed for the controller's life, so a socket
6101
+ * that authenticates by cookie re-handshakes as whoever is signed in at
6102
+ * reconnect time. Without this, a frame buffered by one account during the
6103
+ * backoff was sent on the reconnect under the next account's cookie when the
6104
+ * app did not `close()` the socket on logout (#531).
6105
+ *
6106
+ * Read synchronously. A non-string, non-number value (the `Promise` of an
6107
+ * `async` getter) or a getter that throws reads as nobody. Default: no
6108
+ * owner check.
6109
+ */
6110
+ getPrincipal?: () => string | number | null | undefined;
5995
6111
  /** Parse incoming frames. Default: JSON with raw-string fallback. */
5996
6112
  parser?: (raw: string) => T;
5997
6113
  /**
@@ -6794,10 +6910,18 @@ export declare function decodeJWT(token: string): DecodedJWT;
6794
6910
  * compression was enabled — or by a write that fell back after `gzipSync`
6795
6911
  * failed — still read back.
6796
6912
  *
6913
+ * The output size is bounded before anything is inflated. fflate sizes its
6914
+ * output buffer from the gzip trailer (`ISIZE`) and never grows it — measured: a
6915
+ * 1 MB payload whose trailer claims 10 bytes inflates to exactly 10 — so
6916
+ * refusing a trailer above {@link MAX_DECOMPRESSED_BYTES} bounds the allocation,
6917
+ * whatever the trailer says about the real data. A corrupted or hostile value
6918
+ * fails fast instead of taking the tab's memory.
6919
+ *
6797
6920
  * @typeParam T - The expected value shape.
6798
6921
  * @param raw - The stored string.
6799
6922
  * @returns The decoded value.
6800
- * @throws If the payload is neither valid compressed data nor valid JSON.
6923
+ * @throws If the payload is neither valid compressed data nor valid JSON, or
6924
+ * declares a decompressed size above 64 MiB.
6801
6925
  */
6802
6926
  export declare function decompressFromString<T>(raw: string): T;
6803
6927
 
@@ -6808,6 +6932,13 @@ export declare function decompressFromString<T>(raw: string): T;
6808
6932
  * - Arrays and non-plain values (dates, class instances, primitives) replace
6809
6933
  * the target value entirely — they are not merged element by element.
6810
6934
  * - Neither `target` nor `source` is mutated.
6935
+ * - `__proto__`, `constructor` and `prototype` keys in `source` are skipped.
6936
+ * Assigning `result["__proto__"]` does not create a key: it **replaces the
6937
+ * result's prototype**, so a `JSON.parse`d settings blob carrying
6938
+ * `{"__proto__": {"isAdmin": true}}` produced an object whose `isAdmin` read
6939
+ * `true` through inheritance while `Object.keys` showed nothing. No global
6940
+ * prototype is touched either way; the skip removes the surprise, and the
6941
+ * other two names go with it because nothing legitimate merges into them.
6811
6942
  *
6812
6943
  * @example
6813
6944
  * deepMerge(
@@ -8247,7 +8378,7 @@ export declare type FormActionsAlign = "start" | "center" | "end" | "between";
8247
8378
  export declare interface FormActionsProps extends HTMLAttributes<HTMLDivElement> {
8248
8379
  /** Horizontal alignment of buttons. Default `end`. */
8249
8380
  align?: FormActionsAlign;
8250
- /** Gap between buttons. Numbers map to a multiple of the 4px scale (default `2` → 8px). */
8381
+ /** Gap between buttons. Numbers map to a multiple of the 4px scale (default `2` → 8px). A number is a step, not pixels (`6` → 24px): above `12` a development build warns once, and a string such as `"96px"` passes through untouched. */
8251
8382
  gap?: number | string;
8252
8383
  }
8253
8384
 
@@ -8597,7 +8728,7 @@ export { FormProvider }
8597
8728
  export declare function FormRow({ gap, className, style, children, ...props }: FormRowProps): JSX.Element;
8598
8729
 
8599
8730
  export declare interface FormRowProps extends HTMLAttributes<HTMLDivElement> {
8600
- /** Gap between row items. Numbers map to a multiple of the 4px scale (default `3` → 12px). */
8731
+ /** Gap between row items. Numbers map to a multiple of the 4px scale (default `3` → 12px). A number is a step, not pixels (`6` → 24px): above `12` a development build warns once, and a string such as `"96px"` passes through untouched. */
8601
8732
  gap?: number | string;
8602
8733
  }
8603
8734
 
@@ -8720,7 +8851,14 @@ export declare interface GetListParams {
8720
8851
  field: string;
8721
8852
  order?: "asc" | "desc";
8722
8853
  };
8723
- /** Arbitrary filter query params, spread onto the request. */
8854
+ /**
8855
+ * Arbitrary filter query params, spread onto the request **before**
8856
+ * `pagination` and `sort`. A filter whose key equals a pagination or sort
8857
+ * param name (`page`, `size`, `order_by`, `ascending` by default) is
8858
+ * overridden by the structured value when that one is set: until 0.81.0 the
8859
+ * filter won, so `filters: { page: 1 }` from a table's filter state silently
8860
+ * pinned every request to page 1.
8861
+ */
8724
8862
  filters?: DataFilters;
8725
8863
  }
8726
8864
 
@@ -8769,7 +8907,7 @@ export declare function getThemePreset(name: string): CreateThemeOptions | undef
8769
8907
  * />
8770
8908
  * </GoogleOAuthProvider>
8771
8909
  */
8772
- export declare function GoogleSignIn({ component: Component, onSuccess, onError, locale, theme, text, shape, size, disableOneTap, width, className, style, }: GoogleSignInProps): JSX.Element;
8910
+ export declare function GoogleSignIn({ component: Component, onSuccess, onError, locale, theme, text, shape, size, disableOneTap, width, nonce, className, style, }: GoogleSignInProps): JSX.Element;
8773
8911
 
8774
8912
  export declare interface GoogleSignInProps {
8775
8913
  /**
@@ -8796,6 +8934,16 @@ export declare interface GoogleSignInProps {
8796
8934
  disableOneTap?: boolean;
8797
8935
  /** Optional `width` override (px) — Google's button is fixed-width. */
8798
8936
  width?: number;
8937
+ /**
8938
+ * Server-issued nonce Google copies into the ID token's `nonce` claim.
8939
+ *
8940
+ * The backend issues one per sign-in attempt, keeps it, and rejects an
8941
+ * `id_token` whose claim does not match — which is what stops a token
8942
+ * captured elsewhere from being replayed against your API. Until 0.82.0
8943
+ * the wrapper dropped it, so an app could not bind the token through
8944
+ * `<GoogleSignIn>` at all (#530).
8945
+ */
8946
+ nonce?: string;
8799
8947
  /** Optional className applied to the wrapper. */
8800
8948
  className?: string;
8801
8949
  /** Optional inline style applied to the wrapper. */
@@ -8816,7 +8964,7 @@ export declare function Grid({ columns, gap, className, style, children, ...prop
8816
8964
  export declare interface GridProps extends HTMLAttributes<HTMLDivElement> {
8817
8965
  /** Number of columns or a custom `grid-template-columns` value. Accepts responsive object. */
8818
8966
  columns?: ResponsiveValue<number | string>;
8819
- /** Gap as a CSS length. Numbers map to a multiple of the 4px scale. Accepts responsive object. */
8967
+ /** Gap as a CSS length. Numbers map to a multiple of the 4px scale. Accepts responsive object. A number is a step, not pixels (`6` → 24px): above `12` a development build warns once, and a string such as `"96px"` passes through untouched. */
8820
8968
  gap?: ResponsiveValue<number | string>;
8821
8969
  children?: ReactNode;
8822
8970
  }
@@ -9494,7 +9642,9 @@ export declare type InstallMethod = "native" | "ios" | "manual" | "none";
9494
9642
  *
9495
9643
  * A click on an action button opens that action's URL (see
9496
9644
  * {@link PushNotificationAction.url}); a click on the body, or on an action
9497
- * without one, opens the top-level `url`.
9645
+ * without one, opens the top-level `url`. Only a same-origin `http(s)` URL is
9646
+ * opened by default; see {@link InstallNotificationClickHandlerOptions.resolveUrl}
9647
+ * for opting into another origin.
9498
9648
  */
9499
9649
  export declare function installNotificationClickHandler(options?: InstallNotificationClickHandlerOptions): void;
9500
9650
 
@@ -9503,6 +9653,12 @@ export declare interface InstallNotificationClickHandlerOptions {
9503
9653
  * Resolve the destination URL from the notification data and the clicked
9504
9654
  * action id (`""` or `undefined` for a click on the body). Default: the
9505
9655
  * action's entry in `data.actionUrls`, else `data.url`, else `"/"`.
9656
+ *
9657
+ * The default only ever opens a page of the worker's **own origin**: a URL on
9658
+ * another origin, or with a scheme other than `http:`/`https:`, becomes `"/"`.
9659
+ * A resolver of your own is how an app opts into another origin — what it
9660
+ * returns may point anywhere `http:`/`https:`, and any other scheme still
9661
+ * becomes `"/"`.
9506
9662
  */
9507
9663
  resolveUrl?: (data: unknown, action: string | undefined) => string;
9508
9664
  }
@@ -9517,7 +9673,27 @@ export declare type InstallOutcome = "accepted" | "dismissed" | "unsupported";
9517
9673
  * - on `fetch`, serves precached assets cache-first and falls back to the
9518
9674
  * `navigateFallback` document for offline navigations (SPA routing).
9519
9675
  *
9520
- * Same-origin only. Register this LAST, after any {@link installRuntimeCache}.
9676
+ * Survives the browser stopping and restarting the worker, which it does
9677
+ * whenever the worker sits idle and which never repeats `install`. Nothing the
9678
+ * fetch handler needs lives only in memory: `install` and `activate` record, in
9679
+ * an entry inside the versioned cache, when that version was installed and
9680
+ * activated, and a restarted worker reads back the activated version and its
9681
+ * pathnames from Cache Storage. Before 0.83.0 the cache name and the precached
9682
+ * paths were module variables filled only by `install`, so after the first
9683
+ * restart offline navigations failed with "offline and no cached app shell",
9684
+ * precached assets went to the network, and an `activate` in a run without
9685
+ * `install` deleted every precache, the current one included (#572).
9686
+ *
9687
+ * `activate` deletes the other `${cacheName}-*` caches only once it knows which
9688
+ * version it is activating; when no version recorded an install it deletes
9689
+ * nothing. In the first request after a restart, while the worker is still
9690
+ * reading which paths are precached, a same-origin `GET` that a runtime route
9691
+ * did not answer is answered with `fetch(request)` when it is not precached —
9692
+ * the decision to call `respondWith` cannot wait for Cache Storage. From then on
9693
+ * a non-precached request is left to the browser, as before.
9694
+ *
9695
+ * Same-origin only. Register this LAST, after any {@link installRuntimeCache}:
9696
+ * a request a runtime route answered is never answered again here.
9521
9697
  */
9522
9698
  export declare function installPrecache(options?: InstallPrecacheOptions): void;
9523
9699
 
@@ -9549,8 +9725,9 @@ export declare interface InstallPrecacheOptions {
9549
9725
  * Every `NotificationOptions` member the payload carries is forwarded —
9550
9726
  * `actions`, `requireInteraction`, `vibrate`, `silent`, `renotify`,
9551
9727
  * `timestamp`, `dir` and `lang` alongside `body`, `icon`, `badge`, `image` and
9552
- * `tag`. `data` receives the top-level `url` (default `"/"`), the payload's
9553
- * own `data`, and `actionUrls` mapping each action id to its `url`.
9728
+ * `tag`. `data` receives the payload's own `data`, then the top-level `url`
9729
+ * (default `"/"`) and `actionUrls` mapping each action id to its `url` — in that
9730
+ * order, so `payload.data` cannot override where a click goes.
9554
9731
  */
9555
9732
  export declare function installPushHandler(options?: InstallPushHandlerOptions): void;
9556
9733
 
@@ -9574,9 +9751,10 @@ export declare interface InstallPushHandlerOptions {
9574
9751
  * `respondWith`), so a later {@link installPrecache} can handle them.
9575
9752
  *
9576
9753
  * A request carrying a credential header (`Authorization`, `X-Api-Key`, … — the
9577
- * route's `credentialHeaders`) is also left untouched unless its route sets
9754
+ * route's `credentialHeaders`), or a CORS `fetch` sent with
9755
+ * `credentials: "include"`, is also left untouched unless its route sets
9578
9756
  * `cacheAuthenticated`, and a response with `Cache-Control: no-store`
9579
- * (or `private`, without that opt-in) is served but never stored. `maxAgeSeconds`
9757
+ * (or `private`, without that opt-in) or `Vary: *` is served but never stored. `maxAgeSeconds`
9580
9758
  * applies to every read, including the offline fallback: an expired entry is a
9581
9759
  * miss, never a last resort. Under `rangeRequests`, the full resource is cached
9582
9760
  * once (the `Range` header stripped) and each range is sliced from it.
@@ -9973,11 +10151,13 @@ declare type IssuePathSegment = PropertyKey | {
9973
10151
  * rather than the request blocked: the upload still goes through, it just goes
9974
10152
  * without the API's bearer token.
9975
10153
  *
9976
- * Both sides are resolved against the document first, so a relative `baseURL`
9977
- * or `endpoint` — the shape behind a dev-server or reverse proxy — compares
9978
- * equal to the absolute URL the request actually goes to. Outside a browsing
9979
- * context a relative target resolves to nothing and is allowed: there is no
9980
- * origin for it to cross.
10154
+ * Both sides are resolved first, so a relative `baseURL` or `endpoint` — the
10155
+ * shape behind a dev-server or reverse proxy — compares equal to the absolute
10156
+ * URL the request actually goes to. The target resolves against the document
10157
+ * base URL, where the transport sends it; the reference against the page's
10158
+ * own address, which a `<base href>` cannot move. Outside a browsing context a
10159
+ * relative target is allowed — there is no origin for it to cross — and a
10160
+ * target that does not parse is refused rather than trusted.
9981
10161
  *
9982
10162
  * @param target - The URL the request is about to go to.
9983
10163
  * @param reference - The origin the credential belongs to, normally the
@@ -10273,7 +10453,7 @@ declare interface LayoutProps {
10273
10453
  layout?: FormLayout;
10274
10454
  /** Number of columns when `layout="grid"`, or a custom `grid-template-columns` value. Default `2`. */
10275
10455
  columns?: number | string;
10276
- /** Gap between fields. Numbers map to a multiple of the 4px scale (default `4` → 16px). */
10456
+ /** Gap between fields. Numbers map to a multiple of the 4px scale (default `4` → 16px). A number is a step, not pixels (`6` → 24px): above `12` a development build warns once, and a string such as `"96px"` passes through untouched. */
10277
10457
  gap?: number | string;
10278
10458
  }
10279
10459
 
@@ -11604,7 +11784,12 @@ export declare function NavigationMenu({ items, portal, className, ...props }: N
11604
11784
  export declare interface NavigationMenuItem {
11605
11785
  /** Visible label for the entry. */
11606
11786
  label: ReactNode;
11607
- /** When set, the entry renders as an anchor. */
11787
+ /**
11788
+ * When set, the entry renders as an anchor. The URL is checked against
11789
+ * `safeLinkUrl`'s allowlist: a scheme outside `http:`/`https:`/`mailto:`/`tel:`/`sms:`
11790
+ * renders the entry as a button instead, so a menu built from API data cannot
11791
+ * put a clickable `javascript:` link on the page under React 18.
11792
+ */
11608
11793
  href?: string;
11609
11794
  /** Invoked when the entry is activated (click / Enter). */
11610
11795
  onSelect?: () => void;
@@ -11976,7 +12161,8 @@ export declare interface OfflineQueryPersistence {
11976
12161
  /**
11977
12162
  * Load the persisted snapshot into the `QueryClient`. Call once on boot,
11978
12163
  * before rendering queries, so cached data is available offline. A no-op
11979
- * once {@link OfflineQueryPersistence.clear} has been called.
12164
+ * once {@link OfflineQueryPersistence.clear} has been called, and — with
12165
+ * `getPrincipal` — for a snapshot written under another principal.
11980
12166
  */
11981
12167
  restore: () => Promise<void>;
11982
12168
  /**
@@ -12036,6 +12222,39 @@ export declare interface OfflineQueryPersistenceOptions {
12036
12222
  * one trailing write per window. Default `1000`.
12037
12223
  */
12038
12224
  throttleMs?: number;
12225
+ /**
12226
+ * Who is signed in right now — a stable, non-secret id such as the user id;
12227
+ * `null`/`undefined` when nobody is. Read on every write, which stamps the
12228
+ * snapshot with a one-way fingerprint of it (never the id itself), and on
12229
+ * `restore()`, which hydrates only a snapshot stamped with the same
12230
+ * fingerprint.
12231
+ *
12232
+ * `clear()` on logout already deletes the snapshot; this covers the session
12233
+ * that ends without it — a token that expired, a crash, a tab closed while
12234
+ * signed in. Without it, the next account to boot on the browser is shown
12235
+ * the previous account's cached responses (#531). A snapshot written before
12236
+ * this option was set carries no stamp and is not restored either; it is a
12237
+ * cache, so the cost is one cold start.
12238
+ *
12239
+ * A foreign snapshot is skipped, not deleted: a cookie app that only learns
12240
+ * the principal after a `/me` round trip would otherwise wipe its own cache
12241
+ * on every cold start. The next write replaces it.
12242
+ *
12243
+ * The handle is bound to the first signed-in owner it writes or restores.
12244
+ * Once bound, a write under another owner — nobody, because the token
12245
+ * expired without `clear()`, or a second account on the same tab — deletes
12246
+ * the snapshot instead of stamping the bound owner's cached responses with
12247
+ * the new owner (#563); the same owner coming back writes again. Writes
12248
+ * before anyone signs in stay anonymous and are restored while nobody is,
12249
+ * so an app that persists logged-out data keeps doing so. An anonymous
12250
+ * snapshot written by 0.82.0 is not restored (it may hold an expired
12251
+ * session's cache): one cold start, once.
12252
+ *
12253
+ * Read synchronously. A non-string, non-number value (the `Promise` of an
12254
+ * `async` getter) or a getter that throws reads as nobody. Omit it to restore
12255
+ * every snapshot, as before 0.82.0.
12256
+ */
12257
+ getPrincipal?: () => string | number | null | undefined;
12039
12258
  }
12040
12259
 
12041
12260
  /** Maps each table name to the record type it stores. */
@@ -12212,6 +12431,30 @@ export declare interface OfflineSyncConfig<TPayload, TRemote> {
12212
12431
  crossTab?: boolean;
12213
12432
  /** Channel name when `crossTab` is on. Default `tempest-sync:${databaseName}`. */
12214
12433
  broadcastChannelName?: string;
12434
+ /**
12435
+ * Who is signed in right now — a stable, non-secret id such as the user id;
12436
+ * `null`/`undefined` when nobody is. Read synchronously when an entry is
12437
+ * queued, which stamps it with a one-way fingerprint (`entry.owner`, never
12438
+ * the id itself), and again right before each delivery:
12439
+ *
12440
+ * - same principal → delivered;
12441
+ * - nobody signed in now → held: it stays queued and goes out when its owner
12442
+ * signs back in, so a flush fired by the `online` event before login loses
12443
+ * nothing;
12444
+ * - anybody else → deleted unsent and counted in `summary.dropped`, because
12445
+ * delivering it would send the previous account's mutation with the next
12446
+ * account's session.
12447
+ *
12448
+ * `clearOutbox()` on logout already empties the queue; this covers the app
12449
+ * that forgets it, or a session that ends without a logout (#531). Entries
12450
+ * queued before this option was set carry no stamp and are delivered as
12451
+ * before — they are the user's own unsynced edits, and holding them would
12452
+ * strand every queue on upgrade.
12453
+ *
12454
+ * A non-string, non-number value (the `Promise` of an `async` getter) or a
12455
+ * getter that throws reads as nobody. Default: no owner binding.
12456
+ */
12457
+ getPrincipal?: () => string | number | null | undefined;
12215
12458
  }
12216
12459
 
12217
12460
  export declare interface OfflineTableConfig<TItem> {
@@ -12493,6 +12736,13 @@ export declare interface OutboxEntry<TPayload = unknown> {
12493
12736
  lastError?: string;
12494
12737
  /** Record snapshot for `create`/`update`. Omitted for `delete`. */
12495
12738
  payload?: TPayload;
12739
+ /**
12740
+ * One-way fingerprint of whoever was signed in when the entry was queued
12741
+ * (`null` for nobody), stamped only when the engine has
12742
+ * {@link OfflineSyncConfig.getPrincipal}. Absent on entries queued without
12743
+ * it, which are delivered as before.
12744
+ */
12745
+ owner?: string | null;
12496
12746
  }
12497
12747
 
12498
12748
  /**
@@ -13059,6 +13309,23 @@ export declare interface PeerMeshOptions {
13059
13309
  onState?: (state: MeshState, detail?: string) => void;
13060
13310
  /** Called for a failure worth surfacing that is not fatal to the mesh. */
13061
13311
  onNotice?: (reason: string) => void;
13312
+ /**
13313
+ * Decide whether an offer from a peer the mesh has no link to is answered.
13314
+ *
13315
+ * By default the mesh answers any offer that reaches {@link PeerMesh.accept},
13316
+ * opening a link and publishing the local tracks to it — the answering side
13317
+ * usually learns of a peer from its offer, so that is the documented flow.
13318
+ * It also means whether the microphone and camera reach someone rests only
13319
+ * on the signalling server relaying offers to the right people. Pass a gate
13320
+ * — typically "is this user in the room roster I fetched" — to make that
13321
+ * the app's decision too. A refused offer opens nothing, answers nothing and
13322
+ * reports `onNotice("offer_refused")`. Peers added with `addPeer` are not
13323
+ * asked: adding them was the decision.
13324
+ *
13325
+ * @param peerId - The `from` of the offer.
13326
+ * @returns `true` to answer it.
13327
+ */
13328
+ acceptPeer?: (peerId: string) => boolean;
13062
13329
  /** Initial encoder limits. */
13063
13330
  quality?: MeshQuality;
13064
13331
  /** Measure every link, on one timer the mesh owns. See {@link MeshStatsOptions}. */
@@ -13541,7 +13808,13 @@ export declare function projectMercator(coord: Coordinate): MercatorPoint;
13541
13808
  *
13542
13809
  * Pass `getPrincipal` to bind each entry to whoever queued it: the worker asks
13543
13810
  * the issuing tab right after queueing, asks every tab again before replaying,
13544
- * and drops the entry when no signed-in tab is its owner.
13811
+ * and drops the entry when no signed-in tab is its owner. Without it every
13812
+ * entry is `"unbound"` and replays with whichever session answers — the next
13813
+ * account's bearer included, unless `clearSessionData()` ran on logout — so a
13814
+ * development build warns once per call (#531). Treating an unbound
13815
+ * credentialed entry as `"unknown"` instead would change nothing: an
13816
+ * `"unknown"` entry replays when no answering tab reports a principal, which is
13817
+ * exactly the page that omits `getPrincipal`.
13545
13818
  *
13546
13819
  * @param getHeaders - Resolves the headers for one queued request at replay.
13547
13820
  * @param options - `getPrincipal` binds entries to their owner.
@@ -13663,7 +13936,14 @@ export declare interface PushPayload {
13663
13936
  dir?: NotificationDirection;
13664
13937
  /** BCP 47 language tag of the title and body. */
13665
13938
  lang?: string;
13666
- /** Arbitrary extra data forwarded to `event.notification.data`. */
13939
+ /**
13940
+ * Arbitrary extra data forwarded to `event.notification.data`.
13941
+ *
13942
+ * Its `url` and `actionUrls` keys are overwritten by the top-level `url` and
13943
+ * the actions' `url`s: those two keys decide where a click goes, and a
13944
+ * free-form bag — often filled from the record that triggered the push — must
13945
+ * not be able to redirect it.
13946
+ */
13667
13947
  data?: Record<string, unknown>;
13668
13948
  }
13669
13949
 
@@ -14554,6 +14834,13 @@ export declare interface ResumableUpload {
14554
14834
  /**
14555
14835
  * Stop for good.
14556
14836
  *
14837
+ * A later `start()`/`resume()` on the same handle attaches as a new handle
14838
+ * would (since 0.83.0): it resumes the stored record only when the current
14839
+ * owner stamped it, and otherwise creates a new upload with a fresh
14840
+ * `Idempotency-Key`. Until then a token-bound handle resumed its own upload
14841
+ * with whatever token was current — after an account switch, the next
14842
+ * account's (#561).
14843
+ *
14557
14844
  * @param options - `discard: true` also sends `DELETE` (tus termination) and
14558
14845
  * forgets the persisted record, so the next `start()` uploads from zero.
14559
14846
  */
@@ -14580,7 +14867,21 @@ export declare interface ResumableUploadOptions {
14580
14867
  chunkSize?: number;
14581
14868
  /** Sent as `Upload-Metadata` (base64-encoded values), e.g. `{ filename }`. */
14582
14869
  metadata?: Record<string, string>;
14583
- /** Extra headers on every request. */
14870
+ /**
14871
+ * Extra headers on every request inside the credential scope — the
14872
+ * `endpoint`'s origin plus {@link trustedOrigins}. A `Location` on another
14873
+ * host gets only the tus headers, never these (since 0.82.0).
14874
+ *
14875
+ * A request that carries them never follows a redirect (since 0.83.0): it
14876
+ * goes out over `fetch` with `redirect: "manual"`, and a redirect rejects
14877
+ * with a `TempestApiError` of `code: "REDIRECT_REFUSED"`. An
14878
+ * `XMLHttpRequest` follows every redirect, and these headers went with it
14879
+ * to the other origin (#564). The cost: `fetch` reports no upload
14880
+ * progress, so `onProgress` then ticks once per confirmed chunk — lower
14881
+ * `chunkSize` for a finer bar, or send the credential through `getToken`,
14882
+ * which keeps the `XMLHttpRequest` (the browser strips `Authorization` on
14883
+ * a cross-origin redirect).
14884
+ */
14584
14885
  headers?: Record<string, string>;
14585
14886
  /** Returns the current bearer token, read before each request. */
14586
14887
  getToken?: () => string | null | undefined;
@@ -14592,13 +14893,20 @@ export declare interface ResumableUploadOptions {
14592
14893
  * The resume record is stamped with a one-way fingerprint of it, and a
14593
14894
  * record stamped by anyone else — another user, nobody, or no stamp at all
14594
14895
  * — is deleted instead of resumed: its upload URL is not probed, and its
14595
- * `Idempotency-Key` is never replayed. Without it, the record is bound to
14596
- * the file alone (endpoint, name, size, type, mtime), so after user A
14597
- * signed out leaving an upload half-done, user B picking an identical file
14598
- * sent `HEAD`/`PATCH` to A's upload URL with B's token, and on refusal
14599
- * replayed A's `Idempotency-Key` with B's token (#479). Pass it on every
14600
- * app with more than one account per browser, and also clear the storage
14601
- * at session end (`createLocalUploadStorage().clear()` in `onSessionEnd`).
14896
+ * `Idempotency-Key` is never replayed (#479).
14897
+ *
14898
+ * Without it, since 0.82.0 the record is bound to a fingerprint of the
14899
+ * `getToken` token instead, so another account's record is still never
14900
+ * adopted (#528) — but a token rotates: a reload after a refresh that no
14901
+ * chunk landed under starts the upload over. Pass `getPrincipal` to keep
14902
+ * resuming across refreshes, and always with a cookie session, where there
14903
+ * is no token to bind to and the record stays unbound.
14904
+ *
14905
+ * `getToken: auth.getToken` — the getter of `createTempestAuth` itself, not
14906
+ * an arrow around it — binds to that preset's session instead, as if
14907
+ * `getPrincipal: auth.sessionKey` were passed: the record survives token
14908
+ * rotation, a switch of account stops the run, and a new `login()`, even
14909
+ * into the same account, starts over.
14602
14910
  *
14603
14911
  * It is read again before every chunk and every record write: when it
14604
14912
  * names someone else mid-run, the run stops with
@@ -14675,10 +14983,11 @@ export declare interface ResumableUploadRecord {
14675
14983
  /** Epoch ms of the last write, so an app can sweep stale records. */
14676
14984
  updatedAt: number;
14677
14985
  /**
14678
- * One-way fingerprint of the principal that created the upload (`"p:<hex>"`),
14679
- * `null` for an anonymous one. Absent when the upload ran without
14680
- * {@link ResumableUploadOptions.getPrincipal}, and on records written before
14681
- * 0.78.0.
14986
+ * One-way fingerprint of the principal that created the upload (`"p:<hex>"`)
14987
+ * or, without {@link ResumableUploadOptions.getPrincipal}, of the bearer
14988
+ * token of its last write (`"t:<hex>"`, since 0.82.0); `null` for an
14989
+ * anonymous one. Absent when the upload ran with neither getter, and on
14990
+ * records written before 0.78.0.
14682
14991
  */
14683
14992
  owner?: string | null;
14684
14993
  }
@@ -14999,8 +15308,9 @@ export declare interface RuntimeRoute {
14999
15308
  */
15000
15309
  rangeRequests?: boolean;
15001
15310
  /**
15002
- * Opt in to caching requests that carry a credential header (see
15003
- * `credentialHeaders`), and responses marked `Cache-Control: private`.
15311
+ * Opt in to caching credentialed requests — those that carry a credential
15312
+ * header (see `credentialHeaders`) or are a CORS-mode `fetch` sent with
15313
+ * `credentials: "include"` — and responses marked `Cache-Control: private`.
15004
15314
  * Default `false`.
15005
15315
  *
15006
15316
  * Cache Storage is keyed by URL and outlives the session: without this
@@ -15017,11 +15327,18 @@ export declare interface RuntimeRoute {
15017
15327
  * `clearSessionData()` on logout, which removes the entries themselves.
15018
15328
  * `Cache-Control: no-store` is never cached, opt-in or not.
15019
15329
  *
15020
- * A cookie session is invisible here: the worker cannot see `Cookie`, and
15021
- * gating on `request.credentials` would switch off caching for every
15022
- * same-origin image and font. A cookie-authenticated API stays private only
15330
+ * A cookie session is only partly visible here: the worker cannot see
15331
+ * `Cookie`. What it can see is a `fetch` that asked for cookies explicitly —
15332
+ * `mode: "cors"` with `credentials: "include"`, which is what `ApiClient`
15333
+ * sends under `withCredentials` — and since 0.82.0 that request is treated
15334
+ * as credentialed too (#531). `<img>`, `<audio>` and `<video>` also send
15335
+ * `credentials: "include"`, but in `no-cors` mode, so they keep caching. A
15336
+ * plain same-origin `fetch` (`credentials: "same-origin"`, the default)
15337
+ * carries the cookie without saying so; such an API stays private only
15023
15338
  * through `Cache-Control: private`/`no-store` on its responses and
15024
- * `clearSessionData()` on logout.
15339
+ * `clearSessionData()` on logout. Opting a cookie request in caches it by
15340
+ * URL — there is no credential header to vary on — so `clearSessionData()`
15341
+ * is then its only isolation.
15025
15342
  */
15026
15343
  cacheAuthenticated?: boolean;
15027
15344
  /**
@@ -15645,6 +15962,16 @@ export declare interface SequentialScaleOptions {
15645
15962
  ordinal?: boolean;
15646
15963
  }
15647
15964
 
15965
+ /**
15966
+ * Identifies the session a stream belongs to: the signed-in user's id, an
15967
+ * auth epoch, `null` when signed out.
15968
+ *
15969
+ * A primitive on purpose. The hook form lists it in its effect dependencies,
15970
+ * and an object built inline would be a new identity on every render, so the
15971
+ * stream would reopen on every render.
15972
+ */
15973
+ export declare type SessionKey = string | number | boolean | null | undefined;
15974
+
15648
15975
  /**
15649
15976
  * Thrown when the session that started an operation is no longer the current
15650
15977
  * one by the time it settles: a `refresh` hook (rethrown by
@@ -16026,6 +16353,10 @@ export declare interface SidebarItem {
16026
16353
  * A `disabled` entry ignores this and stays a `<button disabled>`: there is no
16027
16354
  * disabled state for an anchor, and dropping the `href` to fake one leaves a
16028
16355
  * link that announces itself as actionable and is not.
16356
+ *
16357
+ * The URL goes through `safeLinkUrl`: a scheme outside
16358
+ * `http:`/`https:`/`mailto:`/`tel:`/`sms:` makes the entry a button, the same
16359
+ * as an entry without `href`.
16029
16360
  */
16030
16361
  href?: string;
16031
16362
  }
@@ -16506,7 +16837,7 @@ export declare type StackJustify = "start" | "center" | "end" | "between";
16506
16837
  export declare interface StackProps extends HTMLAttributes<HTMLDivElement> {
16507
16838
  /** Direction. Accepts responsive object — e.g. `{ mobile: "vertical", desktop: "horizontal" }`. */
16508
16839
  direction?: ResponsiveValue<StackDirection>;
16509
- /** Gap as a CSS length. Numbers map to a multiple of the 4px scale. Accepts responsive object. */
16840
+ /** Gap as a CSS length. Numbers map to a multiple of the 4px scale. Accepts responsive object. A number is a step, not pixels (`6` → 24px): above `12` a development build warns once, and a string such as `"96px"` passes through untouched. */
16510
16841
  gap?: ResponsiveValue<number | string>;
16511
16842
  align?: StackAlign;
16512
16843
  justify?: StackJustify;
@@ -16727,6 +17058,17 @@ export declare interface SyncRunSummary {
16727
17058
  * run that went to completion.
16728
17059
  */
16729
17060
  interrupted?: true;
17061
+ /**
17062
+ * Entries left queued because nobody is signed in and they belong to
17063
+ * somebody (see {@link OfflineSyncConfig.getPrincipal}). Absent when zero.
17064
+ */
17065
+ held?: number;
17066
+ /**
17067
+ * Entries deleted unsent because they were queued under another principal —
17068
+ * or while signed out — and somebody else is signed in now (see
17069
+ * {@link OfflineSyncConfig.getPrincipal}). Absent when zero.
17070
+ */
17071
+ dropped?: number;
16730
17072
  }
16731
17073
 
16732
17074
  /**
@@ -17020,6 +17362,28 @@ export declare interface TempestAuth<TUser, TCredentials> {
17020
17362
  refresh: () => Promise<void>;
17021
17363
  /** The current access token, or null. */
17022
17364
  getToken: () => string | null;
17365
+ /**
17366
+ * The key of the session signed in now, or `null` when nobody is.
17367
+ *
17368
+ * It changes when the session is replaced — `login()`, even into the same
17369
+ * account, a sign-in or sign-out in another tab, `logout()` — and stays
17370
+ * the same while that session's tokens rotate: it is the session lineage
17371
+ * `login()` mints, not the token. That is the identity a per-session
17372
+ * resource needs. `useTicketEventStream`/`createTicketEventStream` read it
17373
+ * on their own from `api`, and `createResumableUpload` from `getToken`;
17374
+ * pass it as `sessionKey` or `getPrincipal` anywhere else.
17375
+ *
17376
+ * A session restored by `refresh()` with none installed — the boot
17377
+ * restore from a refresh cookie, an OAuth callback — is a new sign-in and
17378
+ * gets a lineage of its own, like `login()` (#561). A session persisted
17379
+ * before lineages existed has none in storage; its key is minted by this
17380
+ * preset for as long as that session lasts, so it survives the session's
17381
+ * rotations but no other session ever shares it. Until 0.82.0 both cases
17382
+ * answered one constant for every account, and an upload bound by
17383
+ * `getToken: auth.getToken` was resumed by the next account restored the
17384
+ * same way.
17385
+ */
17386
+ sessionKey: () => string | null;
17023
17387
  /**
17024
17388
  * Stop following the other tabs: removes the `storage` listener this
17025
17389
  * preset adds to `window`. Idempotent.
@@ -17194,6 +17558,10 @@ export declare function themeContrast(options: CreateThemeOptions): number | nul
17194
17558
  * hydrates. Inline this in `<head>` to avoid a flash of the wrong theme on
17195
17559
  * first paint.
17196
17560
  *
17561
+ * Both options are embedded through an escaper that keeps them inside the
17562
+ * `<script>` element whatever they contain, so the snippet is safe to inline
17563
+ * even when the storage key comes from configuration.
17564
+ *
17197
17565
  * @example
17198
17566
  * <script dangerouslySetInnerHTML={{ __html: themeInitScript() }} />
17199
17567
  */
@@ -17289,6 +17657,10 @@ export declare interface TicketEventStreamSource {
17289
17657
  * Authenticated client the ticket is requested through, so it carries the
17290
17658
  * `Authorization` header or the session cookie, the CSRF header, and the
17291
17659
  * 401 refresh-and-replay that a hand-rolled `fetch` would lose.
17660
+ *
17661
+ * The `api` of `createTempestAuth` also carries the session it acts for,
17662
+ * and the stream binds to it when `sessionKey` is not passed — see
17663
+ * {@link useTicketEventStream}.
17292
17664
  */
17293
17665
  client: Pick<ApiClient, "post" | "url">;
17294
17666
  /** Router prefix, relative to the client's base URL. Default: `"/sse"`. */
@@ -18094,7 +18466,12 @@ export declare function uploadFingerprint(endpoint: string, file: Blob | File):
18094
18466
  * allowing a preflight.
18095
18467
  *
18096
18468
  * A file larger than `post.max_bytes` is refused before anything is sent, with
18097
- * the same `413 FILE_TOO_LARGE` the server would answer. Server errors are
18469
+ * the same `413 FILE_TOO_LARGE` the server would answer. A numeric string
18470
+ * (`"5242880"`) compares as a number; a missing or non-numeric `max_bytes` —
18471
+ * a bare boto3 `generate_presigned_post` has none — skips this precheck, and
18472
+ * the signed policy's `content-length-range` stays the control that refuses
18473
+ * the bytes. The precheck saves a wasted upload; it never was the limit.
18474
+ * Server errors are
18098
18475
  * normalized into one `TempestApiError` whichever backend answered: the S3 XML
18099
18476
  * (`EntityTooLarge` → `FILE_TOO_LARGE`, `EntityTooSmall` → `FILE_TOO_SMALL`,
18100
18477
  * `AccessDenied` → `SIGNED_URL_INVALID`, or `SIGNED_URL_EXPIRED` when the policy
@@ -18138,6 +18515,11 @@ export declare interface UploadProgressEvent {
18138
18515
  * back to `XMLHttpRequest`. It mirrors the error contract used by
18139
18516
  * {@link createApiClient}: non-2xx responses reject with a `TempestApiError`.
18140
18517
  *
18518
+ * An `XMLHttpRequest` cannot refuse a redirect; see
18519
+ * {@link UploadWithProgressOptions.redirect} for what follows one, what the
18520
+ * helper still refuses, and the `fetch` path that trades progress for never
18521
+ * following.
18522
+ *
18141
18523
  * @returns The parsed JSON response, or the raw text when the response is not JSON.
18142
18524
  */
18143
18525
  export declare function uploadWithProgress<T = unknown>(options: UploadWithProgressOptions): Promise<T>;
@@ -18151,18 +18533,22 @@ export declare interface UploadWithProgressOptions {
18151
18533
  getToken?: () => string | null | undefined;
18152
18534
  /**
18153
18535
  * Origin the `getToken` credential belongs to, normally the API's.
18536
+ * Defaults to the page's own origin (`location.origin`).
18154
18537
  *
18155
18538
  * Unlike `createApiClient`, this helper has no base URL to infer a scope
18156
- * from — the caller names the destination on every call. Set this when the
18157
- * `url` can come from somewhere other than your own code (a signed URL the
18158
- * API handed back, a value from a response body) and the token must not
18159
- * follow it off-origin. Left unset, the header goes wherever `url` points,
18160
- * which is the behaviour every version before 0.66.0 had.
18539
+ * from — the caller names the destination on every call, and the `url` can
18540
+ * come from somewhere other than your own code (a signed URL the API handed
18541
+ * back, a value from a response body). Until 0.82.0 an unset scope sent the
18542
+ * token wherever `url` pointed; it now starts closed, like the CSRF token
18543
+ * always did, and an API on another origin sets this to receive it (#530).
18544
+ *
18545
+ * Outside a browsing context there is no page origin, and the scope falls
18546
+ * back to `url` itself.
18161
18547
  */
18162
18548
  credentialOrigin?: string;
18163
18549
  /**
18164
18550
  * Extra origins allowed to receive the credential, on top of
18165
- * {@link credentialOrigin}. Ignored when that one is unset.
18551
+ * {@link credentialOrigin} (or the page origin it defaults to).
18166
18552
  */
18167
18553
  trustedOrigins?: readonly string[];
18168
18554
  /** Send cookies. Defaults to false. */
@@ -18171,12 +18557,9 @@ export declare interface UploadWithProgressOptions {
18171
18557
  * Send a CSRF token with the upload, as `createApiClient`'s `csrf` does.
18172
18558
  * Off by default; `true` reads the `csrf_token` cookie into `X-CSRF-Token`.
18173
18559
  *
18174
- * Scoped to {@link credentialOrigin} plus {@link trustedOrigins} — and,
18175
- * unlike the bearer token, scoped even when `credentialOrigin` is unset:
18176
- * then the scope is the page's own origin. The bearer default stays open
18177
- * only for compatibility with every version before 0.66.0; this option is
18178
- * new, so it starts closed. An API on another origin sets
18179
- * `credentialOrigin` to receive the token.
18560
+ * Scoped exactly like the bearer token: to {@link credentialOrigin} (the
18561
+ * page's own origin when unset) plus {@link trustedOrigins}. An API on
18562
+ * another origin sets `credentialOrigin` to receive the token.
18180
18563
  */
18181
18564
  csrf?: boolean | CsrfOptions;
18182
18565
  /** Called on every `progress` event from the XHR upload channel. */
@@ -18190,6 +18573,33 @@ export declare interface UploadWithProgressOptions {
18190
18573
  * Defaults to a generated id. Return an empty string to disable.
18191
18574
  */
18192
18575
  requestId?: () => string;
18576
+ /**
18577
+ * What to do when the server answers with a redirect. Default `"follow"`.
18578
+ *
18579
+ * - `"follow"` — the `XMLHttpRequest` path, with byte-level progress. The
18580
+ * browser follows every redirect and offers no way to stop it: measured
18581
+ * in Chrome 150 (#570), a same-origin upload answered `301`/`302`/`303`/
18582
+ * `307`/`308` towards another origin delivered `X-Api-Key` from
18583
+ * {@link headers} and the SDK's own `X-CSRF-Token` there on all five, and
18584
+ * the body on `307`/`308`; only `Authorization` was stripped. What this
18585
+ * path does enforce (since 0.83.0): an answer from another origin than
18586
+ * the one the request was sent to is never the result — it rejects with
18587
+ * `code: "REDIRECT_REFUSED"`, so that host cannot hand the app a URL to
18588
+ * store. Until 0.82.0 it resolved with the other host's body.
18589
+ * - `"error"` — goes out over `fetch` with `redirect: "manual"`, and a
18590
+ * redirect rejects with `code: "REDIRECT_REFUSED"` before anything is
18591
+ * sent to the other host. The cost: `fetch` reports no upload progress,
18592
+ * so `onProgress` fires once, when the server confirms the whole body. A
18593
+ * streamed `fetch` body would report progress, but Chrome refuses one
18594
+ * over HTTP/1.1 (`TypeError: Failed to fetch`, measured) and Firefox and
18595
+ * Safari do not support it.
18596
+ *
18597
+ * Use `"error"` when {@link headers} carry a credential (an `X-Api-Key`) and
18598
+ * the server behind `url` could redirect; sending the bearer through
18599
+ * {@link getToken} keeps `"follow"` safe for it, because the browser strips
18600
+ * `Authorization` on a cross-origin redirect.
18601
+ */
18602
+ redirect?: "follow" | "error";
18193
18603
  }
18194
18604
 
18195
18605
  /**
@@ -18557,9 +18967,19 @@ export declare function useBreakpoint(): BreakpointHelpers;
18557
18967
  *
18558
18968
  * Handles sync booleans, sync {@link CanResult}, and promises of either. When
18559
18969
  * no provider is present, access is allowed (see `useAccessControl`). The check
18560
- * re-runs whenever the params change.
18970
+ * re-runs whenever the params change; they are compared by their
18971
+ * `JSON.stringify` form, so an inline object literal does not re-run it on
18972
+ * every render.
18973
+ *
18974
+ * A resolved answer is stored with the control and the params it answers, and
18975
+ * is only returned while both still match. Until 0.81.0 the previous answer was
18976
+ * returned with `isLoading: false` for the render between a params change and
18977
+ * the effect that re-ran the check, so `<Can>` showed the children for the new
18978
+ * resource for one frame on the strength of the old resource's permission. The
18979
+ * first render for new params now reads `{ allowed: false, isLoading: true }`.
18561
18980
  *
18562
18981
  * @param params - The action/resource being checked.
18982
+ * @returns The answer for exactly these params, or the pending state.
18563
18983
  */
18564
18984
  export declare function useCan(params: CanParams): UseCanResult;
18565
18985
 
@@ -18899,8 +19319,12 @@ export declare function useEventListener<K extends keyof HTMLElementEventMap>(ev
18899
19319
 
18900
19320
  /**
18901
19321
  * React hook wrapper around {@link createEventStream}. Connection lifecycle is
18902
- * tied to the component (and the `url`/`enabled` dependencies); the stream
18903
- * closes on unmount.
19322
+ * tied to the component (and the `url`/`enabled`/`sessionKey` dependencies);
19323
+ * the stream closes on unmount.
19324
+ *
19325
+ * Pass `sessionKey` (the signed-in user's id) whenever the stream carries one
19326
+ * user's data: a change of account then closes the previous user's stream and
19327
+ * clears `lastMessage`, even when `enabled` never went `false` in between.
18904
19328
  *
18905
19329
  * A string `url` reopens the stream when it changes. A function `url` does not:
18906
19330
  * an inline arrow is a new function every render, and keying on its identity
@@ -18932,9 +19356,24 @@ export declare function useEventListener<K extends keyof HTMLElementEventMap>(ev
18932
19356
  */
18933
19357
  export declare function useEventStream<T = unknown>(url: EventStreamUrl, options?: UseEventStreamOptions<T>): UseEventStreamResult<T>;
18934
19358
 
18935
- export declare interface UseEventStreamOptions<T> extends Omit<CreateEventStreamOptions<T>, "onStatusChange"> {
19359
+ export declare interface UseEventStreamOptions<T> extends Omit<CreateEventStreamOptions<T>, "onStatusChange" | "sessionKey"> {
18936
19360
  /** When false, the stream is not opened. Useful for "wait for auth". Default: true. */
18937
19361
  enabled?: boolean;
19362
+ /**
19363
+ * The session the stream belongs to — the signed-in user's id, typically.
19364
+ *
19365
+ * A change closes the stream, clears `lastMessage` and, while `enabled`,
19366
+ * opens a new connection for the new session (a fresh ticket, for
19367
+ * {@link useTicketEventStream}). Without it, a tab that switches accounts
19368
+ * without passing through `enabled: false` keeps the previous user's
19369
+ * stream open and delivers its events under the new user: the server does
19370
+ * not end an open stream on logout or revocation, so the client has to.
19371
+ *
19372
+ * A frame that arrives between the render that changed the key and the
19373
+ * effect that closes the stream is dropped as well. Default: `undefined`,
19374
+ * which never changes, so the stream follows `url` and `enabled` alone.
19375
+ */
19376
+ sessionKey?: SessionKey;
18938
19377
  }
18939
19378
 
18940
19379
  export declare interface UseEventStreamResult<T> {
@@ -20958,11 +21397,33 @@ export declare function useThrottle<T>(value: T, delay: number): T;
20958
21397
  * Reopening on identity would reconnect on every render for a client built
20959
21398
  * inline.
20960
21399
  *
21400
+ * The stream is bound to a session: the ticket names the channel of the user
21401
+ * who asked for it, the server never ends an open stream on logout, and a tab
21402
+ * that switches accounts without `enabled` going `false` would otherwise keep
21403
+ * delivering the previous user's events. A change of session closes that
21404
+ * stream and asks a ticket for the new one.
21405
+ *
21406
+ * With the `api` of `createTempestAuth` as `client`, that binding is automatic
21407
+ * (since 0.82.0): the session is read from the client — `auth.sessionKey()`,
21408
+ * the lineage `login()` mints — so a switch closes the stream, a token
21409
+ * rotation of the same session does not, and while nobody is signed in the
21410
+ * stream stays `idle` without asking for a ticket. Any other client keeps the
21411
+ * behaviour it had: pass `sessionKey` (the signed-in user's id). A
21412
+ * `sessionKey` passed explicitly always wins over the client's.
21413
+ *
21414
+ * @example
21415
+ * const { status } = useTicketEventStream<Notification>({
21416
+ * client: auth.api,
21417
+ * schema: notificationSchema,
21418
+ * onMessage: ({ data }) => addNotification(data),
21419
+ * });
21420
+ *
20961
21421
  * @example
21422
+ * // A client createTempestAuth did not build
20962
21423
  * const { status } = useTicketEventStream<Notification>({
20963
21424
  * client: api,
20964
21425
  * enabled: isAuthenticated,
20965
- * schema: notificationSchema,
21426
+ * sessionKey: user?.id ?? null,
20966
21427
  * onMessage: ({ data }) => addNotification(data),
20967
21428
  * });
20968
21429
  *
@@ -21184,7 +21645,7 @@ export { useWatch }
21184
21645
  * for the host component and tears it down on unmount.
21185
21646
  *
21186
21647
  * Every callback is read through a ref, so `onOpen` / `onMessage` / `onClose` /
21187
- * `onError` / `onReconnecting` / `onReconnected` / `onLost` always run the
21648
+ * `onError` / `onReconnecting` / `onReconnected` / `onLost` / `getPrincipal` always run the
21188
21649
  * latest closure — an inline arrow function is fine and never reopens the
21189
21650
  * socket. Connection-shaping options (`protocols`, `maxRetries`,
21190
21651
  * `initialBackoff`, `maxBackoff`, `jitter`, `handshakeTimeout`,
@@ -21275,6 +21736,12 @@ export declare function validateCPF(value: string): boolean;
21275
21736
  * become `"address.city"`, array entries `"items.0.name"`. The first issue
21276
21737
  * per path wins (subsequent ones are dropped to keep error UIs tidy).
21277
21738
  *
21739
+ * The map is a plain object, but every key is written as an **own** property
21740
+ * and looked up with `hasOwnProperty`: with `path in errors` and `errors[path] =`
21741
+ * a field named `constructor` or `toString` read as already failed through
21742
+ * `Object.prototype` and lost its message, and an issue a `superRefine` files
21743
+ * under `__proto__` replaced the map's prototype instead of becoming a key.
21744
+ *
21278
21745
  * @param schema - zod schema describing the form shape.
21279
21746
  * @param values - Raw form values (typed as `unknown`).
21280
21747
  * @returns Either `{ success: true, data, errors: {} }` or `{ success: false, errors }`.
@@ -22381,6 +22848,12 @@ export declare function writeXlsx(headers: readonly string[], rows: readonly (re
22381
22848
  * `ResolverOptions` is accepted and ignored, because react-hook-form always
22382
22849
  * passes the whole object.
22383
22850
  *
22851
+ * Errors are written as **own** properties and checked with `hasOwnProperty`.
22852
+ * A plain `errors[path]` read saw `Object.prototype.constructor` for a field
22853
+ * named `constructor`, so `firstError` mode kept the inherited function instead
22854
+ * of the message, and an issue a `superRefine` files under `__proto__` replaced
22855
+ * the map's prototype instead of adding the field.
22856
+ *
22384
22857
  * @example
22385
22858
  * const form = useForm<LoginForm>({ resolver: zodResolver(loginSchema) });
22386
22859
  */