talizen 0.2.13 → 0.2.14

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.
package/README.md CHANGED
@@ -120,6 +120,7 @@ import {
120
120
  logout,
121
121
  register,
122
122
  updateProfile,
123
+ useAuth,
123
124
  } from "talizen/auth";
124
125
 
125
126
  await register({
@@ -140,6 +141,13 @@ const providers = await listAuthProviders();
140
141
  console.log(providers.map((provider) => provider.key));
141
142
 
142
143
  await loginWithOAuth("github", { redirectUrl: "/account" });
144
+
145
+ function AccountBadge() {
146
+ const { user, loading, logout } = useAuth();
147
+ if (loading) return <span>Loading...</span>;
148
+ if (!user) return <a href="/login">Sign in</a>;
149
+ return <button onClick={() => logout()}>{user.name ?? user.account ?? "Logout"}</button>;
150
+ }
143
151
  ```
144
152
 
145
153
  ### Invoke a custom function
package/auth.d.ts CHANGED
@@ -54,6 +54,23 @@ export declare class TalizenAuthError extends Error {
54
54
  }
55
55
  export declare function register(input: AuthRegisterInput, options?: TalizenRequestOptions): Promise<AuthUser>;
56
56
  export declare function login(input: AuthPasswordInput, options?: TalizenRequestOptions): Promise<AuthUser>;
57
+ export interface UseAuthResult {
58
+ user: AuthUser | null;
59
+ loading: boolean;
60
+ error: unknown;
61
+ refresh(): Promise<AuthUser | null>;
62
+ login(input: AuthPasswordInput): Promise<AuthUser>;
63
+ register(input: AuthRegisterInput): Promise<AuthUser>;
64
+ logout(): Promise<void>;
65
+ updateProfile(profile: AuthProfile): Promise<AuthUser>;
66
+ }
67
+ /**
68
+ * Subscribe to the current auth user.
69
+ *
70
+ * The hook reloads `/auth/me` whenever `setTalizenConfig()` changes runtime
71
+ * config, which lets preview auth headers update the page without remounting.
72
+ */
73
+ export declare function useAuth(options?: TalizenRequestOptions): UseAuthResult;
57
74
  export declare function logout(options?: TalizenRequestOptions): Promise<void>;
58
75
  export declare function currentUser(options?: TalizenRequestOptions): Promise<AuthUser | null>;
59
76
  export declare function updateProfile(profile: AuthProfile, options?: TalizenRequestOptions): Promise<AuthUser>;
package/auth.js CHANGED
@@ -1,4 +1,5 @@
1
- import { requestJson, } from "./core.js";
1
+ import * as React from "react";
2
+ import { getTalizenConfig, requestJson, subscribeTalizenConfig, } from "./core.js";
2
3
  export class TalizenAuthError extends Error {
3
4
  constructor(message) {
4
5
  super(message);
@@ -17,6 +18,80 @@ export async function login(input, options) {
17
18
  body: JSON.stringify(input),
18
19
  }, options);
19
20
  }
21
+ function readAuthConfigSnapshot() {
22
+ return getTalizenConfig();
23
+ }
24
+ /**
25
+ * Subscribe to the current auth user.
26
+ *
27
+ * The hook reloads `/auth/me` whenever `setTalizenConfig()` changes runtime
28
+ * config, which lets preview auth headers update the page without remounting.
29
+ */
30
+ export function useAuth(options) {
31
+ const configSnapshot = React.useSyncExternalStore(subscribeTalizenConfig, readAuthConfigSnapshot, readAuthConfigSnapshot);
32
+ const optionsRef = React.useRef(options);
33
+ const requestIdRef = React.useRef(0);
34
+ const [state, setState] = React.useState({
35
+ user: null,
36
+ loading: true,
37
+ error: null,
38
+ });
39
+ React.useEffect(() => {
40
+ optionsRef.current = options;
41
+ }, [options]);
42
+ const refresh = React.useCallback(async () => {
43
+ const requestId = requestIdRef.current + 1;
44
+ requestIdRef.current = requestId;
45
+ setState(current => ({ ...current, loading: true, error: null }));
46
+ try {
47
+ const nextUser = await currentUser(optionsRef.current);
48
+ if (requestIdRef.current === requestId) {
49
+ setState({ user: nextUser, loading: false, error: null });
50
+ }
51
+ return nextUser;
52
+ }
53
+ catch (error) {
54
+ if (requestIdRef.current === requestId) {
55
+ setState(current => ({ ...current, loading: false, error }));
56
+ }
57
+ throw error;
58
+ }
59
+ }, []);
60
+ React.useEffect(() => {
61
+ void refresh().catch(() => { });
62
+ }, [configSnapshot, refresh]);
63
+ const loginAndRefresh = React.useCallback(async (input) => {
64
+ const nextUser = await login(input, optionsRef.current);
65
+ requestIdRef.current += 1;
66
+ setState({ user: nextUser, loading: false, error: null });
67
+ return nextUser;
68
+ }, []);
69
+ const registerAndRefresh = React.useCallback(async (input) => {
70
+ const nextUser = await register(input, optionsRef.current);
71
+ requestIdRef.current += 1;
72
+ setState({ user: nextUser, loading: false, error: null });
73
+ return nextUser;
74
+ }, []);
75
+ const logoutAndRefresh = React.useCallback(async () => {
76
+ await logout(optionsRef.current);
77
+ requestIdRef.current += 1;
78
+ setState({ user: null, loading: false, error: null });
79
+ }, []);
80
+ const updateProfileAndRefresh = React.useCallback(async (profile) => {
81
+ const nextUser = await updateProfile(profile, optionsRef.current);
82
+ requestIdRef.current += 1;
83
+ setState({ user: nextUser, loading: false, error: null });
84
+ return nextUser;
85
+ }, []);
86
+ return {
87
+ ...state,
88
+ refresh,
89
+ login: loginAndRefresh,
90
+ register: registerAndRefresh,
91
+ logout: logoutAndRefresh,
92
+ updateProfile: updateProfileAndRefresh,
93
+ };
94
+ }
20
95
  export async function logout(options) {
21
96
  await requestJson("/auth/logout", {
22
97
  method: "POST",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "talizen",
3
- "version": "0.2.13",
3
+ "version": "0.2.14",
4
4
  "description": "Talizen frontend SDK types for cms, form and core.",
5
5
  "type": "module",
6
6
  "license": "MIT",