@proveanything/smartlinks-auth-ui 0.1.11 → 0.1.13
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/dist/components/SmartlinksAuthUI.d.ts.map +1 -1
- package/dist/context/AuthContext.d.ts +2 -0
- package/dist/context/AuthContext.d.ts.map +1 -1
- package/dist/index.esm.js +175 -51
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +175 -51
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -11238,7 +11238,7 @@ const tokenStorage = {
|
|
|
11238
11238
|
};
|
|
11239
11239
|
|
|
11240
11240
|
const AuthContext = React.createContext(undefined);
|
|
11241
|
-
const AuthProvider = ({ children, accountCacheTTL = 5 * 60 * 1000, preloadAccountInfo = false }) => {
|
|
11241
|
+
const AuthProvider = ({ children, proxyMode = false, accountCacheTTL = 5 * 60 * 1000, preloadAccountInfo = false }) => {
|
|
11242
11242
|
const [user, setUser] = React.useState(null);
|
|
11243
11243
|
const [token, setToken] = React.useState(null);
|
|
11244
11244
|
const [accountData, setAccountData] = React.useState(null);
|
|
@@ -11262,10 +11262,45 @@ const AuthProvider = ({ children, accountCacheTTL = 5 * 60 * 1000, preloadAccoun
|
|
|
11262
11262
|
}
|
|
11263
11263
|
});
|
|
11264
11264
|
}, []);
|
|
11265
|
-
// Initialize auth state
|
|
11265
|
+
// Initialize auth state - different behavior for proxy mode vs standalone mode
|
|
11266
11266
|
React.useEffect(() => {
|
|
11267
11267
|
const initializeAuth = async () => {
|
|
11268
11268
|
try {
|
|
11269
|
+
if (proxyMode) {
|
|
11270
|
+
// PROXY MODE: Initialize from URL params and parent via SDK
|
|
11271
|
+
const params = new URLSearchParams(window.location.search);
|
|
11272
|
+
const userId = params.get('userId');
|
|
11273
|
+
if (userId) {
|
|
11274
|
+
console.log('[AuthContext] Proxy mode: userId detected, fetching account from parent');
|
|
11275
|
+
try {
|
|
11276
|
+
// Fetch account details from parent via proxied API call
|
|
11277
|
+
const accountResponse = await smartlinks__namespace.auth.getAccount();
|
|
11278
|
+
// Build user object from account response
|
|
11279
|
+
const accountAny = accountResponse;
|
|
11280
|
+
const userFromAccount = {
|
|
11281
|
+
uid: userId,
|
|
11282
|
+
email: accountAny?.email,
|
|
11283
|
+
displayName: accountAny?.displayName || accountAny?.name,
|
|
11284
|
+
phoneNumber: accountAny?.phoneNumber,
|
|
11285
|
+
};
|
|
11286
|
+
setUser(userFromAccount);
|
|
11287
|
+
setAccountData(accountResponse);
|
|
11288
|
+
setAccountInfo(accountResponse);
|
|
11289
|
+
console.log('[AuthContext] Proxy mode: initialized from parent account');
|
|
11290
|
+
notifyAuthStateChange('LOGIN', userFromAccount, null, accountResponse, accountResponse);
|
|
11291
|
+
}
|
|
11292
|
+
catch (error) {
|
|
11293
|
+
console.warn('[AuthContext] Proxy mode: failed to fetch account from parent:', error);
|
|
11294
|
+
// No session - that's ok, user may need to login
|
|
11295
|
+
}
|
|
11296
|
+
}
|
|
11297
|
+
else {
|
|
11298
|
+
console.log('[AuthContext] Proxy mode: no userId in URL, awaiting login');
|
|
11299
|
+
}
|
|
11300
|
+
setIsLoading(false);
|
|
11301
|
+
return;
|
|
11302
|
+
}
|
|
11303
|
+
// STANDALONE MODE: Load from persistent storage
|
|
11269
11304
|
const storedToken = await tokenStorage.getToken();
|
|
11270
11305
|
const storedUser = await tokenStorage.getUser();
|
|
11271
11306
|
const storedAccountData = await tokenStorage.getAccountData();
|
|
@@ -11292,9 +11327,49 @@ const AuthProvider = ({ children, accountCacheTTL = 5 * 60 * 1000, preloadAccoun
|
|
|
11292
11327
|
}
|
|
11293
11328
|
};
|
|
11294
11329
|
initializeAuth();
|
|
11295
|
-
}, []);
|
|
11296
|
-
//
|
|
11330
|
+
}, [proxyMode, notifyAuthStateChange]);
|
|
11331
|
+
// Listen for parent auth state changes (proxy mode only)
|
|
11332
|
+
React.useEffect(() => {
|
|
11333
|
+
if (!proxyMode)
|
|
11334
|
+
return;
|
|
11335
|
+
console.log('[AuthContext] Proxy mode: setting up parent message listener');
|
|
11336
|
+
const handleParentMessage = (event) => {
|
|
11337
|
+
// Handle auth state pushed from parent
|
|
11338
|
+
if (event.data?.type === 'smartlinks:authkit:state') {
|
|
11339
|
+
const { user: parentUser, accountData: parentAccountData, authenticated } = event.data.payload || {};
|
|
11340
|
+
console.log('[AuthContext] Proxy mode: received state from parent:', { authenticated });
|
|
11341
|
+
if (authenticated && parentUser) {
|
|
11342
|
+
const userObj = {
|
|
11343
|
+
uid: parentUser.uid || parentUser.id,
|
|
11344
|
+
email: parentUser.email,
|
|
11345
|
+
displayName: parentUser.displayName || parentUser.name,
|
|
11346
|
+
phoneNumber: parentUser.phoneNumber,
|
|
11347
|
+
};
|
|
11348
|
+
setUser(userObj);
|
|
11349
|
+
setAccountData(parentAccountData || null);
|
|
11350
|
+
setAccountInfo(parentAccountData || null);
|
|
11351
|
+
notifyAuthStateChange('CROSS_TAB_SYNC', userObj, null, parentAccountData || null, parentAccountData || null);
|
|
11352
|
+
}
|
|
11353
|
+
else {
|
|
11354
|
+
// Parent indicates no session / logged out
|
|
11355
|
+
setUser(null);
|
|
11356
|
+
setToken(null);
|
|
11357
|
+
setAccountData(null);
|
|
11358
|
+
setAccountInfo(null);
|
|
11359
|
+
notifyAuthStateChange('LOGOUT', null, null, null, null);
|
|
11360
|
+
}
|
|
11361
|
+
}
|
|
11362
|
+
};
|
|
11363
|
+
window.addEventListener('message', handleParentMessage);
|
|
11364
|
+
return () => {
|
|
11365
|
+
console.log('[AuthContext] Proxy mode: cleaning up parent message listener');
|
|
11366
|
+
window.removeEventListener('message', handleParentMessage);
|
|
11367
|
+
};
|
|
11368
|
+
}, [proxyMode, notifyAuthStateChange]);
|
|
11369
|
+
// Cross-tab synchronization - standalone mode only
|
|
11297
11370
|
React.useEffect(() => {
|
|
11371
|
+
if (proxyMode)
|
|
11372
|
+
return; // Skip cross-tab sync in proxy mode
|
|
11298
11373
|
console.log('[AuthContext] Setting up cross-tab synchronization');
|
|
11299
11374
|
const unsubscribe = onStorageChange(async (event) => {
|
|
11300
11375
|
console.log('[AuthContext] Cross-tab storage event:', event.type, event.key);
|
|
@@ -11353,27 +11428,38 @@ const AuthProvider = ({ children, accountCacheTTL = 5 * 60 * 1000, preloadAccoun
|
|
|
11353
11428
|
console.log('[AuthContext] Cleaning up cross-tab synchronization');
|
|
11354
11429
|
unsubscribe();
|
|
11355
11430
|
};
|
|
11356
|
-
}, [notifyAuthStateChange]);
|
|
11431
|
+
}, [proxyMode, notifyAuthStateChange]);
|
|
11357
11432
|
const login = React.useCallback(async (authToken, authUser, authAccountData) => {
|
|
11358
11433
|
try {
|
|
11359
|
-
//
|
|
11360
|
-
|
|
11361
|
-
|
|
11362
|
-
|
|
11363
|
-
|
|
11434
|
+
// Only persist to storage in standalone mode
|
|
11435
|
+
if (!proxyMode) {
|
|
11436
|
+
await tokenStorage.saveToken(authToken);
|
|
11437
|
+
await tokenStorage.saveUser(authUser);
|
|
11438
|
+
if (authAccountData) {
|
|
11439
|
+
await tokenStorage.saveAccountData(authAccountData);
|
|
11440
|
+
}
|
|
11441
|
+
// Set bearer token in global Smartlinks SDK via auth.verifyToken
|
|
11442
|
+
smartlinks__namespace.auth.verifyToken(authToken).catch(err => {
|
|
11443
|
+
console.warn('Failed to set bearer token on login:', err);
|
|
11444
|
+
});
|
|
11364
11445
|
}
|
|
11446
|
+
// Always update memory state
|
|
11365
11447
|
setToken(authToken);
|
|
11366
11448
|
setUser(authUser);
|
|
11367
11449
|
setAccountData(authAccountData || null);
|
|
11368
|
-
//
|
|
11369
|
-
//
|
|
11370
|
-
|
|
11371
|
-
|
|
11372
|
-
|
|
11450
|
+
// Cross-iframe auth state synchronization
|
|
11451
|
+
// Always notify parent frame of login (both modes, but especially important in proxy mode)
|
|
11452
|
+
const sdk = smartlinks__namespace;
|
|
11453
|
+
if (sdk.iframe?.isIframe?.()) {
|
|
11454
|
+
sdk.iframe.sendParentCustom('smartlinks:authkit:login', {
|
|
11455
|
+
token: authToken,
|
|
11456
|
+
user: authUser,
|
|
11457
|
+
accountData: authAccountData || null
|
|
11458
|
+
});
|
|
11459
|
+
}
|
|
11373
11460
|
notifyAuthStateChange('LOGIN', authUser, authToken, authAccountData || null);
|
|
11374
|
-
// Optionally preload account info on login
|
|
11375
|
-
if (preloadAccountInfo) {
|
|
11376
|
-
// Preload after login completes (non-blocking)
|
|
11461
|
+
// Optionally preload account info on login (standalone mode only)
|
|
11462
|
+
if (!proxyMode && preloadAccountInfo) {
|
|
11377
11463
|
getAccount(true).catch(error => {
|
|
11378
11464
|
console.warn('[AuthContext] Failed to preload account info:', error);
|
|
11379
11465
|
});
|
|
@@ -11383,34 +11469,55 @@ const AuthProvider = ({ children, accountCacheTTL = 5 * 60 * 1000, preloadAccoun
|
|
|
11383
11469
|
console.error('Failed to save auth data to storage:', error);
|
|
11384
11470
|
throw error;
|
|
11385
11471
|
}
|
|
11386
|
-
}, [notifyAuthStateChange, preloadAccountInfo]);
|
|
11472
|
+
}, [proxyMode, notifyAuthStateChange, preloadAccountInfo]);
|
|
11387
11473
|
const logout = React.useCallback(async () => {
|
|
11388
11474
|
try {
|
|
11389
|
-
//
|
|
11390
|
-
|
|
11475
|
+
// Only clear persistent storage in standalone mode
|
|
11476
|
+
if (!proxyMode) {
|
|
11477
|
+
await tokenStorage.clearAll();
|
|
11478
|
+
smartlinks__namespace.auth.logout();
|
|
11479
|
+
}
|
|
11480
|
+
// Always clear memory state
|
|
11391
11481
|
setToken(null);
|
|
11392
11482
|
setUser(null);
|
|
11393
11483
|
setAccountData(null);
|
|
11394
11484
|
setAccountInfo(null);
|
|
11395
|
-
//
|
|
11396
|
-
|
|
11485
|
+
// Cross-iframe auth state synchronization
|
|
11486
|
+
// Always notify parent frame of logout
|
|
11487
|
+
const sdk = smartlinks__namespace;
|
|
11488
|
+
if (sdk.iframe?.isIframe?.()) {
|
|
11489
|
+
sdk.iframe.sendParentCustom('smartlinks:authkit:logout', {});
|
|
11490
|
+
}
|
|
11397
11491
|
notifyAuthStateChange('LOGOUT', null, null, null);
|
|
11398
11492
|
}
|
|
11399
11493
|
catch (error) {
|
|
11400
11494
|
console.error('Failed to clear auth data from storage:', error);
|
|
11401
11495
|
}
|
|
11402
|
-
}, [notifyAuthStateChange]);
|
|
11496
|
+
}, [proxyMode, notifyAuthStateChange]);
|
|
11403
11497
|
const getToken = React.useCallback(async () => {
|
|
11498
|
+
if (proxyMode) {
|
|
11499
|
+
// In proxy mode, token is managed by parent - return memory state
|
|
11500
|
+
return token;
|
|
11501
|
+
}
|
|
11404
11502
|
const storedToken = await tokenStorage.getToken();
|
|
11405
11503
|
return storedToken ? storedToken.token : null;
|
|
11406
|
-
}, []);
|
|
11504
|
+
}, [proxyMode, token]);
|
|
11407
11505
|
const refreshToken = React.useCallback(async () => {
|
|
11408
11506
|
throw new Error('Token refresh must be implemented via your backend API');
|
|
11409
11507
|
}, []);
|
|
11410
|
-
// Get account with intelligent caching
|
|
11508
|
+
// Get account with intelligent caching (or direct parent fetch in proxy mode)
|
|
11411
11509
|
const getAccount = React.useCallback(async (forceRefresh = false) => {
|
|
11412
11510
|
try {
|
|
11413
|
-
|
|
11511
|
+
if (proxyMode) {
|
|
11512
|
+
// PROXY MODE: Always fetch from parent via proxied API, no local cache
|
|
11513
|
+
console.log('[AuthContext] Proxy mode: fetching account from parent');
|
|
11514
|
+
const freshAccountInfo = await smartlinks__namespace.auth.getAccount();
|
|
11515
|
+
setAccountInfo(freshAccountInfo);
|
|
11516
|
+
setAccountData(freshAccountInfo);
|
|
11517
|
+
notifyAuthStateChange('ACCOUNT_REFRESH', user, token, freshAccountInfo, freshAccountInfo);
|
|
11518
|
+
return freshAccountInfo;
|
|
11519
|
+
}
|
|
11520
|
+
// STANDALONE MODE: Use caching
|
|
11414
11521
|
if (!token) {
|
|
11415
11522
|
throw new Error('Not authenticated. Please login first.');
|
|
11416
11523
|
}
|
|
@@ -11433,24 +11540,28 @@ const AuthProvider = ({ children, accountCacheTTL = 5 * 60 * 1000, preloadAccoun
|
|
|
11433
11540
|
}
|
|
11434
11541
|
catch (error) {
|
|
11435
11542
|
console.error('[AuthContext] Failed to get account info:', error);
|
|
11436
|
-
// Fallback to stale cache if API fails
|
|
11437
|
-
|
|
11438
|
-
|
|
11439
|
-
|
|
11440
|
-
|
|
11543
|
+
// Fallback to stale cache if API fails (standalone mode only)
|
|
11544
|
+
if (!proxyMode) {
|
|
11545
|
+
const cached = await tokenStorage.getAccountInfo();
|
|
11546
|
+
if (cached) {
|
|
11547
|
+
console.warn('[AuthContext] Returning stale cached data due to API error');
|
|
11548
|
+
return cached.data;
|
|
11549
|
+
}
|
|
11441
11550
|
}
|
|
11442
11551
|
throw error;
|
|
11443
11552
|
}
|
|
11444
|
-
}, [token, accountCacheTTL, user, accountData, notifyAuthStateChange]);
|
|
11553
|
+
}, [proxyMode, token, accountCacheTTL, user, accountData, notifyAuthStateChange]);
|
|
11445
11554
|
// Convenience method for explicit refresh
|
|
11446
11555
|
const refreshAccount = React.useCallback(async () => {
|
|
11447
11556
|
return await getAccount(true);
|
|
11448
11557
|
}, [getAccount]);
|
|
11449
|
-
// Clear account cache
|
|
11558
|
+
// Clear account cache (no-op in proxy mode)
|
|
11450
11559
|
const clearAccountCache = React.useCallback(async () => {
|
|
11451
|
-
|
|
11560
|
+
if (!proxyMode) {
|
|
11561
|
+
await tokenStorage.clearAccountInfo();
|
|
11562
|
+
}
|
|
11452
11563
|
setAccountInfo(null);
|
|
11453
|
-
}, []);
|
|
11564
|
+
}, [proxyMode]);
|
|
11454
11565
|
const onAuthStateChange = React.useCallback((callback) => {
|
|
11455
11566
|
callbacksRef.current.add(callback);
|
|
11456
11567
|
// Return unsubscribe function
|
|
@@ -11463,8 +11574,9 @@ const AuthProvider = ({ children, accountCacheTTL = 5 * 60 * 1000, preloadAccoun
|
|
|
11463
11574
|
token,
|
|
11464
11575
|
accountData,
|
|
11465
11576
|
accountInfo,
|
|
11466
|
-
isAuthenticated: !!
|
|
11577
|
+
isAuthenticated: !!user,
|
|
11467
11578
|
isLoading,
|
|
11579
|
+
proxyMode,
|
|
11468
11580
|
login,
|
|
11469
11581
|
logout,
|
|
11470
11582
|
getToken,
|
|
@@ -11554,7 +11666,7 @@ const getFriendlyErrorMessage = (errorMessage) => {
|
|
|
11554
11666
|
// Return original message if no pattern matches
|
|
11555
11667
|
return errorMessage;
|
|
11556
11668
|
};
|
|
11557
|
-
const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAuthSuccess, onAuthError, enabledProviders = ['email', 'google', 'phone'], initialMode = 'login', redirectUrl, theme = 'auto', className, customization, skipConfigFetch = false, minimal = false, logger, }) => {
|
|
11669
|
+
const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAuthSuccess, onAuthError, enabledProviders = ['email', 'google', 'phone'], initialMode = 'login', redirectUrl, theme = 'auto', className, customization, skipConfigFetch = false, minimal = false, logger, proxyMode = false, }) => {
|
|
11558
11670
|
const [mode, setMode] = React.useState(initialMode);
|
|
11559
11671
|
const [loading, setLoading] = React.useState(false);
|
|
11560
11672
|
const [error, setError] = React.useState();
|
|
@@ -11587,25 +11699,25 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
11587
11699
|
mediaQuery.addEventListener('change', updateTheme);
|
|
11588
11700
|
return () => mediaQuery.removeEventListener('change', updateTheme);
|
|
11589
11701
|
}, [theme]);
|
|
11590
|
-
// Reinitialize Smartlinks SDK when apiEndpoint
|
|
11702
|
+
// Reinitialize Smartlinks SDK when apiEndpoint or proxyMode changes
|
|
11591
11703
|
// IMPORTANT: Preserve bearer token during reinitialization
|
|
11592
11704
|
React.useEffect(() => {
|
|
11593
|
-
log.log('SDK reinitialize useEffect triggered', { apiEndpoint });
|
|
11705
|
+
log.log('SDK reinitialize useEffect triggered', { apiEndpoint, proxyMode });
|
|
11594
11706
|
setSdkReady(false); // Mark SDK as not ready during reinitialization
|
|
11595
11707
|
const reinitializeWithToken = async () => {
|
|
11596
11708
|
if (apiEndpoint) {
|
|
11597
|
-
log.log('Reinitializing SDK with baseURL:', apiEndpoint);
|
|
11598
|
-
// Get current token before reinitializing
|
|
11599
|
-
const currentToken = await auth.getToken();
|
|
11709
|
+
log.log('Reinitializing SDK with baseURL:', apiEndpoint, 'proxyMode:', proxyMode);
|
|
11710
|
+
// Get current token before reinitializing (only in standalone mode)
|
|
11711
|
+
const currentToken = !proxyMode ? await auth.getToken() : null;
|
|
11600
11712
|
smartlinks__namespace.initializeApi({
|
|
11601
11713
|
baseURL: apiEndpoint,
|
|
11602
|
-
proxyMode:
|
|
11714
|
+
proxyMode: proxyMode, // Use prop value
|
|
11603
11715
|
ngrokSkipBrowserWarning: true,
|
|
11604
11716
|
logger: logger, // Pass logger to SDK for verbose SDK logging
|
|
11605
11717
|
});
|
|
11606
11718
|
log.log('SDK reinitialized successfully');
|
|
11607
|
-
// Restore bearer token after reinitialization using auth.verifyToken
|
|
11608
|
-
if (currentToken) {
|
|
11719
|
+
// Restore bearer token after reinitialization using auth.verifyToken (standalone mode only)
|
|
11720
|
+
if (currentToken && !proxyMode) {
|
|
11609
11721
|
smartlinks__namespace.auth.verifyToken(currentToken).catch(err => {
|
|
11610
11722
|
log.warn('Failed to restore bearer token after reinit:', err);
|
|
11611
11723
|
});
|
|
@@ -11613,6 +11725,11 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
11613
11725
|
// Mark SDK as ready
|
|
11614
11726
|
setSdkReady(true);
|
|
11615
11727
|
}
|
|
11728
|
+
else if (proxyMode) {
|
|
11729
|
+
// In proxy mode without custom endpoint, SDK should already be initialized by parent
|
|
11730
|
+
log.log('Proxy mode without apiEndpoint, SDK already initialized by parent');
|
|
11731
|
+
setSdkReady(true);
|
|
11732
|
+
}
|
|
11616
11733
|
else {
|
|
11617
11734
|
log.log('No apiEndpoint, SDK already initialized by App');
|
|
11618
11735
|
// SDK was initialized by App component, mark as ready
|
|
@@ -11620,7 +11737,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
11620
11737
|
}
|
|
11621
11738
|
};
|
|
11622
11739
|
reinitializeWithToken();
|
|
11623
|
-
}, [apiEndpoint, auth, logger, log]);
|
|
11740
|
+
}, [apiEndpoint, proxyMode, auth, logger, log]);
|
|
11624
11741
|
// Get the effective redirect URL (use prop or default to current page)
|
|
11625
11742
|
const getRedirectUrl = () => {
|
|
11626
11743
|
if (redirectUrl)
|
|
@@ -12134,11 +12251,18 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
12134
12251
|
},
|
|
12135
12252
|
auto_select: false,
|
|
12136
12253
|
cancel_on_tap_outside: true,
|
|
12254
|
+
// Note: use_fedcm_for_prompt omitted - requires Permissions-Policy header on hosting server
|
|
12255
|
+
// Will be needed when FedCM becomes mandatory in the future
|
|
12137
12256
|
});
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
|
|
12141
|
-
|
|
12257
|
+
// Use timeout fallback instead of deprecated notification methods
|
|
12258
|
+
// (isNotDisplayed/isSkippedMoment will stop working when FedCM becomes mandatory)
|
|
12259
|
+
const promptTimeout = setTimeout(() => {
|
|
12260
|
+
setLoading(false);
|
|
12261
|
+
}, 5000);
|
|
12262
|
+
google.accounts.id.prompt(() => {
|
|
12263
|
+
// Clear timeout if prompt interaction occurs
|
|
12264
|
+
clearTimeout(promptTimeout);
|
|
12265
|
+
setLoading(false);
|
|
12142
12266
|
});
|
|
12143
12267
|
}
|
|
12144
12268
|
}
|