@rebasepro/auth 0.4.0 → 0.6.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 +76 -0
- package/dist/index.d.ts +0 -2
- package/dist/index.es.js +765 -1009
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +822 -1061
- package/dist/index.umd.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +13 -13
- package/src/hooks/useRebaseAuthController.ts +5 -3
- package/src/index.ts +0 -3
- package/src/types.ts +1 -1
- package/dist/hooks/useBackendUserManagement.d.ts +0 -70
- package/src/hooks/useBackendUserManagement.ts +0 -504
package/dist/index.umd.js
CHANGED
|
@@ -1,1062 +1,823 @@
|
|
|
1
1
|
(function(global, factory) {
|
|
2
|
-
|
|
3
|
-
})(this,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
if (signal?.aborted) {
|
|
825
|
-
const error = new Error("Request aborted");
|
|
826
|
-
error.name = "AbortError";
|
|
827
|
-
throw error;
|
|
828
|
-
}
|
|
829
|
-
try {
|
|
830
|
-
const token = getAuthToken ? await getAuthToken() : client?.resolveToken ? await client.resolveToken() : null;
|
|
831
|
-
const baseUrl = apiUrl || (client?.baseUrl ? client.baseUrl : "");
|
|
832
|
-
const response = await fetch(`${baseUrl}/api/admin${endpoint}`, {
|
|
833
|
-
method,
|
|
834
|
-
headers: {
|
|
835
|
-
"Content-Type": "application/json",
|
|
836
|
-
...token ? { "Authorization": `Bearer ${token}` } : {}
|
|
837
|
-
},
|
|
838
|
-
body: body ? JSON.stringify(body) : void 0,
|
|
839
|
-
signal
|
|
840
|
-
});
|
|
841
|
-
if (!response.ok) {
|
|
842
|
-
const errorText = await response.text();
|
|
843
|
-
let errorMessage = "API request failed";
|
|
844
|
-
try {
|
|
845
|
-
const errorJson = JSON.parse(errorText);
|
|
846
|
-
errorMessage = errorJson.error?.message || errorMessage;
|
|
847
|
-
} catch (e) {
|
|
848
|
-
errorMessage = errorText || `HTTP error ${response.status}`;
|
|
849
|
-
}
|
|
850
|
-
const error = Object.assign(new Error(errorMessage), { status: response.status });
|
|
851
|
-
throw error;
|
|
852
|
-
}
|
|
853
|
-
return await response.json();
|
|
854
|
-
} catch (error) {
|
|
855
|
-
if (error instanceof Error && error.name === "AbortError" || signal?.aborted) {
|
|
856
|
-
throw error;
|
|
857
|
-
}
|
|
858
|
-
lastError = error instanceof Error ? error : new Error(String(error));
|
|
859
|
-
const isNetworkError = error instanceof TypeError;
|
|
860
|
-
const isServerError = typeof error.status === "number" && error.status >= 500 && error.status < 600;
|
|
861
|
-
if (attempt < retryCount - 1 && (isNetworkError || isServerError)) {
|
|
862
|
-
const delay = Math.min(1e3 * Math.pow(2, attempt), 5e3);
|
|
863
|
-
console.warn(`Admin API request to ${endpoint} failed, retrying in ${delay}ms...`);
|
|
864
|
-
await new Promise((resolve, reject) => {
|
|
865
|
-
if (signal?.aborted) return reject(new Error("AbortError"));
|
|
866
|
-
const timer = setTimeout(resolve, delay);
|
|
867
|
-
if (signal) {
|
|
868
|
-
signal.addEventListener("abort", () => {
|
|
869
|
-
clearTimeout(timer);
|
|
870
|
-
reject(new Error("AbortError"));
|
|
871
|
-
}, { once: true });
|
|
872
|
-
}
|
|
873
|
-
}).catch(() => {
|
|
874
|
-
});
|
|
875
|
-
if (signal?.aborted) {
|
|
876
|
-
const abortError = new Error("Request aborted");
|
|
877
|
-
abortError.name = "AbortError";
|
|
878
|
-
throw abortError;
|
|
879
|
-
}
|
|
880
|
-
continue;
|
|
881
|
-
}
|
|
882
|
-
console.error("Admin API error after retries:", error);
|
|
883
|
-
throw error;
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
throw lastError;
|
|
887
|
-
}, [apiUrl, getAuthToken]);
|
|
888
|
-
apiRequestRef.current = apiRequest;
|
|
889
|
-
const checkAdminExists = react.useCallback(async (signal) => {
|
|
890
|
-
try {
|
|
891
|
-
const data = await apiRequest("/users?role=admin&limit=1", "GET", void 0, 6, signal);
|
|
892
|
-
const adminUsers = data.users.map((u) => convertUser(u));
|
|
893
|
-
setHasAdminUsers(adminUsers.length > 0);
|
|
894
|
-
if (adminUsers.length > 0) {
|
|
895
|
-
mergeIntoCache(adminUsers);
|
|
896
|
-
}
|
|
897
|
-
setUsersError(void 0);
|
|
898
|
-
} catch (error) {
|
|
899
|
-
if (error instanceof Error && error.name === "AbortError") return;
|
|
900
|
-
console.error("Failed to check admin users:", error);
|
|
901
|
-
setUsersError(error instanceof Error ? error : new Error(String(error)));
|
|
902
|
-
}
|
|
903
|
-
}, [apiRequest, mergeIntoCache]);
|
|
904
|
-
react.useEffect(() => {
|
|
905
|
-
if (!currentUser) {
|
|
906
|
-
setLoading(false);
|
|
907
|
-
return;
|
|
908
|
-
}
|
|
909
|
-
const userRoles2 = currentUser.roles ?? [];
|
|
910
|
-
const isUserAdmin2 = userRoles2.some((r) => r === "admin" || r === "schema-admin");
|
|
911
|
-
if (!isUserAdmin2) {
|
|
912
|
-
setLoading(false);
|
|
913
|
-
return;
|
|
914
|
-
}
|
|
915
|
-
if (lastLoadedUidRef.current === currentUser.uid) {
|
|
916
|
-
setLoading(false);
|
|
917
|
-
return;
|
|
918
|
-
}
|
|
919
|
-
const abortController = new AbortController();
|
|
920
|
-
const load = async () => {
|
|
921
|
-
setLoading(true);
|
|
922
|
-
const request = apiRequestRef.current;
|
|
923
|
-
if (!abortController.signal.aborted) {
|
|
924
|
-
try {
|
|
925
|
-
const data = await request("/users?role=admin&limit=1", "GET", void 0, 6, abortController.signal);
|
|
926
|
-
const adminUsers = data.users.map((u) => convertUser(u));
|
|
927
|
-
setHasAdminUsers(adminUsers.length > 0);
|
|
928
|
-
if (adminUsers.length > 0) {
|
|
929
|
-
mergeIntoCache(adminUsers);
|
|
930
|
-
}
|
|
931
|
-
setUsersError(void 0);
|
|
932
|
-
} catch (error) {
|
|
933
|
-
if (error instanceof Error && error.name === "AbortError") return;
|
|
934
|
-
console.error("Failed to check admin users:", error);
|
|
935
|
-
setUsersError(error instanceof Error ? error : new Error(String(error)));
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
if (!abortController.signal.aborted) {
|
|
939
|
-
lastLoadedUidRef.current = currentUser.uid;
|
|
940
|
-
setLoading(false);
|
|
941
|
-
}
|
|
942
|
-
};
|
|
943
|
-
load();
|
|
944
|
-
return () => {
|
|
945
|
-
abortController.abort();
|
|
946
|
-
};
|
|
947
|
-
}, [currentUser?.uid]);
|
|
948
|
-
const searchUsers = react.useCallback(async (options) => {
|
|
949
|
-
const params = new URLSearchParams();
|
|
950
|
-
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
951
|
-
if (options.offset !== void 0) params.set("offset", String(options.offset));
|
|
952
|
-
if (options.search) params.set("search", options.search);
|
|
953
|
-
if (options.orderBy) params.set("orderBy", options.orderBy);
|
|
954
|
-
if (options.orderDir) params.set("orderDir", options.orderDir);
|
|
955
|
-
if (options.roleId) params.set("role", options.roleId);
|
|
956
|
-
const qs = params.toString();
|
|
957
|
-
const data = await apiRequest("/users" + (qs ? "?" + qs : ""), "GET");
|
|
958
|
-
const converted = data.users.map((u) => convertUser(u));
|
|
959
|
-
mergeIntoCache(converted);
|
|
960
|
-
return {
|
|
961
|
-
users: converted,
|
|
962
|
-
total: data.total
|
|
963
|
-
};
|
|
964
|
-
}, [apiRequest, mergeIntoCache]);
|
|
965
|
-
const saveUser = react.useCallback(async (user) => {
|
|
966
|
-
const roleIds = user.roles ?? [];
|
|
967
|
-
const data = await apiRequest(`/users/${user.uid}`, "PUT", {
|
|
968
|
-
email: user.email,
|
|
969
|
-
displayName: user.displayName,
|
|
970
|
-
roles: roleIds
|
|
971
|
-
});
|
|
972
|
-
const updated = convertUser(data.user);
|
|
973
|
-
mergeIntoCache([updated]);
|
|
974
|
-
return updated;
|
|
975
|
-
}, [apiRequest, mergeIntoCache]);
|
|
976
|
-
const createUser = react.useCallback(async (user) => {
|
|
977
|
-
const roleIds = user.roles ?? [];
|
|
978
|
-
const data = await apiRequest("/users", "POST", {
|
|
979
|
-
email: user.email,
|
|
980
|
-
displayName: user.displayName,
|
|
981
|
-
roles: roleIds
|
|
982
|
-
});
|
|
983
|
-
const created = convertUser(data.user);
|
|
984
|
-
mergeIntoCache([created]);
|
|
985
|
-
return {
|
|
986
|
-
user: created,
|
|
987
|
-
invitationSent: data.invitationSent ?? false,
|
|
988
|
-
temporaryPassword: data.temporaryPassword
|
|
989
|
-
};
|
|
990
|
-
}, [apiRequest, mergeIntoCache]);
|
|
991
|
-
const resetPassword2 = react.useCallback(async (user) => {
|
|
992
|
-
const data = await apiRequest(`/users/${user.uid}/reset-password`, "POST");
|
|
993
|
-
const updatedUser = convertUser(data.user);
|
|
994
|
-
mergeIntoCache([updatedUser]);
|
|
995
|
-
return {
|
|
996
|
-
user: updatedUser,
|
|
997
|
-
invitationSent: data.invitationSent ?? false,
|
|
998
|
-
temporaryPassword: data.temporaryPassword
|
|
999
|
-
};
|
|
1000
|
-
}, [apiRequest, mergeIntoCache]);
|
|
1001
|
-
const deleteUser = react.useCallback(async (user) => {
|
|
1002
|
-
await apiRequest(`/users/${user.uid}`, "DELETE");
|
|
1003
|
-
setUserCache((prev) => {
|
|
1004
|
-
const next = new Map(prev);
|
|
1005
|
-
next.delete(user.uid);
|
|
1006
|
-
return next;
|
|
1007
|
-
});
|
|
1008
|
-
}, [apiRequest]);
|
|
1009
|
-
const getUser = react.useCallback((uid) => {
|
|
1010
|
-
return userCache.get(uid) ?? null;
|
|
1011
|
-
}, [userCache]);
|
|
1012
|
-
const defineRolesFor = react.useCallback(async (user) => {
|
|
1013
|
-
let existingUser = userCache.get(user.uid) ?? Array.from(userCache.values()).find((u) => u.email === user.email);
|
|
1014
|
-
if (!existingUser) {
|
|
1015
|
-
try {
|
|
1016
|
-
const data = await apiRequest(`/users/${user.uid}`, "GET");
|
|
1017
|
-
existingUser = convertUser(data.user);
|
|
1018
|
-
mergeIntoCache([existingUser]);
|
|
1019
|
-
} catch {
|
|
1020
|
-
return void 0;
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
const userRoleIds = existingUser.roles ?? [];
|
|
1024
|
-
return userRoleIds;
|
|
1025
|
-
}, [userCache, apiRequest, mergeIntoCache]);
|
|
1026
|
-
const isAdmin = currentUser?.roles?.includes("admin") ?? false;
|
|
1027
|
-
const bootstrapAdmin = react.useCallback(async () => {
|
|
1028
|
-
try {
|
|
1029
|
-
await apiRequest("/bootstrap", "POST");
|
|
1030
|
-
await checkAdminExists();
|
|
1031
|
-
} catch (error) {
|
|
1032
|
-
console.error("Failed to bootstrap admin:", error);
|
|
1033
|
-
throw error;
|
|
1034
|
-
}
|
|
1035
|
-
}, [apiRequest, checkAdminExists]);
|
|
1036
|
-
const users = Array.from(userCache.values());
|
|
1037
|
-
return {
|
|
1038
|
-
loading: effectiveLoading,
|
|
1039
|
-
users,
|
|
1040
|
-
hasAdminUsers,
|
|
1041
|
-
saveUser,
|
|
1042
|
-
createUser,
|
|
1043
|
-
resetPassword: resetPassword2,
|
|
1044
|
-
deleteUser,
|
|
1045
|
-
isAdmin,
|
|
1046
|
-
allowDefaultRolesCreation: isAdmin,
|
|
1047
|
-
defineRolesFor,
|
|
1048
|
-
getUser,
|
|
1049
|
-
searchUsers,
|
|
1050
|
-
usersError,
|
|
1051
|
-
bootstrapAdmin
|
|
1052
|
-
};
|
|
1053
|
-
}
|
|
1054
|
-
exports2.AuthApiError = AuthApiError;
|
|
1055
|
-
exports2.fetchAuthConfig = fetchAuthConfig;
|
|
1056
|
-
exports2.getApiUrl = getApiUrl;
|
|
1057
|
-
exports2.setApiUrl = setApiUrl;
|
|
1058
|
-
exports2.useBackendUserManagement = useBackendUserManagement;
|
|
1059
|
-
exports2.useRebaseAuthController = useRebaseAuthController;
|
|
1060
|
-
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
|
|
1061
|
-
}));
|
|
1062
|
-
//# sourceMappingURL=index.umd.js.map
|
|
2
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("react")) : typeof define === "function" && define.amd ? define(["exports", "react"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["Rebase Auth"] = {}, global.react));
|
|
3
|
+
})(this, function(exports, react) {
|
|
4
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
5
|
+
//#region src/api.ts
|
|
6
|
+
/**
|
|
7
|
+
* Default API URL - can be overridden in hook props
|
|
8
|
+
*/
|
|
9
|
+
var baseApiUrl = "";
|
|
10
|
+
/**
|
|
11
|
+
* Configure the API base URL
|
|
12
|
+
*/
|
|
13
|
+
function setApiUrl(url) {
|
|
14
|
+
baseApiUrl = url;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Get the current API URL
|
|
18
|
+
*/
|
|
19
|
+
function getApiUrl() {
|
|
20
|
+
return baseApiUrl;
|
|
21
|
+
}
|
|
22
|
+
var AuthApiError = class extends Error {
|
|
23
|
+
code;
|
|
24
|
+
constructor(message, code) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.code = code;
|
|
27
|
+
this.name = "AuthApiError";
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
async function handleResponse(response) {
|
|
31
|
+
let data;
|
|
32
|
+
try {
|
|
33
|
+
data = await response.json();
|
|
34
|
+
} catch (parseError) {
|
|
35
|
+
throw new AuthApiError(`Server returned non-JSON response (status: ${response.status})`, "PARSE_ERROR");
|
|
36
|
+
}
|
|
37
|
+
if (!response.ok) throw new AuthApiError(data.error?.message || "Request failed", data.error?.code || "UNKNOWN_ERROR");
|
|
38
|
+
return data;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Wrapper for fetch that catches generic network failures (like server down)
|
|
42
|
+
* and translates them to an AuthApiError.
|
|
43
|
+
*/
|
|
44
|
+
async function fetchWithHandling(input, init) {
|
|
45
|
+
try {
|
|
46
|
+
return await fetch(input, init);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (error instanceof TypeError && error.message.includes("Failed to fetch")) throw new AuthApiError("Failed to connect to the backend server. The backend might be down or failed to initialize (e.g., database connection timeout).", "NETWORK_ERROR");
|
|
49
|
+
throw new AuthApiError("Network error: " + (error instanceof Error ? error.message : String(error)), "NETWORK_ERROR");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Register a new user with email/password
|
|
54
|
+
*/
|
|
55
|
+
async function register(email, password, displayName) {
|
|
56
|
+
return handleResponse(await fetchWithHandling(`${baseApiUrl}/api/auth/register`, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: { "Content-Type": "application/json" },
|
|
59
|
+
body: JSON.stringify({
|
|
60
|
+
email,
|
|
61
|
+
password,
|
|
62
|
+
displayName
|
|
63
|
+
})
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Login with email/password
|
|
68
|
+
*/
|
|
69
|
+
async function login(email, password) {
|
|
70
|
+
return handleResponse(await fetchWithHandling(`${baseApiUrl}/api/auth/login`, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
headers: { "Content-Type": "application/json" },
|
|
73
|
+
body: JSON.stringify({
|
|
74
|
+
email,
|
|
75
|
+
password
|
|
76
|
+
})
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Login with Google.
|
|
81
|
+
*
|
|
82
|
+
* Accepts one of:
|
|
83
|
+
* - `{ idToken }` — ID-token flow (One Tap / Sign In button)
|
|
84
|
+
* - `{ accessToken }` — Access-token flow (popup)
|
|
85
|
+
* - `{ code, redirectUri }` — Authorization code flow (most secure)
|
|
86
|
+
*/
|
|
87
|
+
async function googleLogin(payload) {
|
|
88
|
+
return handleResponse(await fetchWithHandling(`${baseApiUrl}/api/auth/google`, {
|
|
89
|
+
method: "POST",
|
|
90
|
+
headers: { "Content-Type": "application/json" },
|
|
91
|
+
body: JSON.stringify(payload)
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Generic OAuth login — works with any provider registered on the backend.
|
|
96
|
+
* The `providerId` is used to build the endpoint: `/api/auth/{providerId}`.
|
|
97
|
+
*/
|
|
98
|
+
async function oauthLogin(providerId, payload) {
|
|
99
|
+
return handleResponse(await fetchWithHandling(`${baseApiUrl}/api/auth/${providerId}`, {
|
|
100
|
+
method: "POST",
|
|
101
|
+
headers: { "Content-Type": "application/json" },
|
|
102
|
+
body: JSON.stringify(payload)
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Refresh access token using refresh token
|
|
107
|
+
*/
|
|
108
|
+
async function refreshAccessToken(refreshToken) {
|
|
109
|
+
return handleResponse(await fetchWithHandling(`${baseApiUrl}/api/auth/refresh`, {
|
|
110
|
+
method: "POST",
|
|
111
|
+
headers: { "Content-Type": "application/json" },
|
|
112
|
+
body: JSON.stringify({ refreshToken })
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Logout and invalidate refresh token
|
|
117
|
+
*/
|
|
118
|
+
async function logout(refreshToken) {
|
|
119
|
+
await fetchWithHandling(`${baseApiUrl}/api/auth/logout`, {
|
|
120
|
+
method: "POST",
|
|
121
|
+
headers: { "Content-Type": "application/json" },
|
|
122
|
+
body: JSON.stringify({ refreshToken })
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get current user info
|
|
127
|
+
*/
|
|
128
|
+
async function getCurrentUser(accessToken) {
|
|
129
|
+
return handleResponse(await fetchWithHandling(`${baseApiUrl}/api/auth/me`, {
|
|
130
|
+
method: "GET",
|
|
131
|
+
headers: {
|
|
132
|
+
"Content-Type": "application/json",
|
|
133
|
+
"Authorization": `Bearer ${accessToken}`
|
|
134
|
+
}
|
|
135
|
+
}));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Request password reset email
|
|
139
|
+
*/
|
|
140
|
+
async function forgotPassword(email) {
|
|
141
|
+
return handleResponse(await fetchWithHandling(`${baseApiUrl}/api/auth/forgot-password`, {
|
|
142
|
+
method: "POST",
|
|
143
|
+
headers: { "Content-Type": "application/json" },
|
|
144
|
+
body: JSON.stringify({ email })
|
|
145
|
+
}));
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Reset password using token from email
|
|
149
|
+
*/
|
|
150
|
+
async function resetPassword(token, password) {
|
|
151
|
+
return handleResponse(await fetchWithHandling(`${baseApiUrl}/api/auth/reset-password`, {
|
|
152
|
+
method: "POST",
|
|
153
|
+
headers: { "Content-Type": "application/json" },
|
|
154
|
+
body: JSON.stringify({
|
|
155
|
+
token,
|
|
156
|
+
password
|
|
157
|
+
})
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Change password for authenticated user
|
|
162
|
+
*/
|
|
163
|
+
async function changePassword(accessToken, oldPassword, newPassword) {
|
|
164
|
+
return handleResponse(await fetchWithHandling(`${baseApiUrl}/api/auth/change-password`, {
|
|
165
|
+
method: "POST",
|
|
166
|
+
headers: {
|
|
167
|
+
"Content-Type": "application/json",
|
|
168
|
+
"Authorization": `Bearer ${accessToken}`
|
|
169
|
+
},
|
|
170
|
+
body: JSON.stringify({
|
|
171
|
+
oldPassword,
|
|
172
|
+
newPassword
|
|
173
|
+
})
|
|
174
|
+
}));
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Update current user profile
|
|
178
|
+
*/
|
|
179
|
+
async function updateProfile(accessToken, displayName, photoURL) {
|
|
180
|
+
return handleResponse(await fetchWithHandling(`${baseApiUrl}/api/auth/me`, {
|
|
181
|
+
method: "PATCH",
|
|
182
|
+
headers: {
|
|
183
|
+
"Content-Type": "application/json",
|
|
184
|
+
"Authorization": `Bearer ${accessToken}`
|
|
185
|
+
},
|
|
186
|
+
body: JSON.stringify({
|
|
187
|
+
displayName,
|
|
188
|
+
photoURL
|
|
189
|
+
})
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Fetch active sessions for current user
|
|
194
|
+
*/
|
|
195
|
+
async function fetchSessions(accessToken, currentRefreshToken) {
|
|
196
|
+
const headers = {
|
|
197
|
+
"Content-Type": "application/json",
|
|
198
|
+
"Authorization": `Bearer ${accessToken}`
|
|
199
|
+
};
|
|
200
|
+
if (currentRefreshToken) headers["X-Refresh-Token"] = currentRefreshToken;
|
|
201
|
+
return handleResponse(await fetchWithHandling(`${baseApiUrl}/api/auth/sessions`, {
|
|
202
|
+
method: "GET",
|
|
203
|
+
headers
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Revoke a specific session
|
|
208
|
+
*/
|
|
209
|
+
async function revokeSession(accessToken, sessionId) {
|
|
210
|
+
return handleResponse(await fetchWithHandling(`${baseApiUrl}/api/auth/sessions/${sessionId}`, {
|
|
211
|
+
method: "DELETE",
|
|
212
|
+
headers: {
|
|
213
|
+
"Content-Type": "application/json",
|
|
214
|
+
"Authorization": `Bearer ${accessToken}`
|
|
215
|
+
}
|
|
216
|
+
}));
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Revoke all sessions for current user
|
|
220
|
+
*/
|
|
221
|
+
async function revokeAllSessions(accessToken) {
|
|
222
|
+
return handleResponse(await fetchWithHandling(`${baseApiUrl}/api/auth/sessions`, {
|
|
223
|
+
method: "DELETE",
|
|
224
|
+
headers: {
|
|
225
|
+
"Content-Type": "application/json",
|
|
226
|
+
"Authorization": `Bearer ${accessToken}`
|
|
227
|
+
}
|
|
228
|
+
}));
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Inflight promise for `fetchAuthConfig` — ensures concurrent callers
|
|
232
|
+
* (e.g. React StrictMode double-mount) reuse the same network request.
|
|
233
|
+
*/
|
|
234
|
+
var authConfigInflight = null;
|
|
235
|
+
/**
|
|
236
|
+
* Cached result of the last successful `fetchAuthConfig` call.
|
|
237
|
+
* Auth config is static for the lifetime of the app session, so
|
|
238
|
+
* repeat calls (e.g. from effect re-runs) return instantly.
|
|
239
|
+
*/
|
|
240
|
+
var authConfigCached = null;
|
|
241
|
+
/**
|
|
242
|
+
* Fetch auth configuration / status from the backend
|
|
243
|
+
* This is an unauthenticated endpoint used to detect bootstrap mode.
|
|
244
|
+
*
|
|
245
|
+
* Results are cached for the session lifetime.
|
|
246
|
+
* Concurrent calls are deduplicated: only one network request is made
|
|
247
|
+
* and all callers share the same promise.
|
|
248
|
+
*/
|
|
249
|
+
async function fetchAuthConfig() {
|
|
250
|
+
if (authConfigCached) return authConfigCached;
|
|
251
|
+
if (authConfigInflight) return authConfigInflight;
|
|
252
|
+
authConfigInflight = (async () => {
|
|
253
|
+
return handleResponse(await fetchWithHandling(`${baseApiUrl}/api/auth/config`, {
|
|
254
|
+
method: "GET",
|
|
255
|
+
headers: { "Content-Type": "application/json" }
|
|
256
|
+
}));
|
|
257
|
+
})();
|
|
258
|
+
try {
|
|
259
|
+
const result = await authConfigInflight;
|
|
260
|
+
authConfigCached = result;
|
|
261
|
+
return result;
|
|
262
|
+
} finally {
|
|
263
|
+
authConfigInflight = null;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
//#endregion
|
|
267
|
+
//#region src/hooks/useRebaseAuthController.ts
|
|
268
|
+
var STORAGE_KEY = "rebase_react_auth";
|
|
269
|
+
var TOKEN_REFRESH_BUFFER_MS = 120 * 1e3;
|
|
270
|
+
/**
|
|
271
|
+
* Convert UserInfo from API to Rebase User type
|
|
272
|
+
*/
|
|
273
|
+
function convertToUser(userInfo) {
|
|
274
|
+
return {
|
|
275
|
+
uid: userInfo.uid,
|
|
276
|
+
email: userInfo.email,
|
|
277
|
+
displayName: userInfo.displayName || null,
|
|
278
|
+
photoURL: userInfo.photoURL || null,
|
|
279
|
+
providerId: "custom",
|
|
280
|
+
isAnonymous: false,
|
|
281
|
+
roles: userInfo.roles || [],
|
|
282
|
+
metadata: userInfo.metadata
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Save auth data to localStorage
|
|
287
|
+
*/
|
|
288
|
+
function saveAuthToStorage(tokens, user) {
|
|
289
|
+
try {
|
|
290
|
+
const data = {
|
|
291
|
+
tokens,
|
|
292
|
+
user
|
|
293
|
+
};
|
|
294
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
|
|
295
|
+
} catch (e) {}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Load auth data from localStorage
|
|
299
|
+
*/
|
|
300
|
+
function loadAuthFromStorage() {
|
|
301
|
+
try {
|
|
302
|
+
const data = localStorage.getItem(STORAGE_KEY);
|
|
303
|
+
if (data) return JSON.parse(data);
|
|
304
|
+
} catch (e) {
|
|
305
|
+
console.warn("Failed to load auth from storage:", e);
|
|
306
|
+
}
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Clear auth data from localStorage
|
|
311
|
+
*/
|
|
312
|
+
function clearAuthFromStorage() {
|
|
313
|
+
try {
|
|
314
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
315
|
+
} catch (e) {
|
|
316
|
+
console.warn("Failed to clear auth from storage:", e);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Check if token is expired or about to expire
|
|
321
|
+
*/
|
|
322
|
+
function isTokenExpiredOrNearExpiry(expiresAt, bufferMs = TOKEN_REFRESH_BUFFER_MS) {
|
|
323
|
+
return Date.now() + bufferMs >= expiresAt;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Auth controller hook for JWT-based authentication
|
|
327
|
+
* with @rebasepro/server-core
|
|
328
|
+
*
|
|
329
|
+
* @param props Configuration options
|
|
330
|
+
* @returns RebaseAuthController instance
|
|
331
|
+
*/
|
|
332
|
+
function useRebaseAuthController(props = {}) {
|
|
333
|
+
const { client, apiUrl, onSignOut, defineRolesFor } = props;
|
|
334
|
+
const [user, setUser] = (0, react.useState)(null);
|
|
335
|
+
const [authLoading, setAuthLoading] = (0, react.useState)(false);
|
|
336
|
+
const [initialLoading, setInitialLoading] = (0, react.useState)(true);
|
|
337
|
+
const [authError, setAuthError] = (0, react.useState)(null);
|
|
338
|
+
const [authProviderError, setAuthProviderError] = (0, react.useState)(null);
|
|
339
|
+
const [loginSkipped, setLoginSkipped] = (0, react.useState)(false);
|
|
340
|
+
const [extra, setExtra] = (0, react.useState)(null);
|
|
341
|
+
const [authConfig, setAuthConfig] = (0, react.useState)(null);
|
|
342
|
+
const tokensRef = (0, react.useRef)(null);
|
|
343
|
+
const refreshTimeoutRef = (0, react.useRef)(null);
|
|
344
|
+
const refreshPromiseRef = (0, react.useRef)(null);
|
|
345
|
+
const isMountedRef = (0, react.useRef)(true);
|
|
346
|
+
(0, react.useEffect)(() => {
|
|
347
|
+
const url = client?.baseUrl || apiUrl;
|
|
348
|
+
if (url) setApiUrl(url);
|
|
349
|
+
}, [
|
|
350
|
+
client,
|
|
351
|
+
client?.baseUrl,
|
|
352
|
+
apiUrl
|
|
353
|
+
]);
|
|
354
|
+
const clearError = (0, react.useCallback)(() => {
|
|
355
|
+
setAuthProviderError(null);
|
|
356
|
+
}, []);
|
|
357
|
+
const clearSessionAndSignOut = (0, react.useCallback)(() => {
|
|
358
|
+
tokensRef.current = null;
|
|
359
|
+
clearAuthFromStorage();
|
|
360
|
+
if (refreshTimeoutRef.current) {
|
|
361
|
+
clearTimeout(refreshTimeoutRef.current);
|
|
362
|
+
refreshTimeoutRef.current = null;
|
|
363
|
+
}
|
|
364
|
+
setUser(null);
|
|
365
|
+
setLoginSkipped(false);
|
|
366
|
+
onSignOut?.();
|
|
367
|
+
}, [onSignOut]);
|
|
368
|
+
/**
|
|
369
|
+
* Refresh the access token using the stored refresh token.
|
|
370
|
+
* Returns the new tokens or null if refresh failed.
|
|
371
|
+
*/
|
|
372
|
+
const refreshAccessToken$1 = (0, react.useCallback)(async () => {
|
|
373
|
+
if (refreshPromiseRef.current) return refreshPromiseRef.current;
|
|
374
|
+
const executeRefresh = async () => {
|
|
375
|
+
const storedData = loadAuthFromStorage();
|
|
376
|
+
if (storedData?.tokens?.accessTokenExpiresAt) {
|
|
377
|
+
const storedTokens = storedData.tokens;
|
|
378
|
+
if (!isTokenExpiredOrNearExpiry(storedTokens.accessTokenExpiresAt) && storedTokens.accessToken !== tokensRef.current?.accessToken) {
|
|
379
|
+
tokensRef.current = storedTokens;
|
|
380
|
+
return storedTokens;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
const currentTokens = tokensRef.current;
|
|
384
|
+
if (!currentTokens?.refreshToken) return null;
|
|
385
|
+
try {
|
|
386
|
+
const newTokens = (await refreshAccessToken(currentTokens.refreshToken)).tokens;
|
|
387
|
+
tokensRef.current = newTokens;
|
|
388
|
+
const latestStoredData = loadAuthFromStorage();
|
|
389
|
+
if (latestStoredData) saveAuthToStorage(newTokens, latestStoredData.user);
|
|
390
|
+
return newTokens;
|
|
391
|
+
} catch (error) {
|
|
392
|
+
if (error instanceof Error && error.code === "NETWORK_ERROR") throw error;
|
|
393
|
+
return null;
|
|
394
|
+
} finally {
|
|
395
|
+
refreshPromiseRef.current = null;
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
refreshPromiseRef.current = executeRefresh();
|
|
399
|
+
return refreshPromiseRef.current;
|
|
400
|
+
}, []);
|
|
401
|
+
const scheduleTokenRefresh = (0, react.useCallback)((tokens) => {
|
|
402
|
+
if (refreshTimeoutRef.current) clearTimeout(refreshTimeoutRef.current);
|
|
403
|
+
const timeUntilRefresh = tokens.accessTokenExpiresAt - TOKEN_REFRESH_BUFFER_MS - Date.now();
|
|
404
|
+
if (timeUntilRefresh <= 0) {
|
|
405
|
+
refreshAccessToken$1().then((newTokens) => {
|
|
406
|
+
if (newTokens && isMountedRef.current) scheduleTokenRefresh(newTokens);
|
|
407
|
+
else if (!newTokens && isMountedRef.current) clearSessionAndSignOut();
|
|
408
|
+
});
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
refreshTimeoutRef.current = setTimeout(async () => {
|
|
412
|
+
if (!isMountedRef.current) return;
|
|
413
|
+
try {
|
|
414
|
+
const newTokens = await refreshAccessToken$1();
|
|
415
|
+
if (newTokens && isMountedRef.current) scheduleTokenRefresh(newTokens);
|
|
416
|
+
else if (!newTokens && isMountedRef.current) clearSessionAndSignOut();
|
|
417
|
+
} catch (error) {
|
|
418
|
+
if (isMountedRef.current) refreshTimeoutRef.current = setTimeout(() => {
|
|
419
|
+
scheduleTokenRefresh(tokens);
|
|
420
|
+
}, 1e4);
|
|
421
|
+
}
|
|
422
|
+
}, timeUntilRefresh);
|
|
423
|
+
}, [refreshAccessToken$1, clearSessionAndSignOut]);
|
|
424
|
+
const getAuthToken = (0, react.useCallback)(async () => {
|
|
425
|
+
if (initialLoading) throw new Error("Auth is still loading");
|
|
426
|
+
const currentTokens = tokensRef.current;
|
|
427
|
+
if (!currentTokens) throw new Error("User is not logged in");
|
|
428
|
+
if (isTokenExpiredOrNearExpiry(currentTokens.accessTokenExpiresAt)) try {
|
|
429
|
+
const newTokens = await refreshAccessToken$1();
|
|
430
|
+
if (!newTokens) {
|
|
431
|
+
clearSessionAndSignOut();
|
|
432
|
+
throw new Error("Session expired. Please login again.");
|
|
433
|
+
}
|
|
434
|
+
return newTokens.accessToken;
|
|
435
|
+
} catch (error) {
|
|
436
|
+
if (error instanceof Error && error.code === "NETWORK_ERROR") throw error;
|
|
437
|
+
clearSessionAndSignOut();
|
|
438
|
+
throw error;
|
|
439
|
+
}
|
|
440
|
+
return currentTokens.accessToken;
|
|
441
|
+
}, [
|
|
442
|
+
initialLoading,
|
|
443
|
+
refreshAccessToken$1,
|
|
444
|
+
clearSessionAndSignOut
|
|
445
|
+
]);
|
|
446
|
+
(0, react.useEffect)(() => {
|
|
447
|
+
if (client) {
|
|
448
|
+
client.setAuthTokenGetter?.(async () => {
|
|
449
|
+
try {
|
|
450
|
+
return await getAuthToken();
|
|
451
|
+
} catch {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
if (client.setOnUnauthorized) client.setOnUnauthorized(async () => {
|
|
456
|
+
try {
|
|
457
|
+
if (await refreshAccessToken$1()) return true;
|
|
458
|
+
clearSessionAndSignOut();
|
|
459
|
+
return false;
|
|
460
|
+
} catch (e) {
|
|
461
|
+
clearSessionAndSignOut();
|
|
462
|
+
return false;
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
if (client.ws) client.ws.setAuthTokenGetter(async () => {
|
|
466
|
+
try {
|
|
467
|
+
return await getAuthToken();
|
|
468
|
+
} catch {
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
}, [
|
|
474
|
+
client,
|
|
475
|
+
getAuthToken,
|
|
476
|
+
refreshAccessToken$1,
|
|
477
|
+
clearSessionAndSignOut
|
|
478
|
+
]);
|
|
479
|
+
const handleAuthSuccess = (0, react.useCallback)(async (userInfo, tokens) => {
|
|
480
|
+
tokensRef.current = tokens;
|
|
481
|
+
let convertedUser = convertToUser(userInfo);
|
|
482
|
+
if (defineRolesFor) {
|
|
483
|
+
const customRoles = await defineRolesFor(convertedUser);
|
|
484
|
+
if (customRoles) convertedUser = {
|
|
485
|
+
...convertedUser,
|
|
486
|
+
roles: customRoles
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
saveAuthToStorage(tokens, userInfo);
|
|
490
|
+
setUser(convertedUser);
|
|
491
|
+
setAuthError(null);
|
|
492
|
+
setAuthProviderError(null);
|
|
493
|
+
setLoginSkipped(false);
|
|
494
|
+
scheduleTokenRefresh(tokens);
|
|
495
|
+
}, [scheduleTokenRefresh, defineRolesFor]);
|
|
496
|
+
const emailPasswordLogin = (0, react.useCallback)(async (email, password) => {
|
|
497
|
+
setAuthLoading(true);
|
|
498
|
+
setAuthProviderError(null);
|
|
499
|
+
try {
|
|
500
|
+
const response = await login(email, password);
|
|
501
|
+
await handleAuthSuccess(response.user, response.tokens);
|
|
502
|
+
} catch (error) {
|
|
503
|
+
setAuthProviderError(error);
|
|
504
|
+
throw error;
|
|
505
|
+
} finally {
|
|
506
|
+
setAuthLoading(false);
|
|
507
|
+
}
|
|
508
|
+
}, [handleAuthSuccess]);
|
|
509
|
+
const register$1 = (0, react.useCallback)(async (email, password, displayName) => {
|
|
510
|
+
setAuthLoading(true);
|
|
511
|
+
setAuthProviderError(null);
|
|
512
|
+
try {
|
|
513
|
+
const response = await register(email, password, displayName);
|
|
514
|
+
await handleAuthSuccess(response.user, response.tokens);
|
|
515
|
+
} catch (error) {
|
|
516
|
+
setAuthProviderError(error);
|
|
517
|
+
throw error;
|
|
518
|
+
} finally {
|
|
519
|
+
setAuthLoading(false);
|
|
520
|
+
}
|
|
521
|
+
}, [handleAuthSuccess]);
|
|
522
|
+
const googleLogin$1 = (0, react.useCallback)(async (payload) => {
|
|
523
|
+
setAuthLoading(true);
|
|
524
|
+
setAuthProviderError(null);
|
|
525
|
+
try {
|
|
526
|
+
const response = await googleLogin(payload);
|
|
527
|
+
await handleAuthSuccess(response.user, response.tokens);
|
|
528
|
+
} catch (error) {
|
|
529
|
+
setAuthProviderError(error);
|
|
530
|
+
throw error;
|
|
531
|
+
} finally {
|
|
532
|
+
setAuthLoading(false);
|
|
533
|
+
}
|
|
534
|
+
}, [handleAuthSuccess]);
|
|
535
|
+
const oauthLogin$1 = (0, react.useCallback)(async (providerId, payload) => {
|
|
536
|
+
setAuthLoading(true);
|
|
537
|
+
setAuthProviderError(null);
|
|
538
|
+
try {
|
|
539
|
+
const response = await oauthLogin(providerId, payload);
|
|
540
|
+
await handleAuthSuccess(response.user, response.tokens);
|
|
541
|
+
} catch (error) {
|
|
542
|
+
setAuthProviderError(error);
|
|
543
|
+
throw error;
|
|
544
|
+
} finally {
|
|
545
|
+
setAuthLoading(false);
|
|
546
|
+
}
|
|
547
|
+
}, [handleAuthSuccess]);
|
|
548
|
+
const signOut = (0, react.useCallback)(async () => {
|
|
549
|
+
try {
|
|
550
|
+
if (tokensRef.current) await logout(tokensRef.current.refreshToken);
|
|
551
|
+
} catch (error) {
|
|
552
|
+
console.error("Logout error:", error);
|
|
553
|
+
} finally {
|
|
554
|
+
clearSessionAndSignOut();
|
|
555
|
+
}
|
|
556
|
+
}, [clearSessionAndSignOut]);
|
|
557
|
+
const skipLogin = (0, react.useCallback)(() => {
|
|
558
|
+
setLoginSkipped(true);
|
|
559
|
+
setUser(null);
|
|
560
|
+
}, []);
|
|
561
|
+
const forgotPassword$1 = (0, react.useCallback)(async (email) => {
|
|
562
|
+
setAuthLoading(true);
|
|
563
|
+
setAuthProviderError(null);
|
|
564
|
+
try {
|
|
565
|
+
await forgotPassword(email);
|
|
566
|
+
} catch (error) {
|
|
567
|
+
setAuthProviderError(error);
|
|
568
|
+
throw error;
|
|
569
|
+
} finally {
|
|
570
|
+
setAuthLoading(false);
|
|
571
|
+
}
|
|
572
|
+
}, []);
|
|
573
|
+
const resetPassword$1 = (0, react.useCallback)(async (token, password) => {
|
|
574
|
+
setAuthLoading(true);
|
|
575
|
+
setAuthProviderError(null);
|
|
576
|
+
try {
|
|
577
|
+
await resetPassword(token, password);
|
|
578
|
+
} catch (error) {
|
|
579
|
+
setAuthProviderError(error);
|
|
580
|
+
throw error;
|
|
581
|
+
} finally {
|
|
582
|
+
setAuthLoading(false);
|
|
583
|
+
}
|
|
584
|
+
}, []);
|
|
585
|
+
const changePassword$1 = (0, react.useCallback)(async (oldPassword, newPassword) => {
|
|
586
|
+
setAuthLoading(true);
|
|
587
|
+
setAuthProviderError(null);
|
|
588
|
+
try {
|
|
589
|
+
if (!tokensRef.current) throw new Error("User is not logged in");
|
|
590
|
+
await changePassword(tokensRef.current.accessToken, oldPassword, newPassword);
|
|
591
|
+
clearSessionAndSignOut();
|
|
592
|
+
} catch (error) {
|
|
593
|
+
setAuthProviderError(error);
|
|
594
|
+
throw error;
|
|
595
|
+
} finally {
|
|
596
|
+
setAuthLoading(false);
|
|
597
|
+
}
|
|
598
|
+
}, [clearSessionAndSignOut]);
|
|
599
|
+
const updateProfile$1 = (0, react.useCallback)(async (displayName, photoURL) => {
|
|
600
|
+
setAuthLoading(true);
|
|
601
|
+
setAuthProviderError(null);
|
|
602
|
+
try {
|
|
603
|
+
if (!tokensRef.current) throw new Error("User is not logged in");
|
|
604
|
+
const response = await updateProfile(tokensRef.current.accessToken, displayName, photoURL);
|
|
605
|
+
let convertedUser = convertToUser(response.user);
|
|
606
|
+
if (defineRolesFor) {
|
|
607
|
+
const customRoles = await defineRolesFor(convertedUser);
|
|
608
|
+
if (customRoles) convertedUser = {
|
|
609
|
+
...convertedUser,
|
|
610
|
+
roles: customRoles
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
const storedData = loadAuthFromStorage();
|
|
614
|
+
if (storedData) saveAuthToStorage(storedData.tokens, response.user);
|
|
615
|
+
setUser(convertedUser);
|
|
616
|
+
return convertedUser;
|
|
617
|
+
} catch (error) {
|
|
618
|
+
setAuthProviderError(error);
|
|
619
|
+
throw error;
|
|
620
|
+
} finally {
|
|
621
|
+
setAuthLoading(false);
|
|
622
|
+
}
|
|
623
|
+
}, [defineRolesFor]);
|
|
624
|
+
const fetchSessions$1 = (0, react.useCallback)(async () => {
|
|
625
|
+
try {
|
|
626
|
+
if (!tokensRef.current) throw new Error("User is not logged in");
|
|
627
|
+
return (await fetchSessions(tokensRef.current.accessToken, tokensRef.current.refreshToken)).sessions;
|
|
628
|
+
} catch (error) {
|
|
629
|
+
setAuthProviderError(error);
|
|
630
|
+
throw error;
|
|
631
|
+
}
|
|
632
|
+
}, []);
|
|
633
|
+
const revokeSession$1 = (0, react.useCallback)(async (sessionId) => {
|
|
634
|
+
try {
|
|
635
|
+
if (!tokensRef.current) throw new Error("User is not logged in");
|
|
636
|
+
await revokeSession(tokensRef.current.accessToken, sessionId);
|
|
637
|
+
} catch (error) {
|
|
638
|
+
setAuthProviderError(error);
|
|
639
|
+
throw error;
|
|
640
|
+
}
|
|
641
|
+
}, []);
|
|
642
|
+
(0, react.useEffect)(() => {
|
|
643
|
+
isMountedRef.current = true;
|
|
644
|
+
const restoreAuth = async () => {
|
|
645
|
+
try {
|
|
646
|
+
const config = await fetchAuthConfig();
|
|
647
|
+
if (isMountedRef.current) setAuthConfig(config);
|
|
648
|
+
} catch (e) {}
|
|
649
|
+
const stored = loadAuthFromStorage();
|
|
650
|
+
if (!stored) {
|
|
651
|
+
setInitialLoading(false);
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
if (!stored.tokens?.refreshToken) {
|
|
655
|
+
clearAuthFromStorage();
|
|
656
|
+
setInitialLoading(false);
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
const expiresAt = stored.tokens.accessTokenExpiresAt;
|
|
660
|
+
if (typeof expiresAt !== "number" || !Number.isFinite(expiresAt)) {
|
|
661
|
+
clearAuthFromStorage();
|
|
662
|
+
setInitialLoading(false);
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
if (!isTokenExpiredOrNearExpiry(stored.tokens.accessTokenExpiresAt)) {
|
|
666
|
+
tokensRef.current = stored.tokens;
|
|
667
|
+
let userToSet = convertToUser(stored.user);
|
|
668
|
+
if (defineRolesFor) {
|
|
669
|
+
const customRoles = await defineRolesFor(userToSet);
|
|
670
|
+
if (customRoles) userToSet = {
|
|
671
|
+
...userToSet,
|
|
672
|
+
roles: customRoles
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
setUser(userToSet);
|
|
676
|
+
scheduleTokenRefresh(stored.tokens);
|
|
677
|
+
setInitialLoading(false);
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
tokensRef.current = stored.tokens;
|
|
681
|
+
try {
|
|
682
|
+
const newTokens = await refreshAccessToken$1();
|
|
683
|
+
if (!newTokens) {
|
|
684
|
+
clearAuthFromStorage();
|
|
685
|
+
tokensRef.current = null;
|
|
686
|
+
setInitialLoading(false);
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
if (!isMountedRef.current) return;
|
|
690
|
+
let userToSet;
|
|
691
|
+
try {
|
|
692
|
+
const meResponse = await getCurrentUser(newTokens.accessToken);
|
|
693
|
+
if (!isMountedRef.current) return;
|
|
694
|
+
const freshUserInfo = meResponse.user;
|
|
695
|
+
saveAuthToStorage(newTokens, freshUserInfo);
|
|
696
|
+
userToSet = convertToUser(freshUserInfo);
|
|
697
|
+
if (defineRolesFor) {
|
|
698
|
+
const customRoles = await defineRolesFor(userToSet);
|
|
699
|
+
if (!isMountedRef.current) return;
|
|
700
|
+
if (customRoles) userToSet = {
|
|
701
|
+
...userToSet,
|
|
702
|
+
roles: customRoles
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
} catch (meError) {
|
|
706
|
+
if (!isMountedRef.current) return;
|
|
707
|
+
if (meError instanceof AuthApiError && (meError.code === "NOT_FOUND" || meError.code === "UNAUTHORIZED")) {
|
|
708
|
+
clearSessionAndSignOut();
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
userToSet = convertToUser(stored.user);
|
|
712
|
+
}
|
|
713
|
+
if (!isMountedRef.current) return;
|
|
714
|
+
setUser(userToSet);
|
|
715
|
+
scheduleTokenRefresh(newTokens);
|
|
716
|
+
} catch (error) {
|
|
717
|
+
if (!isMountedRef.current) return;
|
|
718
|
+
if (!(error instanceof Error && error.code === "NETWORK_ERROR")) {
|
|
719
|
+
clearAuthFromStorage();
|
|
720
|
+
tokensRef.current = null;
|
|
721
|
+
}
|
|
722
|
+
} finally {
|
|
723
|
+
if (isMountedRef.current) setInitialLoading(false);
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
restoreAuth();
|
|
727
|
+
return () => {
|
|
728
|
+
isMountedRef.current = false;
|
|
729
|
+
};
|
|
730
|
+
}, [
|
|
731
|
+
scheduleTokenRefresh,
|
|
732
|
+
defineRolesFor,
|
|
733
|
+
refreshAccessToken$1
|
|
734
|
+
]);
|
|
735
|
+
(0, react.useEffect)(() => {
|
|
736
|
+
const handleVisibilityChange = async () => {
|
|
737
|
+
if (initialLoading) return;
|
|
738
|
+
if (document.visibilityState === "visible" && tokensRef.current) {
|
|
739
|
+
if (isTokenExpiredOrNearExpiry(tokensRef.current.accessTokenExpiresAt)) try {
|
|
740
|
+
const newTokens = await refreshAccessToken$1();
|
|
741
|
+
if (newTokens && isMountedRef.current) scheduleTokenRefresh(newTokens);
|
|
742
|
+
else if (!newTokens && isMountedRef.current) clearSessionAndSignOut();
|
|
743
|
+
} catch (e) {}
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
747
|
+
return () => {
|
|
748
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
749
|
+
};
|
|
750
|
+
}, [
|
|
751
|
+
initialLoading,
|
|
752
|
+
refreshAccessToken$1,
|
|
753
|
+
scheduleTokenRefresh,
|
|
754
|
+
clearSessionAndSignOut
|
|
755
|
+
]);
|
|
756
|
+
const getApiUrl$1 = (0, react.useCallback)(() => {
|
|
757
|
+
return getApiUrl();
|
|
758
|
+
}, []);
|
|
759
|
+
(0, react.useEffect)(() => {
|
|
760
|
+
return () => {
|
|
761
|
+
isMountedRef.current = false;
|
|
762
|
+
if (refreshTimeoutRef.current) clearTimeout(refreshTimeoutRef.current);
|
|
763
|
+
};
|
|
764
|
+
}, []);
|
|
765
|
+
const revokeAllSessions$1 = (0, react.useCallback)(async () => {
|
|
766
|
+
try {
|
|
767
|
+
if (!tokensRef.current) throw new Error("User is not logged in");
|
|
768
|
+
await revokeAllSessions(tokensRef.current.accessToken);
|
|
769
|
+
clearSessionAndSignOut();
|
|
770
|
+
} catch (error) {
|
|
771
|
+
setAuthProviderError(error);
|
|
772
|
+
throw error;
|
|
773
|
+
}
|
|
774
|
+
}, [clearSessionAndSignOut]);
|
|
775
|
+
return {
|
|
776
|
+
user,
|
|
777
|
+
authLoading,
|
|
778
|
+
initialLoading,
|
|
779
|
+
authError,
|
|
780
|
+
authProviderError,
|
|
781
|
+
loginSkipped,
|
|
782
|
+
needsSetup: authConfig?.needsSetup ?? false,
|
|
783
|
+
registrationEnabled: authConfig?.registrationEnabled ?? false,
|
|
784
|
+
getAuthToken,
|
|
785
|
+
getApiUrl: getApiUrl$1,
|
|
786
|
+
signOut,
|
|
787
|
+
emailPasswordLogin,
|
|
788
|
+
register: register$1,
|
|
789
|
+
googleLogin: googleLogin$1,
|
|
790
|
+
oauthLogin: oauthLogin$1,
|
|
791
|
+
skipLogin,
|
|
792
|
+
forgotPassword: forgotPassword$1,
|
|
793
|
+
resetPassword: resetPassword$1,
|
|
794
|
+
changePassword: changePassword$1,
|
|
795
|
+
updateProfile: updateProfile$1,
|
|
796
|
+
fetchSessions: fetchSessions$1,
|
|
797
|
+
revokeSession: revokeSession$1,
|
|
798
|
+
revokeAllSessions: revokeAllSessions$1,
|
|
799
|
+
clearError,
|
|
800
|
+
setAuthProviderError,
|
|
801
|
+
extra,
|
|
802
|
+
setExtra,
|
|
803
|
+
capabilities: {
|
|
804
|
+
emailPasswordLogin: true,
|
|
805
|
+
googleLogin: !!props.googleClientId,
|
|
806
|
+
registration: authConfig?.registrationEnabled ?? false,
|
|
807
|
+
passwordReset: authConfig?.passwordReset ?? false,
|
|
808
|
+
sessionManagement: true,
|
|
809
|
+
profileUpdate: true,
|
|
810
|
+
emailVerification: authConfig?.emailVerification ?? false,
|
|
811
|
+
enabledProviders: authConfig?.enabledProviders ?? []
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
//#endregion
|
|
816
|
+
exports.AuthApiError = AuthApiError;
|
|
817
|
+
exports.fetchAuthConfig = fetchAuthConfig;
|
|
818
|
+
exports.getApiUrl = getApiUrl;
|
|
819
|
+
exports.setApiUrl = setApiUrl;
|
|
820
|
+
exports.useRebaseAuthController = useRebaseAuthController;
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
//# sourceMappingURL=index.umd.js.map
|