@leisuresaas/react 0.1.1 → 0.1.2-dev.2
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 +1 -1
- package/package.json +1 -1
- package/src/auth-provider.tsx +27 -22
- package/src/auth.ts +46 -11
- package/src/index.ts +14 -2
- package/src/oauth.ts +3 -3
package/README.md
CHANGED
package/package.json
CHANGED
package/src/auth-provider.tsx
CHANGED
|
@@ -3,43 +3,43 @@
|
|
|
3
3
|
import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from "react";
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
type
|
|
6
|
+
login,
|
|
7
|
+
logout,
|
|
8
|
+
refreshSession,
|
|
9
|
+
register,
|
|
10
|
+
type AuthTokens,
|
|
11
11
|
type PublicAuthContext,
|
|
12
12
|
} from "./auth";
|
|
13
13
|
import { accessNeedsRefresh } from "./oauth";
|
|
14
14
|
|
|
15
15
|
const STORAGE_KEY = "leisuresaas_product_session";
|
|
16
16
|
|
|
17
|
-
type
|
|
18
|
-
tokens:
|
|
17
|
+
type AuthState = {
|
|
18
|
+
tokens: AuthTokens | null;
|
|
19
19
|
ready: boolean;
|
|
20
20
|
login: (input: { email: string; password: string }) => Promise<void>;
|
|
21
21
|
register: (input: { email: string; password: string; name?: string }) => Promise<{ verificationRequired: boolean }>;
|
|
22
22
|
logout: () => Promise<void>;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
const
|
|
25
|
+
const AuthContext = createContext<AuthState | null>(null);
|
|
26
26
|
|
|
27
|
-
function readStored():
|
|
27
|
+
function readStored(): AuthTokens | null {
|
|
28
28
|
if (typeof sessionStorage === "undefined") return null;
|
|
29
29
|
const raw = sessionStorage.getItem(STORAGE_KEY);
|
|
30
30
|
if (!raw) return null;
|
|
31
31
|
try {
|
|
32
|
-
return JSON.parse(raw) as
|
|
32
|
+
return JSON.parse(raw) as AuthTokens;
|
|
33
33
|
} catch {
|
|
34
34
|
return null;
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export function
|
|
39
|
-
const [tokens, setTokens] = useState<
|
|
38
|
+
export function AuthProvider({ context, children }: { context: PublicAuthContext; children: ReactNode }) {
|
|
39
|
+
const [tokens, setTokens] = useState<AuthTokens | null>(null);
|
|
40
40
|
const [ready, setReady] = useState(false);
|
|
41
41
|
|
|
42
|
-
const persist = useCallback((next:
|
|
42
|
+
const persist = useCallback((next: AuthTokens | null) => {
|
|
43
43
|
setTokens(next);
|
|
44
44
|
if (typeof sessionStorage === "undefined") return;
|
|
45
45
|
if (!next) sessionStorage.removeItem(STORAGE_KEY);
|
|
@@ -57,34 +57,39 @@ export function ProductAuthProvider({ context, children }: { context: PublicAuth
|
|
|
57
57
|
setReady(true);
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
60
|
-
void
|
|
60
|
+
void refreshSession(context, stored.refreshToken)
|
|
61
61
|
.then((next) => persist(next))
|
|
62
62
|
.catch(() => persist(null))
|
|
63
63
|
.finally(() => setReady(true));
|
|
64
64
|
}, [context, persist]);
|
|
65
65
|
|
|
66
|
-
const value = useMemo<
|
|
66
|
+
const value = useMemo<AuthState>(() => ({
|
|
67
67
|
tokens,
|
|
68
68
|
ready,
|
|
69
69
|
login: async (input) => {
|
|
70
|
-
persist(await
|
|
70
|
+
persist(await login(context, input));
|
|
71
71
|
},
|
|
72
|
-
register: async (input) =>
|
|
72
|
+
register: async (input) => register(context, input),
|
|
73
73
|
logout: async () => {
|
|
74
74
|
if (tokens?.accessToken) {
|
|
75
|
-
await
|
|
75
|
+
await logout(context, tokens.accessToken, tokens.refreshToken).catch(() => undefined);
|
|
76
76
|
}
|
|
77
77
|
persist(null);
|
|
78
78
|
},
|
|
79
79
|
}), [tokens, ready, context, persist]);
|
|
80
80
|
|
|
81
|
-
return <
|
|
81
|
+
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
export function
|
|
85
|
-
const ctx = useContext(
|
|
84
|
+
export function useAuth(): AuthState {
|
|
85
|
+
const ctx = useContext(AuthContext);
|
|
86
86
|
if (!ctx) {
|
|
87
|
-
throw new Error("
|
|
87
|
+
throw new Error("useAuth must be used within AuthProvider");
|
|
88
88
|
}
|
|
89
89
|
return ctx;
|
|
90
90
|
}
|
|
91
|
+
|
|
92
|
+
/** @deprecated Use AuthProvider. */
|
|
93
|
+
export const ProductAuthProvider = AuthProvider;
|
|
94
|
+
/** @deprecated Use useAuth. */
|
|
95
|
+
export const useProductAuth = useAuth;
|
package/src/auth.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type PublicAuthContext = {
|
|
|
10
10
|
origin: string;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
export type
|
|
13
|
+
export type AuthTokens = {
|
|
14
14
|
accessToken: string;
|
|
15
15
|
refreshToken: string;
|
|
16
16
|
accessExpiresAtUnix: number;
|
|
@@ -70,7 +70,7 @@ async function publicAuthRequest<T>(
|
|
|
70
70
|
return JSON.parse(text) as T;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
function tokensFromJSON(data: TokenJSON):
|
|
73
|
+
function tokensFromJSON(data: TokenJSON): AuthTokens {
|
|
74
74
|
const accessToken = data.access_token?.trim() ?? "";
|
|
75
75
|
if (!accessToken) {
|
|
76
76
|
throw new LeisureSaasHttpError(502, "missing access_token");
|
|
@@ -85,7 +85,7 @@ function tokensFromJSON(data: TokenJSON): ProductAuthTokens {
|
|
|
85
85
|
};
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
export async function
|
|
88
|
+
export async function register(
|
|
89
89
|
ctx: PublicAuthContext,
|
|
90
90
|
input: { email: string; password: string; name?: string; locale?: string },
|
|
91
91
|
): Promise<{ verificationRequired: boolean }> {
|
|
@@ -95,36 +95,48 @@ export async function registerProductAccount(
|
|
|
95
95
|
return { verificationRequired: resp.verification_required !== false };
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
export async function
|
|
98
|
+
export async function login(
|
|
99
99
|
ctx: PublicAuthContext,
|
|
100
100
|
input: { email: string; password: string; locale?: string },
|
|
101
|
-
): Promise<
|
|
101
|
+
): Promise<AuthTokens> {
|
|
102
102
|
const resp = await publicAuthRequest<TokenJSON>(ctx, "/login", {
|
|
103
103
|
email: input.email, password: input.password, locale: input.locale ?? "",
|
|
104
104
|
});
|
|
105
105
|
return tokensFromJSON(resp);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
export async function
|
|
108
|
+
export async function refreshSession(ctx: PublicAuthContext, refreshToken: string): Promise<AuthTokens> {
|
|
109
109
|
const resp = await publicAuthRequest<TokenJSON>(ctx, "/refresh", { refresh_token: refreshToken });
|
|
110
110
|
return tokensFromJSON(resp);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
export async function
|
|
113
|
+
export async function requestPasswordReset(
|
|
114
114
|
ctx: PublicAuthContext,
|
|
115
115
|
input: { email: string; locale?: string },
|
|
116
116
|
): Promise<void> {
|
|
117
117
|
await publicAuthRequest(ctx, "/password-reset", { email: input.email, locale: input.locale ?? "" });
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
export async function
|
|
120
|
+
export async function requestEmailVerification(
|
|
121
121
|
ctx: PublicAuthContext,
|
|
122
122
|
input: { email: string; locale?: string },
|
|
123
123
|
): Promise<void> {
|
|
124
124
|
await publicAuthRequest(ctx, "/email-verification", { email: input.email, locale: input.locale ?? "" });
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
export async function
|
|
127
|
+
export async function confirmEmailVerification(ctx: PublicAuthContext, token: string): Promise<AuthTokens> {
|
|
128
|
+
const resp = await publicAuthRequest<TokenJSON>(ctx, "/email-verification/confirm", { token });
|
|
129
|
+
return tokensFromJSON(resp);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export async function confirmPasswordReset(
|
|
133
|
+
ctx: PublicAuthContext,
|
|
134
|
+
input: { token: string; newPassword: string },
|
|
135
|
+
): Promise<void> {
|
|
136
|
+
await publicAuthRequest(ctx, "/password-reset/confirm", { token: input.token, new_password: input.newPassword });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export async function changePassword(
|
|
128
140
|
ctx: PublicAuthContext,
|
|
129
141
|
accessToken: string,
|
|
130
142
|
input: { currentPassword: string; newPassword: string },
|
|
@@ -134,7 +146,7 @@ export async function changeProductPassword(
|
|
|
134
146
|
}, accessToken);
|
|
135
147
|
}
|
|
136
148
|
|
|
137
|
-
export async function
|
|
149
|
+
export async function logout(
|
|
138
150
|
ctx: PublicAuthContext,
|
|
139
151
|
accessToken: string,
|
|
140
152
|
refreshToken?: string,
|
|
@@ -142,7 +154,7 @@ export async function logoutProductAccount(
|
|
|
142
154
|
await publicAuthRequest(ctx, "/logout", { refresh_token: refreshToken ?? "" }, accessToken);
|
|
143
155
|
}
|
|
144
156
|
|
|
145
|
-
export async function
|
|
157
|
+
export async function deleteAccount(ctx: PublicAuthContext, accessToken: string): Promise<void> {
|
|
146
158
|
await publicAuthRequest(ctx, "/account/delete", {}, accessToken);
|
|
147
159
|
}
|
|
148
160
|
|
|
@@ -175,3 +187,26 @@ export async function bindPlatformAccount(
|
|
|
175
187
|
export async function unbindPlatformAccount(ctx: PublicAuthContext, accessToken: string): Promise<void> {
|
|
176
188
|
await publicAuthRequest(ctx, "/unbind", {}, accessToken);
|
|
177
189
|
}
|
|
190
|
+
|
|
191
|
+
/** @deprecated Use AuthTokens. */
|
|
192
|
+
export type ProductAuthTokens = AuthTokens;
|
|
193
|
+
/** @deprecated Use register. */
|
|
194
|
+
export const registerProductAccount = register;
|
|
195
|
+
/** @deprecated Use login. */
|
|
196
|
+
export const loginProductAccount = login;
|
|
197
|
+
/** @deprecated Use logout. */
|
|
198
|
+
export const logoutProductAccount = logout;
|
|
199
|
+
/** @deprecated Use refreshSession. */
|
|
200
|
+
export const refreshProductSession = refreshSession;
|
|
201
|
+
/** @deprecated Use deleteAccount. */
|
|
202
|
+
export const deleteProductAccount = deleteAccount;
|
|
203
|
+
/** @deprecated Use changePassword. */
|
|
204
|
+
export const changeProductPassword = changePassword;
|
|
205
|
+
/** @deprecated Use requestPasswordReset. */
|
|
206
|
+
export const requestProductPasswordReset = requestPasswordReset;
|
|
207
|
+
/** @deprecated Use confirmPasswordReset. */
|
|
208
|
+
export const confirmProductPasswordReset = confirmPasswordReset;
|
|
209
|
+
/** @deprecated Use requestEmailVerification. */
|
|
210
|
+
export const requestProductEmailVerification = requestEmailVerification;
|
|
211
|
+
/** @deprecated Use confirmEmailVerification. */
|
|
212
|
+
export const confirmProductEmailVerification = confirmEmailVerification;
|
package/src/index.ts
CHANGED
|
@@ -6,19 +6,31 @@ export type { ResolvePlatformApiBaseOptions } from "./platform-api-base";
|
|
|
6
6
|
|
|
7
7
|
export {
|
|
8
8
|
bindPlatformAccount,
|
|
9
|
+
changePassword,
|
|
9
10
|
changeProductPassword,
|
|
11
|
+
confirmEmailVerification,
|
|
12
|
+
confirmPasswordReset,
|
|
13
|
+
confirmProductEmailVerification,
|
|
14
|
+
confirmProductPasswordReset,
|
|
15
|
+
deleteAccount,
|
|
10
16
|
deleteProductAccount,
|
|
17
|
+
login,
|
|
11
18
|
loginProductAccount,
|
|
19
|
+
logout,
|
|
12
20
|
logoutProductAccount,
|
|
13
21
|
refreshProductSession,
|
|
22
|
+
refreshSession,
|
|
23
|
+
register,
|
|
14
24
|
registerProductAccount,
|
|
25
|
+
requestEmailVerification,
|
|
26
|
+
requestPasswordReset,
|
|
15
27
|
requestProductEmailVerification,
|
|
16
28
|
requestProductPasswordReset,
|
|
17
29
|
startPlatformAuthorize,
|
|
18
30
|
unbindPlatformAccount,
|
|
19
31
|
} from "./auth";
|
|
20
|
-
export type { ProductAuthTokens, PublicAuthContext } from "./auth";
|
|
21
|
-
export { ProductAuthProvider, useProductAuth } from "./auth-provider";
|
|
32
|
+
export type { AuthTokens, ProductAuthTokens, PublicAuthContext } from "./auth";
|
|
33
|
+
export { AuthProvider, ProductAuthProvider, useAuth, useProductAuth } from "./auth-provider";
|
|
22
34
|
|
|
23
35
|
export {
|
|
24
36
|
accessNeedsRefresh,
|
package/src/oauth.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { startPlatformAuthorize, type
|
|
1
|
+
import { startPlatformAuthorize, type AuthTokens, type PublicAuthContext } from "./auth";
|
|
2
2
|
|
|
3
3
|
const REFRESH_SKEW_SEC = 60;
|
|
4
4
|
|
|
@@ -214,7 +214,7 @@ function jwtClaims(accessToken: string): Record<string, unknown> {
|
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
export function productTokensFromOAuth(tokens: OAuthTokenResponse):
|
|
217
|
+
export function productTokensFromOAuth(tokens: OAuthTokenResponse): AuthTokens {
|
|
218
218
|
const now = Math.floor(Date.now() / 1000);
|
|
219
219
|
const claims = jwtClaims(tokens.accessToken);
|
|
220
220
|
return {
|
|
@@ -248,7 +248,7 @@ export async function completePlatformLogin(input: {
|
|
|
248
248
|
code: string;
|
|
249
249
|
redirectUri: string;
|
|
250
250
|
verifier: string;
|
|
251
|
-
}): Promise<
|
|
251
|
+
}): Promise<AuthTokens> {
|
|
252
252
|
const authorize = new URL(input.authorizationUrl);
|
|
253
253
|
const clientId = authorize.searchParams.get("client_id")?.trim() ?? "";
|
|
254
254
|
const issuer = `${authorize.protocol}//${authorize.host}`;
|