@sanity/sdk-react 3.3.0 → 3.4.0-rc.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.
@@ -0,0 +1,95 @@
1
+ import {
2
+ getOAuthTokensState,
3
+ type OAuthTokens,
4
+ refreshOAuthTokens,
5
+ revokeOAuthTokens,
6
+ } from '@sanity/sdk'
7
+
8
+ import {createCallbackHook} from '../helpers/createCallbackHook'
9
+ import {createStateSourceHook} from '../helpers/createStateSourceHook'
10
+
11
+ /**
12
+ * The current OAuth token state, plus actions to refresh and revoke it.
13
+ *
14
+ * @public
15
+ */
16
+ export interface UseOAuthTokensResult {
17
+ /** The stored OAuth tokens, or `null` when not logged in via OAuth */
18
+ tokens: OAuthTokens | null
19
+ /**
20
+ * Returns whether the access token has expired, comparing `expiresAt` against
21
+ * the current time at the moment it is called. Reading the clock does not
22
+ * trigger a re-render, so call this in an event handler or effect rather than
23
+ * during render. Returns `false` when there are no tokens.
24
+ */
25
+ isExpired: () => boolean
26
+ /**
27
+ * Refresh via the OAuth `refresh_token` grant. When there is no refresh token,
28
+ * core clears the stored tokens, logs the user out, and this resolves `null`.
29
+ * Rejects on transient failures (network, 5xx, 408, 429), leaving tokens
30
+ * unchanged so the call can be retried. Also rejects when the server rejects
31
+ * the refresh token itself (other 4xx); core clears the tokens and logs out
32
+ * first, so check `tokens` before retrying.
33
+ */
34
+ refresh: () => Promise<OAuthTokens | null>
35
+ /** Revoke the tokens at the OAuth server, clear them locally, and log out. */
36
+ revoke: () => Promise<void>
37
+ }
38
+
39
+ const useOAuthTokensState = createStateSourceHook(getOAuthTokensState)
40
+ const useRefreshOAuthTokens = createCallbackHook(refreshOAuthTokens)
41
+ const useRevokeOAuthTokens = createCallbackHook(revokeOAuthTokens)
42
+
43
+ function isOAuthTokenExpired(tokens: OAuthTokens | null): boolean {
44
+ return tokens ? tokens.expiresAt.getTime() <= Date.now() : false
45
+ }
46
+
47
+ /**
48
+ * A React hook that exposes the stored OAuth token state along with `refresh`
49
+ * and `revoke` actions.
50
+ *
51
+ * @remarks
52
+ * The token view is a synchronous read over core's token state source, so the
53
+ * hook re-renders whenever tokens change — including changes made in another
54
+ * tab, which core propagates via `storage` events.
55
+ *
56
+ * @returns The current {@link UseOAuthTokensResult}
57
+ *
58
+ * @example
59
+ * ```tsx
60
+ * function TokenStatus() {
61
+ * const {tokens, isExpired, refresh, revoke} = useOAuthTokens()
62
+ *
63
+ * if (!tokens) return <div>Not signed in</div>
64
+ *
65
+ * const handleRefresh = async () => {
66
+ * if (!isExpired()) return
67
+ * try {
68
+ * await refresh()
69
+ * } catch {
70
+ * // Transient failure (tokens unchanged, retry later) or the refresh
71
+ * // token was rejected (tokens now null, user is logged out).
72
+ * }
73
+ * }
74
+ *
75
+ * return (
76
+ * <div>
77
+ * <p>Expires at {tokens.expiresAt.toLocaleTimeString()}</p>
78
+ * <button onClick={handleRefresh}>Refresh if expired</button>
79
+ * <button onClick={() => revoke()}>Revoke tokens</button>
80
+ * </div>
81
+ * )
82
+ * }
83
+ * ```
84
+ *
85
+ * @public
86
+ */
87
+ export function useOAuthTokens(): UseOAuthTokensResult {
88
+ const tokens = useOAuthTokensState()
89
+ return {
90
+ tokens,
91
+ isExpired: () => isOAuthTokenExpired(tokens),
92
+ refresh: useRefreshOAuthTokens(),
93
+ revoke: useRevokeOAuthTokens(),
94
+ }
95
+ }