@23blocks/react 14.4.0 → 14.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/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
## 14.5.0 (2026-03-14)
|
|
2
|
+
|
|
3
|
+
### 🚀 Features
|
|
4
|
+
|
|
5
|
+
- **@23blocks/react:** integrate token lifecycle in Provider ([71aee53](https://github.com/23blocks-OS/frontend-sdk/commit/71aee53))
|
|
6
|
+
|
|
7
|
+
### ❤️ Thank You
|
|
8
|
+
|
|
9
|
+
- Claude Opus 4.6
|
|
10
|
+
- Juan Pelaez
|
|
11
|
+
|
|
1
12
|
## 14.4.0 (2026-03-09)
|
|
2
13
|
|
|
3
14
|
### 🚀 Features
|
package/dist/index.esm.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { _ } from '@swc/helpers/_/_extends';
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
|
-
import { useState, useRef, useMemo, useCallback, createContext, useContext
|
|
3
|
+
import { useState, useRef, useMemo, useCallback, useEffect, createContext, useContext } from 'react';
|
|
4
4
|
import { createHttpTransport } from '@23blocks/transport-http';
|
|
5
|
+
import { BlockErrorException } from '@23blocks/contracts';
|
|
5
6
|
import { createAuthenticationBlock } from '@23blocks/block-authentication';
|
|
6
7
|
import { createSearchBlock } from '@23blocks/block-search';
|
|
7
8
|
import { createProductsBlock } from '@23blocks/block-products';
|
|
@@ -187,6 +188,178 @@ let MemoryStorage = class MemoryStorage {
|
|
|
187
188
|
};
|
|
188
189
|
}
|
|
189
190
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
191
|
+
// Token Lifecycle Helpers
|
|
192
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
193
|
+
function decodeJwtExp(token) {
|
|
194
|
+
try {
|
|
195
|
+
const parts = token.split('.');
|
|
196
|
+
if (parts.length !== 3) return null;
|
|
197
|
+
let payload = parts[1].replace(/-/g, '+').replace(/_/g, '/');
|
|
198
|
+
const pad = payload.length % 4;
|
|
199
|
+
if (pad) payload += '='.repeat(4 - pad);
|
|
200
|
+
let decoded;
|
|
201
|
+
if (typeof atob === 'function') {
|
|
202
|
+
decoded = atob(payload);
|
|
203
|
+
} else if (typeof Buffer !== 'undefined') {
|
|
204
|
+
decoded = Buffer.from(payload, 'base64').toString('utf-8');
|
|
205
|
+
} else {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
const parsed = JSON.parse(decoded);
|
|
209
|
+
return typeof parsed.exp === 'number' ? parsed.exp : null;
|
|
210
|
+
} catch (e) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function isBrowserEnv() {
|
|
215
|
+
try {
|
|
216
|
+
return typeof window !== 'undefined' && typeof window.localStorage !== 'undefined' && typeof window.localStorage.getItem === 'function';
|
|
217
|
+
} catch (e) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function createLifecycleManager(tokenManager, refreshFn, config = {}) {
|
|
222
|
+
const { refreshBufferSeconds = 120, enableVisibilityRefresh = true, enableProactiveRefresh = true } = config;
|
|
223
|
+
const listeners = new Set();
|
|
224
|
+
let refreshTimer = null;
|
|
225
|
+
let refreshPromise = null;
|
|
226
|
+
let visibilityHandler = null;
|
|
227
|
+
let destroyed = false;
|
|
228
|
+
let running = false;
|
|
229
|
+
function notify(event) {
|
|
230
|
+
listeners.forEach((l)=>{
|
|
231
|
+
try {
|
|
232
|
+
l(event);
|
|
233
|
+
} catch (e) {}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
function clearTimer() {
|
|
237
|
+
if (refreshTimer !== null) {
|
|
238
|
+
clearTimeout(refreshTimer);
|
|
239
|
+
refreshTimer = null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function scheduleRefresh() {
|
|
243
|
+
if (!enableProactiveRefresh || destroyed || !running) return;
|
|
244
|
+
clearTimer();
|
|
245
|
+
const accessToken = tokenManager.getAccessToken();
|
|
246
|
+
if (!accessToken) return;
|
|
247
|
+
const exp = decodeJwtExp(accessToken);
|
|
248
|
+
if (!exp) return;
|
|
249
|
+
const refreshInSeconds = exp - Math.floor(Date.now() / 1000) - refreshBufferSeconds;
|
|
250
|
+
if (refreshInSeconds <= 0) {
|
|
251
|
+
refreshNow().catch(()=>{});
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
refreshTimer = setTimeout(()=>{
|
|
255
|
+
if (!destroyed && running) refreshNow().catch(()=>{});
|
|
256
|
+
}, refreshInSeconds * 1000);
|
|
257
|
+
}
|
|
258
|
+
function handleVisibilityChange() {
|
|
259
|
+
if (destroyed || !running || typeof document === 'undefined') return;
|
|
260
|
+
if (document.visibilityState === 'visible') {
|
|
261
|
+
const accessToken = tokenManager.getAccessToken();
|
|
262
|
+
if (!accessToken) return;
|
|
263
|
+
const exp = decodeJwtExp(accessToken);
|
|
264
|
+
if (!exp) {
|
|
265
|
+
refreshNow().catch(()=>{});
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const secondsUntilExpiry = exp - Math.floor(Date.now() / 1000);
|
|
269
|
+
if (secondsUntilExpiry <= refreshBufferSeconds) {
|
|
270
|
+
refreshNow().catch(()=>{});
|
|
271
|
+
} else {
|
|
272
|
+
scheduleRefresh();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
async function refreshNow() {
|
|
277
|
+
if (destroyed) throw new Error('[23blocks] Lifecycle destroyed');
|
|
278
|
+
if (refreshPromise) return refreshPromise;
|
|
279
|
+
refreshPromise = (async ()=>{
|
|
280
|
+
try {
|
|
281
|
+
const rt = tokenManager.getRefreshToken();
|
|
282
|
+
if (!rt) throw new Error('No refresh token');
|
|
283
|
+
const result = await refreshFn(rt);
|
|
284
|
+
tokenManager.setTokens(result.accessToken, result.refreshToken);
|
|
285
|
+
scheduleRefresh();
|
|
286
|
+
notify('TOKEN_REFRESHED');
|
|
287
|
+
return result.accessToken;
|
|
288
|
+
} catch (error) {
|
|
289
|
+
clearTimer();
|
|
290
|
+
tokenManager.clearTokens();
|
|
291
|
+
running = false;
|
|
292
|
+
notify('SESSION_EXPIRED');
|
|
293
|
+
throw error;
|
|
294
|
+
} finally{
|
|
295
|
+
refreshPromise = null;
|
|
296
|
+
}
|
|
297
|
+
})();
|
|
298
|
+
return refreshPromise;
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
start () {
|
|
302
|
+
if (destroyed) return;
|
|
303
|
+
running = true;
|
|
304
|
+
scheduleRefresh();
|
|
305
|
+
if (enableVisibilityRefresh && isBrowserEnv() && !visibilityHandler && typeof document !== 'undefined') {
|
|
306
|
+
visibilityHandler = handleVisibilityChange;
|
|
307
|
+
document.addEventListener('visibilitychange', visibilityHandler);
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
stop () {
|
|
311
|
+
running = false;
|
|
312
|
+
clearTimer();
|
|
313
|
+
refreshPromise = null;
|
|
314
|
+
},
|
|
315
|
+
onAuthStateChanged (listener) {
|
|
316
|
+
listeners.add(listener);
|
|
317
|
+
return ()=>{
|
|
318
|
+
listeners.delete(listener);
|
|
319
|
+
};
|
|
320
|
+
},
|
|
321
|
+
refreshNow,
|
|
322
|
+
destroy () {
|
|
323
|
+
destroyed = true;
|
|
324
|
+
running = false;
|
|
325
|
+
clearTimer();
|
|
326
|
+
refreshPromise = null;
|
|
327
|
+
if (visibilityHandler && typeof document !== 'undefined') {
|
|
328
|
+
document.removeEventListener('visibilitychange', visibilityHandler);
|
|
329
|
+
visibilityHandler = null;
|
|
330
|
+
}
|
|
331
|
+
listeners.clear();
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function createRetryTransport(baseTransport, getLifecycle) {
|
|
336
|
+
async function withRetry(fn) {
|
|
337
|
+
try {
|
|
338
|
+
return await fn();
|
|
339
|
+
} catch (error) {
|
|
340
|
+
if (error instanceof BlockErrorException && error.status === 401) {
|
|
341
|
+
const lc = getLifecycle();
|
|
342
|
+
if (lc) {
|
|
343
|
+
try {
|
|
344
|
+
await lc.refreshNow();
|
|
345
|
+
return await fn();
|
|
346
|
+
} catch (e) {
|
|
347
|
+
throw error;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
throw error;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return {
|
|
355
|
+
get: (path, options)=>withRetry(()=>baseTransport.get(path, options)),
|
|
356
|
+
post: (path, body, options)=>withRetry(()=>baseTransport.post(path, body, options)),
|
|
357
|
+
patch: (path, body, options)=>withRetry(()=>baseTransport.patch(path, body, options)),
|
|
358
|
+
put: (path, body, options)=>withRetry(()=>baseTransport.put(path, body, options)),
|
|
359
|
+
delete: (path, options)=>withRetry(()=>baseTransport.delete(path, options))
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
190
363
|
// Context
|
|
191
364
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
192
365
|
const Blocks23Context = /*#__PURE__*/ createContext(null);
|
|
@@ -280,10 +453,12 @@ const Blocks23Context = /*#__PURE__*/ createContext(null);
|
|
|
280
453
|
* <App />
|
|
281
454
|
* </Provider>
|
|
282
455
|
* ```
|
|
283
|
-
*/ function Provider({ children, urls, apiKey, tenantId, authMode = 'token', storage = 'localStorage', customStorage, headers: staticHeaders = {}, timeout }) {
|
|
456
|
+
*/ function Provider({ children, urls, apiKey, tenantId, authMode = 'token', storage = 'localStorage', customStorage, headers: staticHeaders = {}, timeout, tokenLifecycle: lifecycleConfig = {} }) {
|
|
284
457
|
// Track if async storage has loaded tokens
|
|
285
458
|
const [isReady, setIsReady] = useState(!customStorage);
|
|
286
459
|
const tokenManagerRef = useRef(null);
|
|
460
|
+
const lifecycleRef = useRef(null);
|
|
461
|
+
const lifecycleEnabled = authMode === 'token' && lifecycleConfig !== false;
|
|
287
462
|
// Create token manager (memoized) with scoped storage keys
|
|
288
463
|
const tokenManager = useMemo(()=>{
|
|
289
464
|
if (authMode !== 'token') {
|
|
@@ -309,8 +484,8 @@ const Blocks23Context = /*#__PURE__*/ createContext(null);
|
|
|
309
484
|
tenantId,
|
|
310
485
|
customStorage
|
|
311
486
|
]);
|
|
312
|
-
// Factory to create transport for a specific service URL
|
|
313
|
-
const
|
|
487
|
+
// Factory to create base transport for a specific service URL
|
|
488
|
+
const createBaseTransport = useCallback((baseUrl)=>{
|
|
314
489
|
return createHttpTransport({
|
|
315
490
|
baseUrl,
|
|
316
491
|
timeout,
|
|
@@ -338,6 +513,17 @@ const Blocks23Context = /*#__PURE__*/ createContext(null);
|
|
|
338
513
|
staticHeaders,
|
|
339
514
|
timeout
|
|
340
515
|
]);
|
|
516
|
+
// Factory to create transport with optional 401 retry
|
|
517
|
+
const createServiceTransport = useCallback((baseUrl)=>{
|
|
518
|
+
const base = createBaseTransport(baseUrl);
|
|
519
|
+
if (lifecycleEnabled) {
|
|
520
|
+
return createRetryTransport(base, ()=>lifecycleRef.current);
|
|
521
|
+
}
|
|
522
|
+
return base;
|
|
523
|
+
}, [
|
|
524
|
+
createBaseTransport,
|
|
525
|
+
lifecycleEnabled
|
|
526
|
+
]);
|
|
341
527
|
// Create blocks (memoized) - each with its own transport (no fallback)
|
|
342
528
|
const blockConfig = useMemo(()=>({
|
|
343
529
|
apiKey,
|
|
@@ -527,6 +713,40 @@ const Blocks23Context = /*#__PURE__*/ createContext(null);
|
|
|
527
713
|
urls.university,
|
|
528
714
|
blockConfig
|
|
529
715
|
]);
|
|
716
|
+
// Create and manage lifecycle manager
|
|
717
|
+
useEffect(()=>{
|
|
718
|
+
if (!lifecycleEnabled || !tokenManager || !urls.authentication) {
|
|
719
|
+
lifecycleRef.current = null;
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
const authBlock = authentication;
|
|
723
|
+
const refreshFn = async (refreshToken)=>{
|
|
724
|
+
const response = await authBlock.auth.refreshToken({
|
|
725
|
+
refreshToken
|
|
726
|
+
});
|
|
727
|
+
return {
|
|
728
|
+
accessToken: response.accessToken,
|
|
729
|
+
refreshToken: response.refreshToken,
|
|
730
|
+
expiresIn: response.expiresIn
|
|
731
|
+
};
|
|
732
|
+
};
|
|
733
|
+
const lc = createLifecycleManager(tokenManager, refreshFn, typeof lifecycleConfig === 'object' ? lifecycleConfig : {});
|
|
734
|
+
lifecycleRef.current = lc;
|
|
735
|
+
// Auto-start if tokens already exist (page reload)
|
|
736
|
+
if (tokenManager.getAccessToken() && tokenManager.getRefreshToken()) {
|
|
737
|
+
lc.start();
|
|
738
|
+
}
|
|
739
|
+
return ()=>{
|
|
740
|
+
lc.destroy();
|
|
741
|
+
lifecycleRef.current = null;
|
|
742
|
+
};
|
|
743
|
+
}, [
|
|
744
|
+
lifecycleEnabled,
|
|
745
|
+
tokenManager,
|
|
746
|
+
authentication,
|
|
747
|
+
urls.authentication,
|
|
748
|
+
lifecycleConfig
|
|
749
|
+
]);
|
|
530
750
|
// Check if authentication is configured for auth methods
|
|
531
751
|
const isAuthConfigured = !!urls.authentication;
|
|
532
752
|
// Auth methods with automatic token management
|
|
@@ -536,7 +756,9 @@ const Blocks23Context = /*#__PURE__*/ createContext(null);
|
|
|
536
756
|
}
|
|
537
757
|
const response = await authentication.auth.signIn(request);
|
|
538
758
|
if (authMode === 'token' && tokenManager && response.accessToken) {
|
|
759
|
+
var _lifecycleRef_current;
|
|
539
760
|
tokenManager.setTokens(response.accessToken, response.refreshToken);
|
|
761
|
+
(_lifecycleRef_current = lifecycleRef.current) == null ? void 0 : _lifecycleRef_current.start();
|
|
540
762
|
}
|
|
541
763
|
return response;
|
|
542
764
|
}, [
|
|
@@ -561,9 +783,11 @@ const Blocks23Context = /*#__PURE__*/ createContext(null);
|
|
|
561
783
|
isAuthConfigured
|
|
562
784
|
]);
|
|
563
785
|
const signOut = useCallback(async ()=>{
|
|
786
|
+
var _lifecycleRef_current;
|
|
564
787
|
if (!isAuthConfigured) {
|
|
565
788
|
throw new Error('[23blocks] Cannot call signOut: The authentication service URL is not configured. ' + "Add 'urls.authentication' to your Provider configuration.");
|
|
566
789
|
}
|
|
790
|
+
(_lifecycleRef_current = lifecycleRef.current) == null ? void 0 : _lifecycleRef_current.stop();
|
|
567
791
|
await authentication.auth.signOut();
|
|
568
792
|
if (authMode === 'token' && tokenManager) {
|
|
569
793
|
tokenManager.clearTokens();
|
|
@@ -608,6 +832,18 @@ const Blocks23Context = /*#__PURE__*/ createContext(null);
|
|
|
608
832
|
}, [
|
|
609
833
|
tokenManager
|
|
610
834
|
]);
|
|
835
|
+
const onAuthStateChanged = useCallback((listener)=>{
|
|
836
|
+
var _lifecycleRef_current;
|
|
837
|
+
var _lifecycleRef_current_onAuthStateChanged;
|
|
838
|
+
return (_lifecycleRef_current_onAuthStateChanged = (_lifecycleRef_current = lifecycleRef.current) == null ? void 0 : _lifecycleRef_current.onAuthStateChanged(listener)) != null ? _lifecycleRef_current_onAuthStateChanged : ()=>{};
|
|
839
|
+
}, []);
|
|
840
|
+
const refreshSession = useCallback(async ()=>{
|
|
841
|
+
const lc = lifecycleRef.current;
|
|
842
|
+
if (!lc) {
|
|
843
|
+
throw new Error('[23blocks] Token lifecycle is not available. ' + 'Ensure authMode is "token" and tokenLifecycle is not disabled.');
|
|
844
|
+
}
|
|
845
|
+
return lc.refreshNow();
|
|
846
|
+
}, []);
|
|
611
847
|
const value = useMemo(()=>({
|
|
612
848
|
// Blocks
|
|
613
849
|
authentication,
|
|
@@ -639,6 +875,9 @@ const Blocks23Context = /*#__PURE__*/ createContext(null);
|
|
|
639
875
|
clearTokens,
|
|
640
876
|
isAuthenticated,
|
|
641
877
|
onStorageChange,
|
|
878
|
+
// Lifecycle
|
|
879
|
+
onAuthStateChanged,
|
|
880
|
+
refreshSession,
|
|
642
881
|
// Config
|
|
643
882
|
authMode,
|
|
644
883
|
isReady
|
|
@@ -670,6 +909,8 @@ const Blocks23Context = /*#__PURE__*/ createContext(null);
|
|
|
670
909
|
clearTokens,
|
|
671
910
|
isAuthenticated,
|
|
672
911
|
onStorageChange,
|
|
912
|
+
onAuthStateChanged,
|
|
913
|
+
refreshSession,
|
|
673
914
|
authMode,
|
|
674
915
|
isReady
|
|
675
916
|
]);
|
|
@@ -795,6 +1036,9 @@ const Blocks23Context = /*#__PURE__*/ createContext(null);
|
|
|
795
1036
|
// Token validation
|
|
796
1037
|
validateToken: ()=>getAuth().validateToken(),
|
|
797
1038
|
getCurrentUser: ()=>getAuth().getCurrentUser(),
|
|
1039
|
+
// Token lifecycle
|
|
1040
|
+
onAuthStateChanged: context.onAuthStateChanged,
|
|
1041
|
+
refreshSession: context.refreshSession,
|
|
798
1042
|
// Full block access for advanced usage
|
|
799
1043
|
authentication: context.authentication
|
|
800
1044
|
};
|
package/dist/src/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Provider, useClient, useAuth, useUser, type ProviderProps, type ClientContext, type ServiceUrls, type AuthMode, type StorageType, type TokenManager, type AsyncStorageInterface, type UseUserReturn, SimpleBlocks23Provider, useSimpleBlocks23, useSimpleAuth, type SimpleBlocks23ProviderProps, type SimpleBlocks23Context, } from './simple-provider.js';
|
|
1
|
+
export { Provider, useClient, useAuth, useUser, type ProviderProps, type ClientContext, type ServiceUrls, type AuthMode, type StorageType, type TokenManager, type AsyncStorageInterface, type UseUserReturn, type AuthStateEvent, type AuthStateListener, type TokenLifecycleConfig, SimpleBlocks23Provider, useSimpleBlocks23, useSimpleAuth, type SimpleBlocks23ProviderProps, type SimpleBlocks23Context, } from './simple-provider.js';
|
|
2
2
|
export { Blocks23Provider, use23Blocks, useAuthenticationBlock, useSearchBlock, useProductsBlock, useCrmBlock, useContentBlock, useGeolocationBlock, useConversationsBlock, useFilesBlock, useFormsBlock, useAssetsBlock, useCampaignsBlock, useCompanyBlock, useRewardsBlock, useSalesBlock, useWalletBlock, useJarvisBlock, useOnboardingBlock, useUniversityBlock, type Blocks23ProviderProps, type Blocks23Context, } from './context.js';
|
|
3
3
|
export { useUsers, type UseUsersReturn, type UseUsersState, type UseUsersActions, useMfa, type UseMfaReturn, type UseMfaState, type UseMfaActions, useOAuth, type UseOAuthReturn, type UseOAuthState, type UseOAuthActions, useAvatars, type UseAvatarsReturn, type UseAvatarsState, type UseAvatarsActions, useTenants, type UseTenantsReturn, type UseTenantsState, type UseTenantsActions, useSearch, useFavorites, type UseSearchReturn, type UseSearchState, type UseSearchActions, type UseFavoritesReturn, type UseFavoritesState, type UseFavoritesActions, useContentSeries, type UseContentSeriesReturn, type UseContentSeriesState, type UseContentSeriesActions, } from './hooks/index.js';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,QAAQ,EACR,SAAS,EACT,OAAO,EACP,OAAO,EACP,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,QAAQ,EACR,SAAS,EACT,OAAO,EACP,OAAO,EACP,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAGzB,sBAAsB,EACtB,iBAAiB,EACjB,aAAa,EACb,KAAK,2BAA2B,EAChC,KAAK,qBAAqB,GAC3B,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,sBAAsB,EACtB,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,EACb,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,aAAa,EACb,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAEL,QAAQ,EACR,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,EAGpB,MAAM,EACN,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,EAGlB,QAAQ,EACR,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,EAGpB,UAAU,EACV,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EAGtB,UAAU,EACV,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EAGtB,SAAS,EACT,YAAY,EACZ,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAGxB,gBAAgB,EAChB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,GAC7B,MAAM,kBAAkB,CAAC"}
|
|
@@ -90,6 +90,25 @@ export interface ServiceUrls {
|
|
|
90
90
|
/** University (LMS) service URL */
|
|
91
91
|
university?: string;
|
|
92
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Auth state change events emitted by the token lifecycle manager
|
|
95
|
+
*/
|
|
96
|
+
export type AuthStateEvent = 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'SESSION_EXPIRED';
|
|
97
|
+
/**
|
|
98
|
+
* Callback invoked when auth state changes
|
|
99
|
+
*/
|
|
100
|
+
export type AuthStateListener = (event: AuthStateEvent) => void;
|
|
101
|
+
/**
|
|
102
|
+
* Configuration for automatic token lifecycle management
|
|
103
|
+
*/
|
|
104
|
+
export interface TokenLifecycleConfig {
|
|
105
|
+
/** Seconds before token expiry to trigger a proactive refresh. @default 120 */
|
|
106
|
+
refreshBufferSeconds?: number;
|
|
107
|
+
/** Refresh token when tab becomes visible. @default true */
|
|
108
|
+
enableVisibilityRefresh?: boolean;
|
|
109
|
+
/** Schedule proactive refresh based on JWT `exp` claim. @default true */
|
|
110
|
+
enableProactiveRefresh?: boolean;
|
|
111
|
+
}
|
|
93
112
|
/**
|
|
94
113
|
* Provider props
|
|
95
114
|
*/
|
|
@@ -181,6 +200,16 @@ export interface ProviderProps {
|
|
|
181
200
|
* @default 30000
|
|
182
201
|
*/
|
|
183
202
|
timeout?: number;
|
|
203
|
+
/**
|
|
204
|
+
* Token lifecycle configuration for automatic refresh and 401 retry.
|
|
205
|
+
* - Pass an object to customize (e.g., `{ refreshBufferSeconds: 60 }`)
|
|
206
|
+
* - Pass `false` to disable entirely
|
|
207
|
+
* - Omit or pass `{}` to use defaults (enabled with 120s buffer)
|
|
208
|
+
*
|
|
209
|
+
* Only applies in token mode. Ignored in cookie mode.
|
|
210
|
+
* @default {} (enabled with defaults)
|
|
211
|
+
*/
|
|
212
|
+
tokenLifecycle?: TokenLifecycleConfig | false;
|
|
184
213
|
}
|
|
185
214
|
/**
|
|
186
215
|
* Context value providing access to all 23blocks services
|
|
@@ -217,6 +246,16 @@ export interface ClientContext {
|
|
|
217
246
|
* Returns an unsubscribe function.
|
|
218
247
|
*/
|
|
219
248
|
onStorageChange: (callback: () => void) => () => void;
|
|
249
|
+
/**
|
|
250
|
+
* Subscribe to auth state changes (token refreshed, session expired, etc.).
|
|
251
|
+
* Returns an unsubscribe function.
|
|
252
|
+
*/
|
|
253
|
+
onAuthStateChanged: (listener: AuthStateListener) => () => void;
|
|
254
|
+
/**
|
|
255
|
+
* Force an immediate token refresh.
|
|
256
|
+
* Returns the new access token on success.
|
|
257
|
+
*/
|
|
258
|
+
refreshSession: () => Promise<string>;
|
|
220
259
|
authMode: AuthMode;
|
|
221
260
|
/**
|
|
222
261
|
* Whether the provider has finished loading tokens from async storage.
|
|
@@ -304,7 +343,7 @@ export interface ClientContext {
|
|
|
304
343
|
* </Provider>
|
|
305
344
|
* ```
|
|
306
345
|
*/
|
|
307
|
-
export declare function Provider({ children, urls, apiKey, tenantId, authMode, storage, customStorage, headers: staticHeaders, timeout, }: ProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
346
|
+
export declare function Provider({ children, urls, apiKey, tenantId, authMode, storage, customStorage, headers: staticHeaders, timeout, tokenLifecycle: lifecycleConfig, }: ProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
308
347
|
/**
|
|
309
348
|
* Hook to access all 23blocks services.
|
|
310
349
|
*
|
|
@@ -401,6 +440,8 @@ export declare function useAuth(): {
|
|
|
401
440
|
completeAccountRecovery: (request: import("@23blocks/block-authentication").CompleteRecoveryRequest) => Promise<User>;
|
|
402
441
|
validateToken: () => Promise<import("@23blocks/block-authentication").TokenValidationResponse>;
|
|
403
442
|
getCurrentUser: () => Promise<User>;
|
|
443
|
+
onAuthStateChanged: (listener: AuthStateListener) => () => void;
|
|
444
|
+
refreshSession: () => Promise<string>;
|
|
404
445
|
authentication: AuthenticationBlock;
|
|
405
446
|
};
|
|
406
447
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simple-provider.d.ts","sourceRoot":"","sources":["../../../src/lib/simple-provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgF,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"simple-provider.d.ts","sourceRoot":"","sources":["../../../src/lib/simple-provider.tsx"],"names":[],"mappings":"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"}
|