@pubflow/react 0.2.1 → 0.3.3
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/index.cjs +336 -259
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +336 -260
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createStorageKey, initConfig, ApiClient, AuthService, BridgeApiService, validateWithSchema, FilterOperator } from '@pubflow/core';
|
|
2
2
|
export * from '@pubflow/core';
|
|
3
3
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
4
|
-
import React, { createContext, useState,
|
|
4
|
+
import React, { createContext, useState, useCallback, useEffect, useContext } from 'react';
|
|
5
5
|
import useSWR, { SWRConfig, useSWRConfig } from 'swr';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -208,67 +208,36 @@ const PubflowContext = createContext({
|
|
|
208
208
|
defaultInstance: 'default'
|
|
209
209
|
});
|
|
210
210
|
/**
|
|
211
|
-
* Pubflow
|
|
211
|
+
* Pubflow Provider Component
|
|
212
212
|
*/
|
|
213
|
-
function PubflowProvider({ children, config, instances, defaultInstance = 'default',
|
|
214
|
-
const [isInitialized, setIsInitialized] = useState(false);
|
|
213
|
+
function PubflowProvider({ children, config, instances, defaultInstance = 'default', enableDebugTools = false, showSessionAlerts = false, persistentCache = { enabled: false }, theme = {}, loginRedirectPath = '/login', publicPaths = [] }) {
|
|
215
214
|
const [contextValue, setContextValue] = useState({
|
|
216
215
|
instances: {},
|
|
217
216
|
defaultInstance
|
|
218
217
|
});
|
|
219
|
-
//
|
|
220
|
-
useEffect(() => {
|
|
221
|
-
if (enableDebugTools) {
|
|
222
|
-
console.log('Pubflow debug tools enabled');
|
|
223
|
-
// Add debug utilities to window object
|
|
224
|
-
if (typeof window !== 'undefined') {
|
|
225
|
-
window.pubflowDebug = {
|
|
226
|
-
getInstances: () => contextValue.instances,
|
|
227
|
-
getDefaultInstance: () => contextValue.defaultInstance,
|
|
228
|
-
clearStorage: async () => {
|
|
229
|
-
const storage = new BrowserStorageAdapter();
|
|
230
|
-
await storage.removeItem('pubflow_session_id');
|
|
231
|
-
await storage.removeItem('pubflow_user_data');
|
|
232
|
-
console.log('Pubflow storage cleared');
|
|
233
|
-
},
|
|
234
|
-
loginRedirectPath,
|
|
235
|
-
publicPaths,
|
|
236
|
-
theme
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}, [enableDebugTools]); // ✅ OPTIMIZED: Only enableDebugTools as dependency
|
|
241
|
-
// Handle session expiration
|
|
218
|
+
// Session handlers
|
|
242
219
|
const handleSessionExpired = useCallback(() => {
|
|
243
|
-
if (showSessionAlerts) {
|
|
244
|
-
|
|
245
|
-
}
|
|
246
|
-
if (onSessionExpired) {
|
|
247
|
-
onSessionExpired();
|
|
220
|
+
if (showSessionAlerts && typeof window !== 'undefined') {
|
|
221
|
+
console.warn('Session expired');
|
|
248
222
|
}
|
|
249
|
-
}, [
|
|
250
|
-
// Handle session refresh
|
|
223
|
+
}, [showSessionAlerts]);
|
|
251
224
|
const handleSessionRefreshed = useCallback(() => {
|
|
252
|
-
if (showSessionAlerts) {
|
|
253
|
-
|
|
225
|
+
if (showSessionAlerts && typeof window !== 'undefined') {
|
|
226
|
+
console.log('Session refreshed');
|
|
254
227
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
}, [onSessionRefreshed, showSessionAlerts]);
|
|
228
|
+
}, [showSessionAlerts]);
|
|
229
|
+
// Initialize instances
|
|
259
230
|
useEffect(() => {
|
|
260
231
|
let isMounted = true;
|
|
261
232
|
const initialize = async () => {
|
|
262
233
|
var _a, _b;
|
|
263
234
|
try {
|
|
264
|
-
// Initialize instances
|
|
265
235
|
const instancesMap = {};
|
|
266
236
|
if (instances && instances.length > 0) {
|
|
267
237
|
// Initialize multiple instances
|
|
268
238
|
for (const instanceConfig of instances) {
|
|
269
239
|
if (!isMounted)
|
|
270
|
-
return;
|
|
271
|
-
// Initialize configuration
|
|
240
|
+
return;
|
|
272
241
|
const fullConfig = initConfig({
|
|
273
242
|
...instanceConfig,
|
|
274
243
|
sessionConfig: {
|
|
@@ -277,38 +246,21 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
277
246
|
onSessionRefreshed: handleSessionRefreshed
|
|
278
247
|
}
|
|
279
248
|
}, instanceConfig.id);
|
|
280
|
-
// Create storage adapter
|
|
281
249
|
const storage = new BrowserStorageAdapter({
|
|
282
250
|
prefix: (_a = fullConfig.storageConfig) === null || _a === void 0 ? void 0 : _a.prefix
|
|
283
251
|
});
|
|
284
|
-
// Create API client
|
|
285
252
|
const apiClient = new ApiClient(fullConfig, storage);
|
|
286
|
-
// Create auth service
|
|
287
253
|
const authService = new AuthService(apiClient, storage, fullConfig);
|
|
288
|
-
// Get current user (
|
|
254
|
+
// Get current user (non-blocking)
|
|
289
255
|
let user = null;
|
|
290
256
|
let isAuthenticated = false;
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
[instanceConfig.id]: {
|
|
299
|
-
...prev.instances[instanceConfig.id],
|
|
300
|
-
user: currentUser,
|
|
301
|
-
isAuthenticated: true,
|
|
302
|
-
isLoading: false
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}));
|
|
306
|
-
}
|
|
307
|
-
}).catch(error => {
|
|
308
|
-
console.error(`Error getting current user for instance ${instanceConfig.id}:`, error);
|
|
309
|
-
});
|
|
310
|
-
// Create instance with optimized functions
|
|
311
|
-
const createInstanceFunctions = (id) => ({
|
|
257
|
+
instancesMap[instanceConfig.id] = {
|
|
258
|
+
config: fullConfig,
|
|
259
|
+
apiClient,
|
|
260
|
+
authService,
|
|
261
|
+
user,
|
|
262
|
+
isAuthenticated,
|
|
263
|
+
isLoading: true,
|
|
312
264
|
login: async (credentials) => {
|
|
313
265
|
const result = await authService.login(credentials);
|
|
314
266
|
if (result.success && result.user && isMounted) {
|
|
@@ -316,10 +268,11 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
316
268
|
...prev,
|
|
317
269
|
instances: {
|
|
318
270
|
...prev.instances,
|
|
319
|
-
[id]: {
|
|
320
|
-
...prev.instances[id],
|
|
271
|
+
[instanceConfig.id]: {
|
|
272
|
+
...prev.instances[instanceConfig.id],
|
|
321
273
|
user: result.user,
|
|
322
|
-
isAuthenticated: true
|
|
274
|
+
isAuthenticated: true,
|
|
275
|
+
isLoading: false
|
|
323
276
|
}
|
|
324
277
|
}
|
|
325
278
|
}));
|
|
@@ -333,10 +286,11 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
333
286
|
...prev,
|
|
334
287
|
instances: {
|
|
335
288
|
...prev.instances,
|
|
336
|
-
[id]: {
|
|
337
|
-
...prev.instances[id],
|
|
289
|
+
[instanceConfig.id]: {
|
|
290
|
+
...prev.instances[instanceConfig.id],
|
|
338
291
|
user: null,
|
|
339
|
-
isAuthenticated: false
|
|
292
|
+
isAuthenticated: false,
|
|
293
|
+
isLoading: false
|
|
340
294
|
}
|
|
341
295
|
}
|
|
342
296
|
}));
|
|
@@ -349,31 +303,52 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
349
303
|
...prev,
|
|
350
304
|
instances: {
|
|
351
305
|
...prev.instances,
|
|
352
|
-
[id]: {
|
|
353
|
-
...prev.instances[id],
|
|
306
|
+
[instanceConfig.id]: {
|
|
307
|
+
...prev.instances[instanceConfig.id],
|
|
354
308
|
user: result.user || null,
|
|
355
|
-
isAuthenticated: result.isValid
|
|
309
|
+
isAuthenticated: result.isValid,
|
|
310
|
+
isLoading: false
|
|
356
311
|
}
|
|
357
312
|
}
|
|
358
313
|
}));
|
|
359
314
|
}
|
|
360
315
|
return result;
|
|
361
316
|
}
|
|
362
|
-
});
|
|
363
|
-
instancesMap[instanceConfig.id] = {
|
|
364
|
-
config: fullConfig,
|
|
365
|
-
apiClient,
|
|
366
|
-
authService,
|
|
367
|
-
user,
|
|
368
|
-
isAuthenticated,
|
|
369
|
-
isLoading: true, // Start as loading
|
|
370
|
-
...createInstanceFunctions(instanceConfig.id)
|
|
371
317
|
};
|
|
318
|
+
// Load user asynchronously
|
|
319
|
+
authService.getCurrentUser().then(currentUser => {
|
|
320
|
+
if (isMounted) {
|
|
321
|
+
setContextValue(prev => ({
|
|
322
|
+
...prev,
|
|
323
|
+
instances: {
|
|
324
|
+
...prev.instances,
|
|
325
|
+
[instanceConfig.id]: {
|
|
326
|
+
...prev.instances[instanceConfig.id],
|
|
327
|
+
user: currentUser,
|
|
328
|
+
isAuthenticated: !!currentUser,
|
|
329
|
+
isLoading: false
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}));
|
|
333
|
+
}
|
|
334
|
+
}).catch(() => {
|
|
335
|
+
if (isMounted) {
|
|
336
|
+
setContextValue(prev => ({
|
|
337
|
+
...prev,
|
|
338
|
+
instances: {
|
|
339
|
+
...prev.instances,
|
|
340
|
+
[instanceConfig.id]: {
|
|
341
|
+
...prev.instances[instanceConfig.id],
|
|
342
|
+
isLoading: false
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}));
|
|
346
|
+
}
|
|
347
|
+
});
|
|
372
348
|
}
|
|
373
349
|
}
|
|
374
350
|
else if (config) {
|
|
375
|
-
//
|
|
376
|
-
// Initialize configuration
|
|
351
|
+
// Single instance mode (simplified)
|
|
377
352
|
const fullConfig = initConfig({
|
|
378
353
|
...config,
|
|
379
354
|
sessionConfig: {
|
|
@@ -381,37 +356,22 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
381
356
|
onSessionExpired: handleSessionExpired,
|
|
382
357
|
onSessionRefreshed: handleSessionRefreshed
|
|
383
358
|
}
|
|
384
|
-
}, defaultInstance);
|
|
385
|
-
// Create storage adapter
|
|
359
|
+
}, config.id || defaultInstance);
|
|
386
360
|
const storage = new BrowserStorageAdapter({
|
|
387
361
|
prefix: (_b = fullConfig.storageConfig) === null || _b === void 0 ? void 0 : _b.prefix
|
|
388
362
|
});
|
|
389
|
-
// Create API client
|
|
390
363
|
const apiClient = new ApiClient(fullConfig, storage);
|
|
391
|
-
// Create auth service
|
|
392
364
|
const authService = new AuthService(apiClient, storage, fullConfig);
|
|
393
|
-
// Get current user
|
|
394
|
-
let user = null;
|
|
395
|
-
let isAuthenticated = false;
|
|
396
|
-
try {
|
|
397
|
-
user = await authService.getCurrentUser();
|
|
398
|
-
isAuthenticated = !!user;
|
|
399
|
-
}
|
|
400
|
-
catch (error) {
|
|
401
|
-
console.error('Error getting current user:', error);
|
|
402
|
-
}
|
|
403
|
-
// Create instance
|
|
404
365
|
instancesMap[defaultInstance] = {
|
|
405
366
|
config: fullConfig,
|
|
406
367
|
apiClient,
|
|
407
368
|
authService,
|
|
408
|
-
user,
|
|
409
|
-
isAuthenticated,
|
|
410
|
-
isLoading:
|
|
369
|
+
user: null,
|
|
370
|
+
isAuthenticated: false,
|
|
371
|
+
isLoading: true,
|
|
411
372
|
login: async (credentials) => {
|
|
412
373
|
const result = await authService.login(credentials);
|
|
413
|
-
if (result.success && result.user) {
|
|
414
|
-
// Update instance
|
|
374
|
+
if (result.success && result.user && isMounted) {
|
|
415
375
|
setContextValue(prev => ({
|
|
416
376
|
...prev,
|
|
417
377
|
instances: {
|
|
@@ -419,7 +379,8 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
419
379
|
[defaultInstance]: {
|
|
420
380
|
...prev.instances[defaultInstance],
|
|
421
381
|
user: result.user,
|
|
422
|
-
isAuthenticated: true
|
|
382
|
+
isAuthenticated: true,
|
|
383
|
+
isLoading: false
|
|
423
384
|
}
|
|
424
385
|
}
|
|
425
386
|
}));
|
|
@@ -428,65 +389,107 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
428
389
|
},
|
|
429
390
|
logout: async () => {
|
|
430
391
|
await authService.logout();
|
|
431
|
-
|
|
392
|
+
if (isMounted) {
|
|
393
|
+
setContextValue(prev => ({
|
|
394
|
+
...prev,
|
|
395
|
+
instances: {
|
|
396
|
+
...prev.instances,
|
|
397
|
+
[defaultInstance]: {
|
|
398
|
+
...prev.instances[defaultInstance],
|
|
399
|
+
user: null,
|
|
400
|
+
isAuthenticated: false,
|
|
401
|
+
isLoading: false
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}));
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
validateSession: async () => {
|
|
408
|
+
const result = await authService.validateSession();
|
|
409
|
+
if (isMounted) {
|
|
410
|
+
setContextValue(prev => ({
|
|
411
|
+
...prev,
|
|
412
|
+
instances: {
|
|
413
|
+
...prev.instances,
|
|
414
|
+
[defaultInstance]: {
|
|
415
|
+
...prev.instances[defaultInstance],
|
|
416
|
+
user: result.user || null,
|
|
417
|
+
isAuthenticated: result.isValid,
|
|
418
|
+
isLoading: false
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}));
|
|
422
|
+
}
|
|
423
|
+
return result;
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
// Load user asynchronously
|
|
427
|
+
authService.getCurrentUser().then(currentUser => {
|
|
428
|
+
if (isMounted) {
|
|
432
429
|
setContextValue(prev => ({
|
|
433
430
|
...prev,
|
|
434
431
|
instances: {
|
|
435
432
|
...prev.instances,
|
|
436
433
|
[defaultInstance]: {
|
|
437
434
|
...prev.instances[defaultInstance],
|
|
438
|
-
user:
|
|
439
|
-
isAuthenticated:
|
|
435
|
+
user: currentUser,
|
|
436
|
+
isAuthenticated: !!currentUser,
|
|
437
|
+
isLoading: false
|
|
440
438
|
}
|
|
441
439
|
}
|
|
442
440
|
}));
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
// Update instance
|
|
441
|
+
}
|
|
442
|
+
}).catch(() => {
|
|
443
|
+
if (isMounted) {
|
|
447
444
|
setContextValue(prev => ({
|
|
448
445
|
...prev,
|
|
449
446
|
instances: {
|
|
450
447
|
...prev.instances,
|
|
451
448
|
[defaultInstance]: {
|
|
452
449
|
...prev.instances[defaultInstance],
|
|
453
|
-
|
|
454
|
-
isAuthenticated: result.isValid
|
|
450
|
+
isLoading: false
|
|
455
451
|
}
|
|
456
452
|
}
|
|
457
453
|
}));
|
|
458
|
-
return result;
|
|
459
454
|
}
|
|
460
|
-
};
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
if (isMounted) {
|
|
458
|
+
setContextValue({
|
|
459
|
+
instances: instancesMap,
|
|
460
|
+
defaultInstance
|
|
461
|
+
});
|
|
461
462
|
}
|
|
462
|
-
// Set context value
|
|
463
|
-
setContextValue({
|
|
464
|
-
instances: instancesMap,
|
|
465
|
-
defaultInstance
|
|
466
|
-
});
|
|
467
|
-
// Set initialized
|
|
468
|
-
setIsInitialized(true);
|
|
469
463
|
}
|
|
470
464
|
catch (error) {
|
|
471
465
|
console.error('Error initializing Pubflow:', error);
|
|
472
466
|
}
|
|
473
467
|
};
|
|
474
468
|
initialize();
|
|
475
|
-
// Cleanup function
|
|
476
469
|
return () => {
|
|
477
470
|
isMounted = false;
|
|
478
471
|
};
|
|
479
472
|
}, [config, instances, defaultInstance, handleSessionExpired, handleSessionRefreshed]);
|
|
480
|
-
//
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
473
|
+
// Debug tools (simplified)
|
|
474
|
+
useEffect(() => {
|
|
475
|
+
if (enableDebugTools && typeof window !== 'undefined') {
|
|
476
|
+
window.pubflowDebug = {
|
|
477
|
+
getInstances: () => contextValue.instances,
|
|
478
|
+
getDefaultInstance: () => contextValue.defaultInstance
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
}, [enableDebugTools]);
|
|
482
|
+
// SWR configuration
|
|
483
|
+
const swrConfig = {
|
|
484
|
+
revalidateOnFocus: false,
|
|
485
|
+
revalidateOnReconnect: true,
|
|
486
|
+
...(persistentCache.enabled && {
|
|
487
|
+
provider: () => new Map(),
|
|
488
|
+
isOnline: () => true,
|
|
489
|
+
isVisible: () => true
|
|
490
|
+
})
|
|
491
|
+
};
|
|
492
|
+
return (jsx(PubflowContext.Provider, { value: contextValue, children: jsx(SWRConfig, { value: swrConfig, children: children }) }));
|
|
490
493
|
}
|
|
491
494
|
|
|
492
495
|
/**
|
|
@@ -502,7 +505,6 @@ function PubflowProvider({ children, config, instances, defaultInstance = 'defau
|
|
|
502
505
|
*/
|
|
503
506
|
function useAuth(instanceId) {
|
|
504
507
|
const context = useContext(PubflowContext);
|
|
505
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
506
508
|
if (!context) {
|
|
507
509
|
throw new Error('useAuth must be used within a PubflowProvider');
|
|
508
510
|
}
|
|
@@ -511,68 +513,14 @@ function useAuth(instanceId) {
|
|
|
511
513
|
if (!pubflowInstance) {
|
|
512
514
|
throw new Error(`Pubflow instance '${instance}' not found`);
|
|
513
515
|
}
|
|
514
|
-
// Wrap login to handle loading state
|
|
515
|
-
const login = useCallback(async (credentials) => {
|
|
516
|
-
setIsLoading(true);
|
|
517
|
-
try {
|
|
518
|
-
return await pubflowInstance.login(credentials);
|
|
519
|
-
}
|
|
520
|
-
finally {
|
|
521
|
-
setIsLoading(false);
|
|
522
|
-
}
|
|
523
|
-
}, [pubflowInstance]);
|
|
524
|
-
// Wrap logout to handle loading state
|
|
525
|
-
const logout = useCallback(async () => {
|
|
526
|
-
setIsLoading(true);
|
|
527
|
-
try {
|
|
528
|
-
await pubflowInstance.logout();
|
|
529
|
-
}
|
|
530
|
-
finally {
|
|
531
|
-
setIsLoading(false);
|
|
532
|
-
}
|
|
533
|
-
}, [pubflowInstance]);
|
|
534
|
-
// Wrap validateSession to handle loading state
|
|
535
|
-
const validateSession = useCallback(async () => {
|
|
536
|
-
setIsLoading(true);
|
|
537
|
-
try {
|
|
538
|
-
return await pubflowInstance.validateSession();
|
|
539
|
-
}
|
|
540
|
-
finally {
|
|
541
|
-
setIsLoading(false);
|
|
542
|
-
}
|
|
543
|
-
}, [pubflowInstance]);
|
|
544
|
-
// Add refreshUser function to manually refresh user data
|
|
545
|
-
const refreshUser = useCallback(async () => {
|
|
546
|
-
setIsLoading(true);
|
|
547
|
-
try {
|
|
548
|
-
const result = await pubflowInstance.validateSession();
|
|
549
|
-
return result.user || null;
|
|
550
|
-
}
|
|
551
|
-
finally {
|
|
552
|
-
setIsLoading(false);
|
|
553
|
-
}
|
|
554
|
-
}, [pubflowInstance]);
|
|
555
|
-
// Validate session on mount
|
|
556
|
-
useEffect(() => {
|
|
557
|
-
const validate = async () => {
|
|
558
|
-
try {
|
|
559
|
-
await validateSession();
|
|
560
|
-
}
|
|
561
|
-
catch (error) {
|
|
562
|
-
console.error('Error validating session:', error);
|
|
563
|
-
}
|
|
564
|
-
};
|
|
565
|
-
validate();
|
|
566
|
-
}, [validateSession]);
|
|
567
516
|
return {
|
|
568
517
|
// Ensure user is never undefined
|
|
569
518
|
user: pubflowInstance.user || null,
|
|
570
519
|
isAuthenticated: pubflowInstance.isAuthenticated,
|
|
571
|
-
isLoading,
|
|
572
|
-
login,
|
|
573
|
-
logout,
|
|
574
|
-
validateSession
|
|
575
|
-
refreshUser
|
|
520
|
+
isLoading: pubflowInstance.isLoading,
|
|
521
|
+
login: pubflowInstance.login,
|
|
522
|
+
logout: pubflowInstance.logout,
|
|
523
|
+
validateSession: pubflowInstance.validateSession
|
|
576
524
|
};
|
|
577
525
|
}
|
|
578
526
|
|
|
@@ -8611,6 +8559,68 @@ function BridgeList({ renderItem, showPagination = true, showSearch = true, show
|
|
|
8611
8559
|
}) })), renderPagination()] })] })] }));
|
|
8612
8560
|
}
|
|
8613
8561
|
|
|
8562
|
+
/**
|
|
8563
|
+
* Asset Utilities for Pubflow React
|
|
8564
|
+
*
|
|
8565
|
+
* Utilities for handling assets like logos, images, and other media files
|
|
8566
|
+
* Supports both external URLs and internal assets with proper Vite/bundler integration
|
|
8567
|
+
*/
|
|
8568
|
+
/**
|
|
8569
|
+
* Process asset URL - supports both external URLs and internal assets
|
|
8570
|
+
*
|
|
8571
|
+
* @param assetUrl - The asset URL to process
|
|
8572
|
+
* @returns Processed URL ready for use in src attributes
|
|
8573
|
+
*/
|
|
8574
|
+
function processAssetUrl(assetUrl) {
|
|
8575
|
+
// Return non-string values as-is (React components, null, undefined)
|
|
8576
|
+
if (!assetUrl || typeof assetUrl !== 'string') {
|
|
8577
|
+
return assetUrl;
|
|
8578
|
+
}
|
|
8579
|
+
// Return empty string as-is (no logo case)
|
|
8580
|
+
if (assetUrl.trim() === '') {
|
|
8581
|
+
return '';
|
|
8582
|
+
}
|
|
8583
|
+
// Check if it's an external URL (starts with http:// or https://)
|
|
8584
|
+
if (assetUrl.startsWith('http://') || assetUrl.startsWith('https://')) {
|
|
8585
|
+
return assetUrl;
|
|
8586
|
+
}
|
|
8587
|
+
// Check if it's a data URL (base64 encoded image)
|
|
8588
|
+
if (assetUrl.startsWith('data:')) {
|
|
8589
|
+
return assetUrl;
|
|
8590
|
+
}
|
|
8591
|
+
// Check if it's already a processed Vite asset (starts with /)
|
|
8592
|
+
if (assetUrl.startsWith('/')) {
|
|
8593
|
+
return assetUrl;
|
|
8594
|
+
}
|
|
8595
|
+
// Check if it's a blob URL
|
|
8596
|
+
if (assetUrl.startsWith('blob:')) {
|
|
8597
|
+
return assetUrl;
|
|
8598
|
+
}
|
|
8599
|
+
// For relative paths or simple filenames, assume they're in the public directory
|
|
8600
|
+
// This handles cases like 'logo.svg', './logo.png', '../assets/logo.jpg', etc.
|
|
8601
|
+
if (assetUrl.includes('.')) {
|
|
8602
|
+
// Remove leading ./ if present
|
|
8603
|
+
const cleanPath = assetUrl.replace(/^\.\//, '');
|
|
8604
|
+
// If it starts with ../, keep it as is (relative to current directory)
|
|
8605
|
+
if (assetUrl.startsWith('../')) {
|
|
8606
|
+
return assetUrl;
|
|
8607
|
+
}
|
|
8608
|
+
// For simple filenames or paths, prepend with /
|
|
8609
|
+
return `/${cleanPath}`;
|
|
8610
|
+
}
|
|
8611
|
+
// Return as-is for any other cases
|
|
8612
|
+
return assetUrl;
|
|
8613
|
+
}
|
|
8614
|
+
/**
|
|
8615
|
+
* Process logo URL specifically - alias for processAssetUrl with better naming
|
|
8616
|
+
*
|
|
8617
|
+
* @param logoUrl - The logo URL to process
|
|
8618
|
+
* @returns Processed URL ready for use in img src
|
|
8619
|
+
*/
|
|
8620
|
+
function processLogoUrl(logoUrl) {
|
|
8621
|
+
return processAssetUrl(logoUrl);
|
|
8622
|
+
}
|
|
8623
|
+
|
|
8614
8624
|
/**
|
|
8615
8625
|
* Professional login form component
|
|
8616
8626
|
*/
|
|
@@ -8791,7 +8801,7 @@ function LoginForm({ config = {}, onSuccess, onError, onPasswordReset, onAccount
|
|
|
8791
8801
|
textAlign: 'center'
|
|
8792
8802
|
}
|
|
8793
8803
|
};
|
|
8794
|
-
return (jsxs("div", { className: className, style: styles.container, children: [jsxs("div", { style: styles.logoSection, children: [logo && (typeof logo === 'string' ? (jsx("img", { src: logo, alt: `${appName} Logo`, style: styles.logo })) : (logo)), jsxs("h1", { style: styles.welcomeText, children: ["Welcome to ", appName] }), jsx("p", { style: styles.subtitleText, children: "Sign in to your account" })] }), jsxs("form", { onSubmit: handleSubmit, children: [error && (jsxs("div", { style: styles.errorContainer, children: [jsx("span", { style: { color: '#ff4757', fontSize: '20px' }, children: "\u26A0" }), jsx("span", { style: styles.errorText, children: error })] })), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "Email Address" }), jsxs("div", { style: styles.inputContainer, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\u2709" }), jsx("input", { type: "email", style: styles.input, placeholder: "Enter your email", value: email, onChange: (e) => setEmail(e.target.value), autoCapitalize: "none", autoComplete: "email", disabled: isLoading, required: true })] })] }), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "Password" }), jsxs("div", { style: styles.inputContainer, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\uD83D\uDD12" }), jsx("input", { type: showPassword ? 'text' : 'password', style: styles.input, placeholder: "Enter your password", value: password, onChange: (e) => setPassword(e.target.value), autoComplete: "current-password", disabled: isLoading, required: true }), jsx("button", { type: "button", style: styles.eyeButton, onClick: () => setShowPassword(!showPassword), disabled: isLoading, children: showPassword ? '👁' : '👁🗨' })] })] }), jsxs("div", { style: styles.checkboxContainer, children: [jsxs("label", { style: { display: 'flex', alignItems: 'center', fontSize: '14px', color: '#666' }, children: [jsx("input", { type: "checkbox", checked: rememberMe, onChange: (e) => setRememberMe(e.target.checked), style: { marginRight: '8px' } }), "Remember me"] }), showPasswordReset && (jsx("button", { type: "button", style: { ...styles.linkButton, fontSize: '14px' }, onClick: onPasswordReset, disabled: isLoading, children: "Forgot password?" }))] }), jsx("button", { type: "submit", style: {
|
|
8804
|
+
return (jsxs("div", { className: className, style: styles.container, children: [jsxs("div", { style: styles.logoSection, children: [logo && (typeof logo === 'string' ? (jsx("img", { src: processLogoUrl(logo), alt: `${appName} Logo`, style: styles.logo })) : (logo)), jsxs("h1", { style: styles.welcomeText, children: ["Welcome to ", appName] }), jsx("p", { style: styles.subtitleText, children: "Sign in to your account" })] }), jsxs("form", { onSubmit: handleSubmit, children: [error && (jsxs("div", { style: styles.errorContainer, children: [jsx("span", { style: { color: '#ff4757', fontSize: '20px' }, children: "\u26A0" }), jsx("span", { style: styles.errorText, children: error })] })), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "Email Address" }), jsxs("div", { style: styles.inputContainer, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\u2709" }), jsx("input", { type: "email", style: styles.input, placeholder: "Enter your email", value: email, onChange: (e) => setEmail(e.target.value), autoCapitalize: "none", autoComplete: "email", disabled: isLoading, required: true })] })] }), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "Password" }), jsxs("div", { style: styles.inputContainer, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\uD83D\uDD12" }), jsx("input", { type: showPassword ? 'text' : 'password', style: styles.input, placeholder: "Enter your password", value: password, onChange: (e) => setPassword(e.target.value), autoComplete: "current-password", disabled: isLoading, required: true }), jsx("button", { type: "button", style: styles.eyeButton, onClick: () => setShowPassword(!showPassword), disabled: isLoading, children: showPassword ? '👁' : '👁🗨' })] })] }), jsxs("div", { style: styles.checkboxContainer, children: [jsxs("label", { style: { display: 'flex', alignItems: 'center', fontSize: '14px', color: '#666' }, children: [jsx("input", { type: "checkbox", checked: rememberMe, onChange: (e) => setRememberMe(e.target.checked), style: { marginRight: '8px' } }), "Remember me"] }), showPasswordReset && (jsx("button", { type: "button", style: { ...styles.linkButton, fontSize: '14px' }, onClick: onPasswordReset, disabled: isLoading, children: "Forgot password?" }))] }), jsx("button", { type: "submit", style: {
|
|
8795
8805
|
...styles.loginButton,
|
|
8796
8806
|
opacity: isLoading ? 0.8 : 1,
|
|
8797
8807
|
cursor: isLoading ? 'not-allowed' : 'pointer'
|
|
@@ -9041,7 +9051,7 @@ function PasswordResetForm({ config = {}, onSuccess, onError, onBackToLogin, res
|
|
|
9041
9051
|
const renderStep = () => {
|
|
9042
9052
|
switch (step) {
|
|
9043
9053
|
case 'request':
|
|
9044
|
-
return (jsxs(Fragment, { children: [jsxs("div", { style: styles.logoSection, children: [logo && (typeof logo === 'string' ? (jsx("img", { src: logo, alt: `${appName} Logo`, style: styles.logo })) : (logo)), jsx("h1", { style: styles.title, children: "Reset Password" }), jsx("p", { style: styles.subtitle, children: "Enter your email to receive reset instructions" })] }), jsxs("form", { onSubmit: handleRequestReset, children: [error && (jsxs("div", { style: styles.errorContainer, children: [jsx("span", { style: { color: '#ff4757', fontSize: '20px' }, children: "\u26A0" }), jsx("span", { style: styles.errorText, children: error })] })), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "Email Address" }), jsxs("div", { style: styles.inputContainer, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\u2709" }), jsx("input", { type: "email", style: styles.input, placeholder: "Enter your email", value: email, onChange: (e) => setEmail(e.target.value), autoCapitalize: "none", autoComplete: "email", disabled: isLoading, required: true })] })] }), jsx("button", { type: "submit", style: {
|
|
9054
|
+
return (jsxs(Fragment, { children: [jsxs("div", { style: styles.logoSection, children: [logo && (typeof logo === 'string' ? (jsx("img", { src: processLogoUrl(logo), alt: `${appName} Logo`, style: styles.logo })) : (logo)), jsx("h1", { style: styles.title, children: "Reset Password" }), jsx("p", { style: styles.subtitle, children: "Enter your email to receive reset instructions" })] }), jsxs("form", { onSubmit: handleRequestReset, children: [error && (jsxs("div", { style: styles.errorContainer, children: [jsx("span", { style: { color: '#ff4757', fontSize: '20px' }, children: "\u26A0" }), jsx("span", { style: styles.errorText, children: error })] })), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "Email Address" }), jsxs("div", { style: styles.inputContainer, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\u2709" }), jsx("input", { type: "email", style: styles.input, placeholder: "Enter your email", value: email, onChange: (e) => setEmail(e.target.value), autoCapitalize: "none", autoComplete: "email", disabled: isLoading, required: true })] })] }), jsx("button", { type: "submit", style: {
|
|
9045
9055
|
...styles.button,
|
|
9046
9056
|
opacity: isLoading ? 0.8 : 1,
|
|
9047
9057
|
cursor: isLoading ? 'not-allowed' : 'pointer'
|
|
@@ -9305,7 +9315,7 @@ function AccountCreationForm({ config = {}, onSuccess, onError, onBackToLogin })
|
|
|
9305
9315
|
const renderStep = () => {
|
|
9306
9316
|
switch (step) {
|
|
9307
9317
|
case 'form':
|
|
9308
|
-
return (jsxs(Fragment, { children: [jsxs("div", { style: styles.logoSection, children: [logo && (typeof logo === 'string' ? (jsx("img", { src: logo, alt: `${appName} Logo`, style: styles.logo })) : (logo)), jsx("h1", { style: styles.title, children: "Create Account" }), jsxs("p", { style: styles.subtitle, children: ["Join ", appName, " today"] })] }), jsxs("form", { onSubmit: handleSubmit, children: [errors.general && (jsxs("div", { style: { ...styles.successContainer, backgroundColor: '#fef2f2', borderColor: '#fecaca' }, children: [jsx("span", { style: { color: '#ff4757', fontSize: '20px' }, children: "\u26A0" }), jsx("span", { style: { ...styles.successText, color: '#dc2626' }, children: errors.general })] })), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "First Name *" }), jsxs("div", { style: { ...styles.inputContainer, ...(errors.name ? styles.inputError : {}) }, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\uD83D\uDC64" }), jsx("input", { type: "text", style: styles.input, placeholder: "Enter your first name", value: formData.name, onChange: (e) => updateField('name', e.target.value), autoComplete: "given-name", disabled: isLoading, required: true })] }), errors.name && jsx("div", { style: styles.errorText, children: errors.name })] }), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "Last Name *" }), jsxs("div", { style: { ...styles.inputContainer, ...(errors.lastName ? styles.inputError : {}) }, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\uD83D\uDC64" }), jsx("input", { type: "text", style: styles.input, placeholder: "Enter your last name", value: formData.lastName, onChange: (e) => updateField('lastName', e.target.value), autoComplete: "family-name", disabled: isLoading, required: true })] }), errors.lastName && jsx("div", { style: styles.errorText, children: errors.lastName })] }), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "Email Address *" }), jsxs("div", { style: { ...styles.inputContainer, ...(errors.email ? styles.inputError : {}) }, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\u2709" }), jsx("input", { type: "email", style: styles.input, placeholder: "Enter your email", value: formData.email, onChange: (e) => updateField('email', e.target.value), autoCapitalize: "none", autoComplete: "email", disabled: isLoading, required: true })] }), errors.email && jsx("div", { style: styles.errorText, children: errors.email })] }), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "Password *" }), jsxs("div", { style: { ...styles.inputContainer, ...(errors.password ? styles.inputError : {}) }, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\uD83D\uDD12" }), jsx("input", { type: showPassword ? 'text' : 'password', style: styles.input, placeholder: "Create a password", value: formData.password, onChange: (e) => updateField('password', e.target.value), autoComplete: "new-password", disabled: isLoading, required: true }), jsx("button", { type: "button", style: styles.eyeButton, onClick: () => setShowPassword(!showPassword), disabled: isLoading, children: showPassword ? '👁' : '👁🗨' })] }), errors.password && jsx("div", { style: styles.errorText, children: errors.password })] }), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "Confirm Password *" }), jsxs("div", { style: { ...styles.inputContainer, ...(errors.confirmPassword ? styles.inputError : {}) }, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\uD83D\uDD12" }), jsx("input", { type: showConfirmPassword ? 'text' : 'password', style: styles.input, placeholder: "Confirm your password", value: formData.confirmPassword, onChange: (e) => updateField('confirmPassword', e.target.value), autoComplete: "new-password", disabled: isLoading, required: true }), jsx("button", { type: "button", style: styles.eyeButton, onClick: () => setShowConfirmPassword(!showConfirmPassword), disabled: isLoading, children: showConfirmPassword ? '👁' : '👁🗨' })] }), errors.confirmPassword && jsx("div", { style: styles.errorText, children: errors.confirmPassword })] }), jsx("button", { type: "submit", style: {
|
|
9318
|
+
return (jsxs(Fragment, { children: [jsxs("div", { style: styles.logoSection, children: [logo && (typeof logo === 'string' ? (jsx("img", { src: processLogoUrl(logo), alt: `${appName} Logo`, style: styles.logo })) : (logo)), jsx("h1", { style: styles.title, children: "Create Account" }), jsxs("p", { style: styles.subtitle, children: ["Join ", appName, " today"] })] }), jsxs("form", { onSubmit: handleSubmit, children: [errors.general && (jsxs("div", { style: { ...styles.successContainer, backgroundColor: '#fef2f2', borderColor: '#fecaca' }, children: [jsx("span", { style: { color: '#ff4757', fontSize: '20px' }, children: "\u26A0" }), jsx("span", { style: { ...styles.successText, color: '#dc2626' }, children: errors.general })] })), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "First Name *" }), jsxs("div", { style: { ...styles.inputContainer, ...(errors.name ? styles.inputError : {}) }, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\uD83D\uDC64" }), jsx("input", { type: "text", style: styles.input, placeholder: "Enter your first name", value: formData.name, onChange: (e) => updateField('name', e.target.value), autoComplete: "given-name", disabled: isLoading, required: true })] }), errors.name && jsx("div", { style: styles.errorText, children: errors.name })] }), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "Last Name *" }), jsxs("div", { style: { ...styles.inputContainer, ...(errors.lastName ? styles.inputError : {}) }, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\uD83D\uDC64" }), jsx("input", { type: "text", style: styles.input, placeholder: "Enter your last name", value: formData.lastName, onChange: (e) => updateField('lastName', e.target.value), autoComplete: "family-name", disabled: isLoading, required: true })] }), errors.lastName && jsx("div", { style: styles.errorText, children: errors.lastName })] }), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "Email Address *" }), jsxs("div", { style: { ...styles.inputContainer, ...(errors.email ? styles.inputError : {}) }, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\u2709" }), jsx("input", { type: "email", style: styles.input, placeholder: "Enter your email", value: formData.email, onChange: (e) => updateField('email', e.target.value), autoCapitalize: "none", autoComplete: "email", disabled: isLoading, required: true })] }), errors.email && jsx("div", { style: styles.errorText, children: errors.email })] }), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "Password *" }), jsxs("div", { style: { ...styles.inputContainer, ...(errors.password ? styles.inputError : {}) }, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\uD83D\uDD12" }), jsx("input", { type: showPassword ? 'text' : 'password', style: styles.input, placeholder: "Create a password", value: formData.password, onChange: (e) => updateField('password', e.target.value), autoComplete: "new-password", disabled: isLoading, required: true }), jsx("button", { type: "button", style: styles.eyeButton, onClick: () => setShowPassword(!showPassword), disabled: isLoading, children: showPassword ? '👁' : '👁🗨' })] }), errors.password && jsx("div", { style: styles.errorText, children: errors.password })] }), jsxs("div", { style: styles.inputGroup, children: [jsx("label", { style: styles.inputLabel, children: "Confirm Password *" }), jsxs("div", { style: { ...styles.inputContainer, ...(errors.confirmPassword ? styles.inputError : {}) }, children: [jsx("span", { style: { marginRight: '12px', opacity: 0.7, color: '#666' }, children: "\uD83D\uDD12" }), jsx("input", { type: showConfirmPassword ? 'text' : 'password', style: styles.input, placeholder: "Confirm your password", value: formData.confirmPassword, onChange: (e) => updateField('confirmPassword', e.target.value), autoComplete: "new-password", disabled: isLoading, required: true }), jsx("button", { type: "button", style: styles.eyeButton, onClick: () => setShowConfirmPassword(!showConfirmPassword), disabled: isLoading, children: showConfirmPassword ? '👁' : '👁🗨' })] }), errors.confirmPassword && jsx("div", { style: styles.errorText, children: errors.confirmPassword })] }), jsx("button", { type: "submit", style: {
|
|
9309
9319
|
...styles.button,
|
|
9310
9320
|
opacity: isLoading ? 0.8 : 1,
|
|
9311
9321
|
cursor: isLoading ? 'not-allowed' : 'pointer'
|
|
@@ -9582,6 +9592,131 @@ function createStyles(theme) {
|
|
|
9582
9592
|
};
|
|
9583
9593
|
}
|
|
9584
9594
|
|
|
9595
|
+
/**
|
|
9596
|
+
* Authentication Guard Hook for React
|
|
9597
|
+
*
|
|
9598
|
+
* Framework-agnostic hook for handling authentication validation and redirects
|
|
9599
|
+
*/
|
|
9600
|
+
/**
|
|
9601
|
+
* Hook for handling authentication validation and redirects
|
|
9602
|
+
*
|
|
9603
|
+
* This hook is framework-agnostic and requires the user to provide
|
|
9604
|
+
* their own redirect function (e.g., Next.js router, React Router, etc.)
|
|
9605
|
+
*
|
|
9606
|
+
* @param options Hook options
|
|
9607
|
+
* @returns Authentication guard result
|
|
9608
|
+
*/
|
|
9609
|
+
function useAuthGuard({ validateOnMount = true, allowedTypes = ['authenticated'], instanceId, onRedirect, onSessionExpired, loginRedirectPath = '/login', accessDeniedPath = '/access-denied', enableLogging = false } = {}) {
|
|
9610
|
+
const { user, isAuthenticated, isLoading, validateSession } = useAuth(instanceId);
|
|
9611
|
+
// Check if user is authorized based on user type
|
|
9612
|
+
const isAuthorized = useCallback(() => {
|
|
9613
|
+
if (!isAuthenticated || !user) {
|
|
9614
|
+
return false;
|
|
9615
|
+
}
|
|
9616
|
+
// If allowedTypes includes 'authenticated', any authenticated user is allowed
|
|
9617
|
+
if (allowedTypes.includes('authenticated')) {
|
|
9618
|
+
return true;
|
|
9619
|
+
}
|
|
9620
|
+
// Check specific user types
|
|
9621
|
+
const userType = user.userType || user.user_type || '';
|
|
9622
|
+
return allowedTypes.some(type => type.toLowerCase() === userType.toLowerCase());
|
|
9623
|
+
}, [isAuthenticated, user, allowedTypes]);
|
|
9624
|
+
const authorized = isAuthorized();
|
|
9625
|
+
// Determine redirect reason
|
|
9626
|
+
const getRedirectReason = useCallback(() => {
|
|
9627
|
+
if (isLoading) {
|
|
9628
|
+
return null;
|
|
9629
|
+
}
|
|
9630
|
+
if (!isAuthenticated) {
|
|
9631
|
+
return 'unauthenticated';
|
|
9632
|
+
}
|
|
9633
|
+
if (!authorized) {
|
|
9634
|
+
return 'unauthorized';
|
|
9635
|
+
}
|
|
9636
|
+
return null;
|
|
9637
|
+
}, [isLoading, isAuthenticated, authorized]);
|
|
9638
|
+
const redirectReason = getRedirectReason();
|
|
9639
|
+
// Validate session on mount
|
|
9640
|
+
useEffect(() => {
|
|
9641
|
+
if (validateOnMount && isAuthenticated) {
|
|
9642
|
+
validateSession().then(({ isValid }) => {
|
|
9643
|
+
if (!isValid) {
|
|
9644
|
+
if (enableLogging) {
|
|
9645
|
+
console.warn('useAuthGuard: Session validation failed');
|
|
9646
|
+
}
|
|
9647
|
+
// Call session expired handler
|
|
9648
|
+
if (onSessionExpired) {
|
|
9649
|
+
onSessionExpired();
|
|
9650
|
+
}
|
|
9651
|
+
// Redirect to login
|
|
9652
|
+
if (onRedirect) {
|
|
9653
|
+
onRedirect(loginRedirectPath, 'session-expired');
|
|
9654
|
+
}
|
|
9655
|
+
}
|
|
9656
|
+
}).catch(error => {
|
|
9657
|
+
if (enableLogging) {
|
|
9658
|
+
console.error('useAuthGuard: Session validation error:', error);
|
|
9659
|
+
}
|
|
9660
|
+
});
|
|
9661
|
+
}
|
|
9662
|
+
}, [validateOnMount, isAuthenticated, validateSession, onSessionExpired, onRedirect, loginRedirectPath, enableLogging]);
|
|
9663
|
+
// Handle authentication redirects
|
|
9664
|
+
useEffect(() => {
|
|
9665
|
+
if (isLoading || !onRedirect) {
|
|
9666
|
+
return;
|
|
9667
|
+
}
|
|
9668
|
+
if (!isAuthenticated) {
|
|
9669
|
+
if (enableLogging) {
|
|
9670
|
+
console.warn('useAuthGuard: User not authenticated, redirecting to login');
|
|
9671
|
+
}
|
|
9672
|
+
onRedirect(loginRedirectPath, 'unauthenticated');
|
|
9673
|
+
return;
|
|
9674
|
+
}
|
|
9675
|
+
if (!authorized) {
|
|
9676
|
+
if (enableLogging) {
|
|
9677
|
+
console.warn('useAuthGuard: User not authorized for this page, redirecting to access denied');
|
|
9678
|
+
}
|
|
9679
|
+
onRedirect(accessDeniedPath, 'unauthorized');
|
|
9680
|
+
return;
|
|
9681
|
+
}
|
|
9682
|
+
}, [isLoading, isAuthenticated, authorized, onRedirect, loginRedirectPath, accessDeniedPath, enableLogging]);
|
|
9683
|
+
return {
|
|
9684
|
+
user,
|
|
9685
|
+
isAuthenticated,
|
|
9686
|
+
isLoading,
|
|
9687
|
+
isAuthorized: authorized,
|
|
9688
|
+
validateSession,
|
|
9689
|
+
redirectReason
|
|
9690
|
+
};
|
|
9691
|
+
}
|
|
9692
|
+
/**
|
|
9693
|
+
* Simple authentication guard hook with automatic redirects
|
|
9694
|
+
*
|
|
9695
|
+
* This is a simplified version that uses window.location for redirects
|
|
9696
|
+
* Suitable for simple React apps without complex routing
|
|
9697
|
+
*
|
|
9698
|
+
* @param options Hook options
|
|
9699
|
+
* @returns Authentication guard result
|
|
9700
|
+
*/
|
|
9701
|
+
function useSimpleAuthGuard(options = {}) {
|
|
9702
|
+
var _a;
|
|
9703
|
+
const handleRedirect = useCallback((path, reason) => {
|
|
9704
|
+
if (typeof window !== 'undefined') {
|
|
9705
|
+
// Add current path as redirect parameter
|
|
9706
|
+
const currentPath = window.location.pathname + window.location.search;
|
|
9707
|
+
const redirectUrl = reason === 'unauthenticated'
|
|
9708
|
+
? `${path}?redirect=${encodeURIComponent(currentPath)}`
|
|
9709
|
+
: path;
|
|
9710
|
+
window.location.href = redirectUrl;
|
|
9711
|
+
}
|
|
9712
|
+
}, []);
|
|
9713
|
+
return useAuthGuard({
|
|
9714
|
+
...options,
|
|
9715
|
+
onRedirect: handleRedirect,
|
|
9716
|
+
enableLogging: (_a = options.enableLogging) !== null && _a !== void 0 ? _a : true
|
|
9717
|
+
});
|
|
9718
|
+
}
|
|
9719
|
+
|
|
9585
9720
|
/**
|
|
9586
9721
|
* Bridge API Raw Hook for React
|
|
9587
9722
|
*
|
|
@@ -9661,65 +9796,6 @@ function useBridgeApiRaw(instanceId) {
|
|
|
9661
9796
|
};
|
|
9662
9797
|
}
|
|
9663
9798
|
|
|
9664
|
-
/**
|
|
9665
|
-
* Server Authentication Hook for React
|
|
9666
|
-
*
|
|
9667
|
-
* Provides a hook for handling authentication with automatic redirects
|
|
9668
|
-
*/
|
|
9669
|
-
/**
|
|
9670
|
-
* Hook for handling authentication with automatic redirects
|
|
9671
|
-
*
|
|
9672
|
-
* @param options Hook options
|
|
9673
|
-
* @returns Authentication hook result
|
|
9674
|
-
*/
|
|
9675
|
-
function useServerAuth({ loginRedirectPath = '/login', allowedTypes = ['authenticated'], validateOnMount = true, instanceId, onRedirect } = {}) {
|
|
9676
|
-
const { user, isAuthenticated, isLoading, validateSession } = useAuth(instanceId);
|
|
9677
|
-
// Default redirect function
|
|
9678
|
-
const defaultRedirect = (path) => {
|
|
9679
|
-
if (typeof window !== 'undefined') {
|
|
9680
|
-
const currentPath = window.location.pathname;
|
|
9681
|
-
const redirectUrl = `${path}?redirect=${encodeURIComponent(currentPath)}`;
|
|
9682
|
-
window.location.href = redirectUrl;
|
|
9683
|
-
}
|
|
9684
|
-
};
|
|
9685
|
-
const redirect = onRedirect || defaultRedirect;
|
|
9686
|
-
useEffect(() => {
|
|
9687
|
-
// Validate session on mount if configured
|
|
9688
|
-
if (validateOnMount) {
|
|
9689
|
-
validateSession().then(({ isValid }) => {
|
|
9690
|
-
if (!isValid) {
|
|
9691
|
-
redirect(loginRedirectPath);
|
|
9692
|
-
}
|
|
9693
|
-
});
|
|
9694
|
-
}
|
|
9695
|
-
}, [validateOnMount, loginRedirectPath, validateSession, redirect]);
|
|
9696
|
-
useEffect(() => {
|
|
9697
|
-
// Skip if still loading
|
|
9698
|
-
if (isLoading) {
|
|
9699
|
-
return;
|
|
9700
|
-
}
|
|
9701
|
-
// Redirect if not authenticated
|
|
9702
|
-
if (!isAuthenticated) {
|
|
9703
|
-
redirect(loginRedirectPath);
|
|
9704
|
-
return;
|
|
9705
|
-
}
|
|
9706
|
-
// Check user type if allowedTypes doesn't include 'authenticated'
|
|
9707
|
-
if (!allowedTypes.includes('authenticated') && user) {
|
|
9708
|
-
const userType = user.userType || '';
|
|
9709
|
-
const isAllowed = allowedTypes.some(type => type.toLowerCase() === userType.toLowerCase());
|
|
9710
|
-
if (!isAllowed) {
|
|
9711
|
-
redirect('/access-denied');
|
|
9712
|
-
}
|
|
9713
|
-
}
|
|
9714
|
-
}, [isLoading, isAuthenticated, user, allowedTypes, loginRedirectPath, redirect]);
|
|
9715
|
-
return {
|
|
9716
|
-
user,
|
|
9717
|
-
isAuthenticated,
|
|
9718
|
-
isLoading,
|
|
9719
|
-
validateSession
|
|
9720
|
-
};
|
|
9721
|
-
}
|
|
9722
|
-
|
|
9723
9799
|
/**
|
|
9724
9800
|
* Search Query Builder Hook for React
|
|
9725
9801
|
*
|
|
@@ -9941,5 +10017,5 @@ function useRequireAuth(options = {}) {
|
|
|
9941
10017
|
};
|
|
9942
10018
|
}
|
|
9943
10019
|
|
|
9944
|
-
export { AccountCreationForm, AdvancedFilter, BridgeForm, BridgeList, BridgeTable, BridgeView, BrowserStorageAdapter, LoginForm, OfflineIndicator, PasswordResetForm, PubflowContext, PubflowProvider, ThemeProvider, createStyles, generateCSSVariables, useAuth, useBridgeApi, useBridgeApiRaw, useBridgeCrud, useBridgeMutation, useBridgeQuery, useNetworkStatus, useRequireAuth, useSearchQueryBuilder,
|
|
10020
|
+
export { AccountCreationForm, AdvancedFilter, BridgeForm, BridgeList, BridgeTable, BridgeView, BrowserStorageAdapter, LoginForm, OfflineIndicator, PasswordResetForm, PubflowContext, PubflowProvider, ThemeProvider, createStyles, generateCSSVariables, useAuth, useAuthGuard, useBridgeApi, useBridgeApiRaw, useBridgeCrud, useBridgeMutation, useBridgeQuery, useNetworkStatus, useRequireAuth, useSearchQueryBuilder, useSimpleAuthGuard, useTheme };
|
|
9945
10021
|
//# sourceMappingURL=index.esm.js.map
|