rystem.authentication.social.client 0.5.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.
- package/README.md +1903 -0
- package/lib/buttons/CreateSocialButton.d.ts +15 -0
- package/lib/buttons/CreateSocialButton.js +158 -0
- package/lib/buttons/SocialLoginButtons.d.ts +2 -0
- package/lib/buttons/SocialLoginButtons.js +22 -0
- package/lib/buttons/SocialLogoutButton.d.ts +3 -0
- package/lib/buttons/SocialLogoutButton.js +11 -0
- package/lib/buttons/graphics/AmazonLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/AmazonLoginButton.js +10 -0
- package/lib/buttons/graphics/AppleLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/AppleLoginButton.js +17 -0
- package/lib/buttons/graphics/BufferLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/BufferLoginButton.js +17 -0
- package/lib/buttons/graphics/DiscordLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/DiscordLoginButton.js +17 -0
- package/lib/buttons/graphics/FacebookLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/FacebookLoginButton.js +10 -0
- package/lib/buttons/graphics/GithubLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/GithubLoginButton.js +10 -0
- package/lib/buttons/graphics/GoogleLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/GoogleLoginButton.js +10 -0
- package/lib/buttons/graphics/InstagramLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/InstagramLoginButton.js +10 -0
- package/lib/buttons/graphics/LinkedInLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/LinkedInLoginButton.js +10 -0
- package/lib/buttons/graphics/MetamaskLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/MetamaskLoginButton.js +25 -0
- package/lib/buttons/graphics/MicrosoftLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/MicrosoftLoginButton.js +10 -0
- package/lib/buttons/graphics/OktaLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/OktaLoginButton.js +17 -0
- package/lib/buttons/graphics/PinterestLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/PinterestLoginButton.js +10 -0
- package/lib/buttons/graphics/SlackLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/SlackLoginButton.js +17 -0
- package/lib/buttons/graphics/SocialButtonStyle.d.ts +8 -0
- package/lib/buttons/graphics/SocialButtonStyle.js +2 -0
- package/lib/buttons/graphics/SocialLoginButton.d.ts +2 -0
- package/lib/buttons/graphics/SocialLoginButton.js +46 -0
- package/lib/buttons/graphics/TelegramLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/TelegramLoginButton.js +17 -0
- package/lib/buttons/graphics/TikTokLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/TikTokLoginButton.js +10 -0
- package/lib/buttons/graphics/XLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/XLoginButton.js +10 -0
- package/lib/buttons/graphics/YahooLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/YahooLoginButton.js +17 -0
- package/lib/buttons/graphics/ZaloLoginButton.d.ts +1 -0
- package/lib/buttons/graphics/ZaloLoginButton.js +17 -0
- package/lib/buttons/singles/AmazonButton.d.ts +2 -0
- package/lib/buttons/singles/AmazonButton.js +33 -0
- package/lib/buttons/singles/FacebookButton.d.ts +2 -0
- package/lib/buttons/singles/FacebookButton.js +55 -0
- package/lib/buttons/singles/GitHubButton.d.ts +2 -0
- package/lib/buttons/singles/GitHubButton.js +19 -0
- package/lib/buttons/singles/GoogleButton.d.ts +2 -0
- package/lib/buttons/singles/GoogleButton.js +44 -0
- package/lib/buttons/singles/InstagramButton.d.ts +2 -0
- package/lib/buttons/singles/InstagramButton.js +21 -0
- package/lib/buttons/singles/LinkedinButton.d.ts +2 -0
- package/lib/buttons/singles/LinkedinButton.js +23 -0
- package/lib/buttons/singles/MicrosoftButton.d.ts +2 -0
- package/lib/buttons/singles/MicrosoftButton.js +68 -0
- package/lib/buttons/singles/PinterestButton.d.ts +2 -0
- package/lib/buttons/singles/PinterestButton.js +22 -0
- package/lib/buttons/singles/TikTokButton.d.ts +2 -0
- package/lib/buttons/singles/TikTokButton.js +18 -0
- package/lib/buttons/singles/XButton.d.ts +2 -0
- package/lib/buttons/singles/XButton.js +24 -0
- package/lib/components/BrandIcons.d.ts +64 -0
- package/lib/components/BrandIcons.js +76 -0
- package/lib/components/ModernSocialButton.d.ts +21 -0
- package/lib/components/ModernSocialButton.js +23 -0
- package/lib/context/SocialLoginContext.d.ts +4 -0
- package/lib/context/SocialLoginContext.js +10 -0
- package/lib/context/SocialLoginWrapper.d.ts +3 -0
- package/lib/context/SocialLoginWrapper.js +137 -0
- package/lib/hooks/removeSocialLogin.d.ts +1 -0
- package/lib/hooks/removeSocialLogin.js +14 -0
- package/lib/hooks/useSocialToken.d.ts +2 -0
- package/lib/hooks/useSocialToken.js +21 -0
- package/lib/hooks/useSocialUser.d.ts +2 -0
- package/lib/hooks/useSocialUser.js +30 -0
- package/lib/index.d.ts +47 -0
- package/lib/index.js +90 -0
- package/lib/models/SocialButtonProps.d.ts +3 -0
- package/lib/models/SocialButtonProps.js +2 -0
- package/lib/models/SocialButtonsProps.d.ts +4 -0
- package/lib/models/SocialButtonsProps.js +2 -0
- package/lib/models/SocialToken.d.ts +6 -0
- package/lib/models/SocialToken.js +2 -0
- package/lib/models/SocialUser.d.ts +5 -0
- package/lib/models/SocialUser.js +2 -0
- package/lib/models/Token.d.ts +6 -0
- package/lib/models/Token.js +2 -0
- package/lib/models/setup/LoginMode.d.ts +13 -0
- package/lib/models/setup/LoginMode.js +17 -0
- package/lib/models/setup/PlatformConfig.d.ts +45 -0
- package/lib/models/setup/PlatformConfig.js +19 -0
- package/lib/models/setup/PlatformType.d.ts +21 -0
- package/lib/models/setup/PlatformType.js +25 -0
- package/lib/models/setup/ProviderType.d.ts +13 -0
- package/lib/models/setup/ProviderType.js +17 -0
- package/lib/models/setup/SocialLoginErrorResponse.d.ts +6 -0
- package/lib/models/setup/SocialLoginErrorResponse.js +2 -0
- package/lib/models/setup/SocialLoginSettings.d.ts +66 -0
- package/lib/models/setup/SocialLoginSettings.js +2 -0
- package/lib/models/setup/SocialParameter.d.ts +3 -0
- package/lib/models/setup/SocialParameter.js +2 -0
- package/lib/services/IRoutingService.d.ts +123 -0
- package/lib/services/IRoutingService.js +2 -0
- package/lib/services/IStorageService.d.ts +33 -0
- package/lib/services/IStorageService.js +2 -0
- package/lib/services/LocalStorageService.d.ts +32 -0
- package/lib/services/LocalStorageService.js +93 -0
- package/lib/services/MockRoutingService.example.d.ts +96 -0
- package/lib/services/MockRoutingService.example.js +153 -0
- package/lib/services/NextAppRouterRoutingService.example.d.ts +75 -0
- package/lib/services/NextAppRouterRoutingService.example.js +128 -0
- package/lib/services/PkceStorageService.d.ts +55 -0
- package/lib/services/PkceStorageService.js +103 -0
- package/lib/services/ReactRouterRoutingService.example.d.ts +69 -0
- package/lib/services/ReactRouterRoutingService.example.js +121 -0
- package/lib/services/TokenStorageService.d.ts +34 -0
- package/lib/services/TokenStorageService.js +90 -0
- package/lib/services/UserStorageService.d.ts +29 -0
- package/lib/services/UserStorageService.js +56 -0
- package/lib/services/WindowRoutingService.d.ts +74 -0
- package/lib/services/WindowRoutingService.js +118 -0
- package/lib/setup/SocialLoginManager.d.ts +12 -0
- package/lib/setup/SocialLoginManager.js +106 -0
- package/lib/setup/getSocialLoginSettings.d.ts +2 -0
- package/lib/setup/getSocialLoginSettings.js +8 -0
- package/lib/setup/setupSocialLogin.d.ts +2 -0
- package/lib/setup/setupSocialLogin.js +62 -0
- package/lib/styles/SocialButton.css +365 -0
- package/lib/utils/pkce.d.ts +18 -0
- package/lib/utils/pkce.js +44 -0
- package/lib/utils/platform.d.ts +30 -0
- package/lib/utils/platform.js +103 -0
- package/package.json +45 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Unified Routing Service for Next.js App Router (v13+)
|
|
4
|
+
*
|
|
5
|
+
* This service handles both URL parameter reading and navigation for Next.js with App Router.
|
|
6
|
+
* Copy this file to your project and remove the `.example` extension.
|
|
7
|
+
*
|
|
8
|
+
* IMPORTANT: This must be used in Client Components ('use client')
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* 'use client';
|
|
13
|
+
*
|
|
14
|
+
* import { NextAppRouterRoutingService } from './NextAppRouterRoutingService';
|
|
15
|
+
* import { useRouter, usePathname, useSearchParams } from 'next/navigation';
|
|
16
|
+
*
|
|
17
|
+
* const routingService = new NextAppRouterRoutingService();
|
|
18
|
+
*
|
|
19
|
+
* setupSocialLogin(x => {
|
|
20
|
+
* x.routingService = routingService;
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* export default function LoginPage() {
|
|
24
|
+
* const router = useRouter();
|
|
25
|
+
* const pathname = usePathname();
|
|
26
|
+
* const searchParams = useSearchParams();
|
|
27
|
+
*
|
|
28
|
+
* useEffect(() => {
|
|
29
|
+
* // Single initialization with all hooks
|
|
30
|
+
* routingService.initialize(router, pathname, searchParams);
|
|
31
|
+
* }, [router, pathname, searchParams]);
|
|
32
|
+
*
|
|
33
|
+
* return <div>Your login page</div>;
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.NextAppRouterRoutingService = void 0;
|
|
39
|
+
/**
|
|
40
|
+
* Routing Service for Next.js App Router (v13+)
|
|
41
|
+
* Uses useRouter, usePathname, and useSearchParams from next/navigation
|
|
42
|
+
*
|
|
43
|
+
* NOTE: Only works in Client Components ('use client' directive required)
|
|
44
|
+
*/
|
|
45
|
+
class NextAppRouterRoutingService {
|
|
46
|
+
router = null;
|
|
47
|
+
pathname = null;
|
|
48
|
+
searchParams = null;
|
|
49
|
+
/**
|
|
50
|
+
* Initialize with Next.js navigation hooks
|
|
51
|
+
* MUST be called inside a Client Component ('use client')
|
|
52
|
+
*
|
|
53
|
+
* @param router - The router from useRouter() hook
|
|
54
|
+
* @param pathname - The pathname from usePathname() hook
|
|
55
|
+
* @param searchParams - The searchParams from useSearchParams() hook
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* 'use client';
|
|
60
|
+
*
|
|
61
|
+
* const router = useRouter();
|
|
62
|
+
* const pathname = usePathname();
|
|
63
|
+
* const searchParams = useSearchParams();
|
|
64
|
+
*
|
|
65
|
+
* useEffect(() => {
|
|
66
|
+
* routingService.initialize(router, pathname, searchParams);
|
|
67
|
+
* }, [router, pathname, searchParams]);
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
initialize(router, pathname, searchParams) {
|
|
71
|
+
this.router = router;
|
|
72
|
+
this.pathname = pathname;
|
|
73
|
+
this.searchParams = searchParams;
|
|
74
|
+
}
|
|
75
|
+
// ===== URL Parameter Reading =====
|
|
76
|
+
getSearchParam(key) {
|
|
77
|
+
if (!this.searchParams) {
|
|
78
|
+
console.warn('NextAppRouterRoutingService not initialized. Call initialize() with Next.js hooks.');
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return this.searchParams.get(key);
|
|
82
|
+
}
|
|
83
|
+
getAllSearchParams() {
|
|
84
|
+
if (!this.searchParams) {
|
|
85
|
+
console.warn('NextAppRouterRoutingService not initialized. Call initialize() with Next.js hooks.');
|
|
86
|
+
return new URLSearchParams();
|
|
87
|
+
}
|
|
88
|
+
return this.searchParams;
|
|
89
|
+
}
|
|
90
|
+
// ===== Navigation Operations =====
|
|
91
|
+
getCurrentPath() {
|
|
92
|
+
if (!this.pathname) {
|
|
93
|
+
console.warn('NextAppRouterRoutingService not initialized. Falling back to window.location.');
|
|
94
|
+
return window.location.pathname + window.location.search;
|
|
95
|
+
}
|
|
96
|
+
const search = this.searchParams?.toString();
|
|
97
|
+
return search ? `${this.pathname}?${search}` : this.pathname;
|
|
98
|
+
}
|
|
99
|
+
navigateTo(url) {
|
|
100
|
+
// External OAuth redirects (https://...) must use window.location
|
|
101
|
+
if (url.startsWith('http://') || url.startsWith('https://')) {
|
|
102
|
+
console.log('🌐 [NextJS] External OAuth redirect, using window.location:', url);
|
|
103
|
+
window.location.href = url;
|
|
104
|
+
}
|
|
105
|
+
else if (this.router) {
|
|
106
|
+
console.log('🔄 [NextJS] Internal navigation:', url);
|
|
107
|
+
this.router.push(url);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
console.warn('NextAppRouterRoutingService not initialized. Using window.location.');
|
|
111
|
+
window.location.href = url;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
navigateReplace(path) {
|
|
115
|
+
if (this.router) {
|
|
116
|
+
console.log('🔄 [NextJS] Replacing URL:', path);
|
|
117
|
+
this.router.replace(path);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
console.warn('NextAppRouterRoutingService not initialized. Using window.history.');
|
|
121
|
+
window.history.replaceState({}, '', path);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
openPopup(url, name, features) {
|
|
125
|
+
return window.open(url, name, features);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.NextAppRouterRoutingService = NextAppRouterRoutingService;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { IStorageService } from "./IStorageService";
|
|
2
|
+
/**
|
|
3
|
+
* PKCE storage service (decorator pattern)
|
|
4
|
+
* Adds domain logic (key prefixes, validation) on top of generic storage
|
|
5
|
+
*/
|
|
6
|
+
export declare class PkceStorageService {
|
|
7
|
+
private storage;
|
|
8
|
+
private readonly prefix;
|
|
9
|
+
constructor(storage: IStorageService);
|
|
10
|
+
/**
|
|
11
|
+
* Store PKCE code verifier for a provider
|
|
12
|
+
* @param provider Provider name (microsoft, google, etc.)
|
|
13
|
+
* @param codeVerifier PKCE code verifier (43+ chars, Base64URL)
|
|
14
|
+
*/
|
|
15
|
+
storeCodeVerifier(provider: string, codeVerifier: string): void;
|
|
16
|
+
/**
|
|
17
|
+
* Get PKCE code verifier for a provider
|
|
18
|
+
* @param provider Provider name
|
|
19
|
+
* @returns Code verifier or null if not found/invalid
|
|
20
|
+
*/
|
|
21
|
+
getCodeVerifier(provider: string): string | null;
|
|
22
|
+
/**
|
|
23
|
+
* Get and remove PKCE code verifier (consume once)
|
|
24
|
+
* Used during token exchange to retrieve and cleanup
|
|
25
|
+
*/
|
|
26
|
+
getAndRemoveCodeVerifier(provider: string): string | null;
|
|
27
|
+
/**
|
|
28
|
+
* Remove PKCE code verifier for a provider
|
|
29
|
+
*/
|
|
30
|
+
removeCodeVerifier(provider: string): void;
|
|
31
|
+
/**
|
|
32
|
+
* Check if PKCE code verifier exists for a provider
|
|
33
|
+
*/
|
|
34
|
+
hasCodeVerifier(provider: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Store PKCE code challenge for a provider (optional, for debugging)
|
|
37
|
+
*/
|
|
38
|
+
storeCodeChallenge(provider: string, codeChallenge: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* Get PKCE code challenge for a provider
|
|
41
|
+
*/
|
|
42
|
+
getCodeChallenge(provider: string): string | null;
|
|
43
|
+
/**
|
|
44
|
+
* Remove PKCE code challenge for a provider
|
|
45
|
+
*/
|
|
46
|
+
removeCodeChallenge(provider: string): void;
|
|
47
|
+
/**
|
|
48
|
+
* Clear all PKCE data for a provider
|
|
49
|
+
*/
|
|
50
|
+
clearAll(provider: string): void;
|
|
51
|
+
/**
|
|
52
|
+
* Build storage key with prefix
|
|
53
|
+
*/
|
|
54
|
+
private getKey;
|
|
55
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PkceStorageService = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* PKCE storage service (decorator pattern)
|
|
6
|
+
* Adds domain logic (key prefixes, validation) on top of generic storage
|
|
7
|
+
*/
|
|
8
|
+
class PkceStorageService {
|
|
9
|
+
storage;
|
|
10
|
+
prefix = 'rystem_pkce_';
|
|
11
|
+
constructor(storage) {
|
|
12
|
+
this.storage = storage;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Store PKCE code verifier for a provider
|
|
16
|
+
* @param provider Provider name (microsoft, google, etc.)
|
|
17
|
+
* @param codeVerifier PKCE code verifier (43+ chars, Base64URL)
|
|
18
|
+
*/
|
|
19
|
+
storeCodeVerifier(provider, codeVerifier) {
|
|
20
|
+
if (!codeVerifier || codeVerifier.length < 43) {
|
|
21
|
+
console.warn(`PkceStorageService: Invalid code verifier for ${provider}`);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const key = this.getKey(provider, 'verifier');
|
|
25
|
+
this.storage.set(key, codeVerifier);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get PKCE code verifier for a provider
|
|
29
|
+
* @param provider Provider name
|
|
30
|
+
* @returns Code verifier or null if not found/invalid
|
|
31
|
+
*/
|
|
32
|
+
getCodeVerifier(provider) {
|
|
33
|
+
const key = this.getKey(provider, 'verifier');
|
|
34
|
+
const value = this.storage.get(key);
|
|
35
|
+
// Validation: PKCE verifier must be at least 43 characters (RFC 7636)
|
|
36
|
+
if (value && value.length < 43) {
|
|
37
|
+
console.warn(`PkceStorageService: Invalid code verifier for ${provider} (length: ${value.length})`);
|
|
38
|
+
this.removeCodeVerifier(provider);
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get and remove PKCE code verifier (consume once)
|
|
45
|
+
* Used during token exchange to retrieve and cleanup
|
|
46
|
+
*/
|
|
47
|
+
getAndRemoveCodeVerifier(provider) {
|
|
48
|
+
const verifier = this.getCodeVerifier(provider);
|
|
49
|
+
if (verifier) {
|
|
50
|
+
this.removeCodeVerifier(provider);
|
|
51
|
+
}
|
|
52
|
+
return verifier;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Remove PKCE code verifier for a provider
|
|
56
|
+
*/
|
|
57
|
+
removeCodeVerifier(provider) {
|
|
58
|
+
const key = this.getKey(provider, 'verifier');
|
|
59
|
+
this.storage.remove(key);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check if PKCE code verifier exists for a provider
|
|
63
|
+
*/
|
|
64
|
+
hasCodeVerifier(provider) {
|
|
65
|
+
const key = this.getKey(provider, 'verifier');
|
|
66
|
+
return this.storage.has(key);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Store PKCE code challenge for a provider (optional, for debugging)
|
|
70
|
+
*/
|
|
71
|
+
storeCodeChallenge(provider, codeChallenge) {
|
|
72
|
+
const key = this.getKey(provider, 'challenge');
|
|
73
|
+
this.storage.set(key, codeChallenge);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get PKCE code challenge for a provider
|
|
77
|
+
*/
|
|
78
|
+
getCodeChallenge(provider) {
|
|
79
|
+
const key = this.getKey(provider, 'challenge');
|
|
80
|
+
return this.storage.get(key);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Remove PKCE code challenge for a provider
|
|
84
|
+
*/
|
|
85
|
+
removeCodeChallenge(provider) {
|
|
86
|
+
const key = this.getKey(provider, 'challenge');
|
|
87
|
+
this.storage.remove(key);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Clear all PKCE data for a provider
|
|
91
|
+
*/
|
|
92
|
+
clearAll(provider) {
|
|
93
|
+
this.removeCodeVerifier(provider);
|
|
94
|
+
this.removeCodeChallenge(provider);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Build storage key with prefix
|
|
98
|
+
*/
|
|
99
|
+
getKey(provider, type) {
|
|
100
|
+
return `${this.prefix}${provider}_${type}`;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.PkceStorageService = PkceStorageService;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Routing Service for React Router v6+
|
|
3
|
+
*
|
|
4
|
+
* This service handles both URL parameter reading and navigation for React Router.
|
|
5
|
+
* Copy this file to your project and remove the `.example` extension.
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: Must be initialized inside a React component with routing context.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { ReactRouterRoutingService } from './ReactRouterRoutingService';
|
|
12
|
+
* import { useSearchParams, useNavigate, useLocation } from 'react-router-dom';
|
|
13
|
+
*
|
|
14
|
+
* const routingService = new ReactRouterRoutingService();
|
|
15
|
+
*
|
|
16
|
+
* setupSocialLogin(x => {
|
|
17
|
+
* x.routingService = routingService;
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* function App() {
|
|
21
|
+
* const [searchParams] = useSearchParams();
|
|
22
|
+
* const navigate = useNavigate();
|
|
23
|
+
* const location = useLocation();
|
|
24
|
+
*
|
|
25
|
+
* useEffect(() => {
|
|
26
|
+
* // Single initialization with all hooks
|
|
27
|
+
* routingService.initialize(() => searchParams, navigate, location);
|
|
28
|
+
* }, [searchParams, navigate, location]);
|
|
29
|
+
*
|
|
30
|
+
* return <div>Your app</div>;
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
import type { IRoutingService } from './IRoutingService';
|
|
35
|
+
/**
|
|
36
|
+
* Routing Service for React Router v6+
|
|
37
|
+
* Uses useSearchParams, useNavigate, and useLocation hooks
|
|
38
|
+
*/
|
|
39
|
+
export declare class ReactRouterRoutingService implements IRoutingService {
|
|
40
|
+
private searchParamsGetter;
|
|
41
|
+
private navigateFunc;
|
|
42
|
+
private location;
|
|
43
|
+
/**
|
|
44
|
+
* Initialize with React Router hooks
|
|
45
|
+
* MUST be called inside a React component with routing context
|
|
46
|
+
*
|
|
47
|
+
* @param searchParamsGetter - Function that returns URLSearchParams from useSearchParams()
|
|
48
|
+
* @param navigateFunc - The navigate function from useNavigate()
|
|
49
|
+
* @param location - The location object from useLocation()
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const [searchParams] = useSearchParams();
|
|
54
|
+
* const navigate = useNavigate();
|
|
55
|
+
* const location = useLocation();
|
|
56
|
+
*
|
|
57
|
+
* useEffect(() => {
|
|
58
|
+
* routingService.initialize(() => searchParams, navigate, location);
|
|
59
|
+
* }, [searchParams, navigate, location]);
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
initialize(searchParamsGetter: () => URLSearchParams, navigateFunc: (to: string, options?: any) => void, location: any): void;
|
|
63
|
+
getSearchParam(key: string): string | null;
|
|
64
|
+
getAllSearchParams(): URLSearchParams;
|
|
65
|
+
getCurrentPath(): string;
|
|
66
|
+
navigateTo(url: string): void;
|
|
67
|
+
navigateReplace(path: string): void;
|
|
68
|
+
openPopup(url: string, name: string, features: string): Window | null;
|
|
69
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Unified Routing Service for React Router v6+
|
|
4
|
+
*
|
|
5
|
+
* This service handles both URL parameter reading and navigation for React Router.
|
|
6
|
+
* Copy this file to your project and remove the `.example` extension.
|
|
7
|
+
*
|
|
8
|
+
* IMPORTANT: Must be initialized inside a React component with routing context.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { ReactRouterRoutingService } from './ReactRouterRoutingService';
|
|
13
|
+
* import { useSearchParams, useNavigate, useLocation } from 'react-router-dom';
|
|
14
|
+
*
|
|
15
|
+
* const routingService = new ReactRouterRoutingService();
|
|
16
|
+
*
|
|
17
|
+
* setupSocialLogin(x => {
|
|
18
|
+
* x.routingService = routingService;
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* function App() {
|
|
22
|
+
* const [searchParams] = useSearchParams();
|
|
23
|
+
* const navigate = useNavigate();
|
|
24
|
+
* const location = useLocation();
|
|
25
|
+
*
|
|
26
|
+
* useEffect(() => {
|
|
27
|
+
* // Single initialization with all hooks
|
|
28
|
+
* routingService.initialize(() => searchParams, navigate, location);
|
|
29
|
+
* }, [searchParams, navigate, location]);
|
|
30
|
+
*
|
|
31
|
+
* return <div>Your app</div>;
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ReactRouterRoutingService = void 0;
|
|
37
|
+
/**
|
|
38
|
+
* Routing Service for React Router v6+
|
|
39
|
+
* Uses useSearchParams, useNavigate, and useLocation hooks
|
|
40
|
+
*/
|
|
41
|
+
class ReactRouterRoutingService {
|
|
42
|
+
searchParamsGetter = null;
|
|
43
|
+
navigateFunc = null;
|
|
44
|
+
location = null;
|
|
45
|
+
/**
|
|
46
|
+
* Initialize with React Router hooks
|
|
47
|
+
* MUST be called inside a React component with routing context
|
|
48
|
+
*
|
|
49
|
+
* @param searchParamsGetter - Function that returns URLSearchParams from useSearchParams()
|
|
50
|
+
* @param navigateFunc - The navigate function from useNavigate()
|
|
51
|
+
* @param location - The location object from useLocation()
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const [searchParams] = useSearchParams();
|
|
56
|
+
* const navigate = useNavigate();
|
|
57
|
+
* const location = useLocation();
|
|
58
|
+
*
|
|
59
|
+
* useEffect(() => {
|
|
60
|
+
* routingService.initialize(() => searchParams, navigate, location);
|
|
61
|
+
* }, [searchParams, navigate, location]);
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
initialize(searchParamsGetter, navigateFunc, location) {
|
|
65
|
+
this.searchParamsGetter = searchParamsGetter;
|
|
66
|
+
this.navigateFunc = navigateFunc;
|
|
67
|
+
this.location = location;
|
|
68
|
+
}
|
|
69
|
+
// ===== URL Parameter Reading =====
|
|
70
|
+
getSearchParam(key) {
|
|
71
|
+
if (!this.searchParamsGetter) {
|
|
72
|
+
console.warn('ReactRouterRoutingService not initialized. Call initialize() with React Router hooks.');
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return this.searchParamsGetter().get(key);
|
|
76
|
+
}
|
|
77
|
+
getAllSearchParams() {
|
|
78
|
+
if (!this.searchParamsGetter) {
|
|
79
|
+
console.warn('ReactRouterRoutingService not initialized. Call initialize() with React Router hooks.');
|
|
80
|
+
return new URLSearchParams();
|
|
81
|
+
}
|
|
82
|
+
return this.searchParamsGetter();
|
|
83
|
+
}
|
|
84
|
+
// ===== Navigation Operations =====
|
|
85
|
+
getCurrentPath() {
|
|
86
|
+
if (!this.location) {
|
|
87
|
+
console.warn('ReactRouterRoutingService not initialized. Falling back to window.location.');
|
|
88
|
+
return window.location.pathname + window.location.search;
|
|
89
|
+
}
|
|
90
|
+
return this.location.pathname + this.location.search;
|
|
91
|
+
}
|
|
92
|
+
navigateTo(url) {
|
|
93
|
+
// External OAuth redirects (https://...) must use window.location
|
|
94
|
+
if (url.startsWith('http://') || url.startsWith('https://')) {
|
|
95
|
+
console.log('🌐 [ReactRouter] External OAuth redirect, using window.location:', url);
|
|
96
|
+
window.location.href = url;
|
|
97
|
+
}
|
|
98
|
+
else if (this.navigateFunc) {
|
|
99
|
+
console.log('🔄 [ReactRouter] Internal navigation:', url);
|
|
100
|
+
this.navigateFunc(url);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
console.warn('ReactRouterRoutingService not initialized. Using window.location.');
|
|
104
|
+
window.location.href = url;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
navigateReplace(path) {
|
|
108
|
+
if (this.navigateFunc) {
|
|
109
|
+
console.log('🔄 [ReactRouter] Replacing URL:', path);
|
|
110
|
+
this.navigateFunc(path, { replace: true });
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
console.warn('ReactRouterRoutingService not initialized. Using window.history.');
|
|
114
|
+
window.history.replaceState({}, '', path);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
openPopup(url, name, features) {
|
|
118
|
+
return window.open(url, name, features);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
exports.ReactRouterRoutingService = ReactRouterRoutingService;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { IStorageService } from "./IStorageService";
|
|
2
|
+
import { Token } from "../models/Token";
|
|
3
|
+
/**
|
|
4
|
+
* Token storage service (decorator pattern)
|
|
5
|
+
* Adds domain logic (expiry check, JSON serialization) on top of generic storage
|
|
6
|
+
*/
|
|
7
|
+
export declare class TokenStorageService {
|
|
8
|
+
private storage;
|
|
9
|
+
private readonly tokenKey;
|
|
10
|
+
private readonly expiryKey;
|
|
11
|
+
constructor(storage: IStorageService);
|
|
12
|
+
/**
|
|
13
|
+
* Save social authentication token
|
|
14
|
+
* @param token Token with expiry information (Date)
|
|
15
|
+
*/
|
|
16
|
+
saveToken(token: Token): void;
|
|
17
|
+
/**
|
|
18
|
+
* Get social authentication token
|
|
19
|
+
* Returns null if not found or expired
|
|
20
|
+
*/
|
|
21
|
+
getToken(): Token | null;
|
|
22
|
+
/**
|
|
23
|
+
* Check if token exists (not expired)
|
|
24
|
+
*/
|
|
25
|
+
hasToken(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Clear token from storage
|
|
28
|
+
*/
|
|
29
|
+
clearToken(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Check if token is expired
|
|
32
|
+
*/
|
|
33
|
+
private isExpired;
|
|
34
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TokenStorageService = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Token storage service (decorator pattern)
|
|
6
|
+
* Adds domain logic (expiry check, JSON serialization) on top of generic storage
|
|
7
|
+
*/
|
|
8
|
+
class TokenStorageService {
|
|
9
|
+
storage;
|
|
10
|
+
tokenKey = 'socialUserToken'; // Backward compatible key
|
|
11
|
+
expiryKey = 'socialUserToken_expiry';
|
|
12
|
+
constructor(storage) {
|
|
13
|
+
this.storage = storage;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Save social authentication token
|
|
17
|
+
* @param token Token with expiry information (Date)
|
|
18
|
+
*/
|
|
19
|
+
saveToken(token) {
|
|
20
|
+
try {
|
|
21
|
+
this.storage.set(this.tokenKey, JSON.stringify(token));
|
|
22
|
+
// Store expiry separately for quick validation
|
|
23
|
+
if (token.expiresIn) {
|
|
24
|
+
this.storage.set(this.expiryKey, token.expiresIn.toISOString());
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.error('TokenStorageService: Error saving token', error);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get social authentication token
|
|
33
|
+
* Returns null if not found or expired
|
|
34
|
+
*/
|
|
35
|
+
getToken() {
|
|
36
|
+
try {
|
|
37
|
+
// Check expiry first (faster than parsing JSON)
|
|
38
|
+
if (this.isExpired()) {
|
|
39
|
+
this.clearToken();
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const raw = this.storage.get(this.tokenKey);
|
|
43
|
+
if (!raw) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const token = JSON.parse(raw);
|
|
47
|
+
// Convert ISO string back to Date
|
|
48
|
+
if (token.expiresIn) {
|
|
49
|
+
token.expiresIn = new Date(token.expiresIn);
|
|
50
|
+
}
|
|
51
|
+
return token;
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.error('TokenStorageService: Error getting token', error);
|
|
55
|
+
this.clearToken();
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Check if token exists (not expired)
|
|
61
|
+
*/
|
|
62
|
+
hasToken() {
|
|
63
|
+
return !this.isExpired() && this.storage.has(this.tokenKey);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Clear token from storage
|
|
67
|
+
*/
|
|
68
|
+
clearToken() {
|
|
69
|
+
this.storage.remove(this.tokenKey);
|
|
70
|
+
this.storage.remove(this.expiryKey);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Check if token is expired
|
|
74
|
+
*/
|
|
75
|
+
isExpired() {
|
|
76
|
+
const expiryRaw = this.storage.get(this.expiryKey);
|
|
77
|
+
if (!expiryRaw) {
|
|
78
|
+
return false; // No expiry set = no token or never expires
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const expiryDate = new Date(expiryRaw);
|
|
82
|
+
return expiryDate <= new Date();
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.error('TokenStorageService: Error checking expiry', error);
|
|
86
|
+
return true; // If can't parse, consider expired
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.TokenStorageService = TokenStorageService;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { IStorageService } from "./IStorageService";
|
|
2
|
+
import { SocialUser } from "../models/SocialUser";
|
|
3
|
+
/**
|
|
4
|
+
* User storage service (decorator pattern)
|
|
5
|
+
* Adds domain logic (JSON serialization, identity transformation) on top of generic storage
|
|
6
|
+
*/
|
|
7
|
+
export declare class UserStorageService {
|
|
8
|
+
private storage;
|
|
9
|
+
private readonly userKey;
|
|
10
|
+
constructor(storage: IStorageService);
|
|
11
|
+
/**
|
|
12
|
+
* Save social user information
|
|
13
|
+
* @param user Social user data
|
|
14
|
+
*/
|
|
15
|
+
saveUser<T = {}>(user: SocialUser<T>): void;
|
|
16
|
+
/**
|
|
17
|
+
* Get social user information
|
|
18
|
+
* Returns null if not found
|
|
19
|
+
*/
|
|
20
|
+
getUser<T = {}>(): SocialUser<T> | null;
|
|
21
|
+
/**
|
|
22
|
+
* Check if user exists
|
|
23
|
+
*/
|
|
24
|
+
hasUser(): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Clear user from storage
|
|
27
|
+
*/
|
|
28
|
+
clearUser(): void;
|
|
29
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UserStorageService = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* User storage service (decorator pattern)
|
|
6
|
+
* Adds domain logic (JSON serialization, identity transformation) on top of generic storage
|
|
7
|
+
*/
|
|
8
|
+
class UserStorageService {
|
|
9
|
+
storage;
|
|
10
|
+
userKey = 'socialUser'; // Backward compatible key
|
|
11
|
+
constructor(storage) {
|
|
12
|
+
this.storage = storage;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Save social user information
|
|
16
|
+
* @param user Social user data
|
|
17
|
+
*/
|
|
18
|
+
saveUser(user) {
|
|
19
|
+
try {
|
|
20
|
+
this.storage.set(this.userKey, JSON.stringify(user));
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
console.error('UserStorageService: Error saving user', error);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get social user information
|
|
28
|
+
* Returns null if not found
|
|
29
|
+
*/
|
|
30
|
+
getUser() {
|
|
31
|
+
try {
|
|
32
|
+
const raw = this.storage.get(this.userKey);
|
|
33
|
+
if (!raw) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return JSON.parse(raw);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
console.error('UserStorageService: Error getting user', error);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Check if user exists
|
|
45
|
+
*/
|
|
46
|
+
hasUser() {
|
|
47
|
+
return this.storage.has(this.userKey);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Clear user from storage
|
|
51
|
+
*/
|
|
52
|
+
clearUser() {
|
|
53
|
+
this.storage.remove(this.userKey);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.UserStorageService = UserStorageService;
|