@authowl/react 0.22.0 → 0.24.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 +11 -2
- package/dist/OrganizationListContent-BSGDHYAC.js +185 -0
- package/dist/OrganizationProfileContent-HJT33DMJ.js +451 -0
- package/dist/OrganizationSwitcherContent-2TJ76HZM.js +176 -0
- package/dist/PrivacyCenterContent-EQEXXSLA.js +204 -0
- package/dist/{TeamsSection-ZQDNMWV3.js → TeamsSection-VJTKS4KP.js} +8 -4
- package/dist/chunk-2HNQYORD.js +139 -0
- package/dist/chunk-7WIBXVGK.js +19 -0
- package/dist/chunk-IDMSHQ6V.js +106 -0
- package/dist/chunk-SAVEQ6RC.js +83 -0
- package/dist/{chunk-PUJV7S6G.js → chunk-TOVDZ2ZE.js} +93 -160
- package/dist/chunk-ZYCPC5DH.js +46 -0
- package/dist/index.cjs +5325 -4772
- package/dist/index.d.cts +48 -7
- package/dist/index.d.ts +48 -7
- package/dist/index.js +529 -1309
- package/dist/styles.css +58 -0
- package/package.json +2 -2
|
@@ -115,7 +115,7 @@ function readableAccent(brandHex, surfaceHex, dir) {
|
|
|
115
115
|
}
|
|
116
116
|
return dir === 1 ? WHITE : NEAR_BLACK;
|
|
117
117
|
}
|
|
118
|
-
var LIGHT_SURFACE = "#
|
|
118
|
+
var LIGHT_SURFACE = "#f4f4f5";
|
|
119
119
|
var DARK_SURFACE = "#18181b";
|
|
120
120
|
function deriveBrandRamp(primaryHex) {
|
|
121
121
|
const solid = normalizeHex(primaryHex) ?? DEFAULT_BRAND_COLOR.toLowerCase();
|
|
@@ -151,7 +151,7 @@ function brandRampVars(set) {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
// src/hooks.ts
|
|
154
|
-
import * as
|
|
154
|
+
import * as React6 from "react";
|
|
155
155
|
import {
|
|
156
156
|
clearInvitationClaim,
|
|
157
157
|
createMembershipHas,
|
|
@@ -159,10 +159,11 @@ import {
|
|
|
159
159
|
} from "@authowl/core";
|
|
160
160
|
|
|
161
161
|
// src/provider.tsx
|
|
162
|
-
import * as
|
|
162
|
+
import * as React5 from "react";
|
|
163
163
|
import {
|
|
164
164
|
captureInvitationClaim,
|
|
165
165
|
createAuthOwlClient,
|
|
166
|
+
setActiveLocale,
|
|
166
167
|
directionFor,
|
|
167
168
|
getPublicConfig,
|
|
168
169
|
isLocale,
|
|
@@ -367,6 +368,39 @@ function InvitationPrompt() {
|
|
|
367
368
|
);
|
|
368
369
|
}
|
|
369
370
|
|
|
371
|
+
// src/last-used-method.ts
|
|
372
|
+
import * as React4 from "react";
|
|
373
|
+
import {
|
|
374
|
+
readLastUsedSignInMethod,
|
|
375
|
+
recordLastUsedSignInMethod,
|
|
376
|
+
rememberPendingSignInMethod,
|
|
377
|
+
settlePendingSignInMethod
|
|
378
|
+
} from "@authowl/core";
|
|
379
|
+
function useLastUsedSignInMethod() {
|
|
380
|
+
const { config } = usePublicConfig();
|
|
381
|
+
const projectId = config?.environmentId ?? null;
|
|
382
|
+
return React4.useMemo(
|
|
383
|
+
() => projectId ? readLastUsedSignInMethod(projectId) : null,
|
|
384
|
+
[projectId]
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
function useSignInMethodRecorder() {
|
|
388
|
+
const { config } = usePublicConfig();
|
|
389
|
+
const projectId = config?.environmentId ?? null;
|
|
390
|
+
return React4.useCallback(
|
|
391
|
+
(method, pending) => {
|
|
392
|
+
if (!projectId) return;
|
|
393
|
+
(pending ? rememberPendingSignInMethod : recordLastUsedSignInMethod)(projectId, method);
|
|
394
|
+
},
|
|
395
|
+
[projectId]
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
function useConfirmPendingSignInMethod(loaded, signedIn, projectId) {
|
|
399
|
+
React4.useEffect(() => {
|
|
400
|
+
if (loaded && projectId) settlePendingSignInMethod(projectId, signedIn);
|
|
401
|
+
}, [loaded, projectId, signedIn]);
|
|
402
|
+
}
|
|
403
|
+
|
|
370
404
|
// src/provider.tsx
|
|
371
405
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
372
406
|
var warnedConfigProjects = /* @__PURE__ */ new Set();
|
|
@@ -384,7 +418,13 @@ function warnPublicConfigFailed(resolved, error) {
|
|
|
384
418
|
`[AuthOwl] Could not load this project's public config from ${origin} (${reason}). Authentication UI is unavailable until the request succeeds. Likely causes: the API is unreachable, \`apiUrl\` is wrong, or the publishable key points at a missing/mismatched project. Check \`apiUrl\` and \`publishableKey\` on <AuthOwlProvider>. (This warning is dev-only.)`
|
|
385
419
|
);
|
|
386
420
|
}
|
|
387
|
-
|
|
421
|
+
function LastUsedMethodSync() {
|
|
422
|
+
const { config } = usePublicConfig();
|
|
423
|
+
const { isLoaded, isSignedIn } = useUser();
|
|
424
|
+
useConfirmPendingSignInMethod(isLoaded, isSignedIn, config?.environmentId ?? null);
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
427
|
+
var Context = React5.createContext(null);
|
|
388
428
|
function detectLocale() {
|
|
389
429
|
if (typeof document !== "undefined") {
|
|
390
430
|
const root = document.documentElement;
|
|
@@ -409,18 +449,18 @@ function AuthOwlProvider({
|
|
|
409
449
|
invitationPrompt = true,
|
|
410
450
|
children
|
|
411
451
|
}) {
|
|
412
|
-
const fetchRef =
|
|
452
|
+
const fetchRef = React5.useRef(fetch);
|
|
413
453
|
fetchRef.current = fetch;
|
|
414
|
-
const resolved =
|
|
454
|
+
const resolved = React5.useMemo(
|
|
415
455
|
() => resolveConfig({ publishableKey, apiUrl, fetch: fetchRef.current }),
|
|
416
456
|
[publishableKey, apiUrl]
|
|
417
457
|
);
|
|
418
|
-
const client =
|
|
419
|
-
const [config, setConfig] =
|
|
420
|
-
const [configState, setConfigState] =
|
|
421
|
-
const [configAttempt, setConfigAttempt] =
|
|
422
|
-
const retryPublicConfig =
|
|
423
|
-
|
|
458
|
+
const client = React5.useMemo(() => createAuthOwlClient(resolved), [resolved]);
|
|
459
|
+
const [config, setConfig] = React5.useState(null);
|
|
460
|
+
const [configState, setConfigState] = React5.useState("loading");
|
|
461
|
+
const [configAttempt, setConfigAttempt] = React5.useState(0);
|
|
462
|
+
const retryPublicConfig = React5.useCallback(() => setConfigAttempt((attempt) => attempt + 1), []);
|
|
463
|
+
React5.useEffect(() => {
|
|
424
464
|
let active = true;
|
|
425
465
|
setConfigState("loading");
|
|
426
466
|
getPublicConfig(resolved).then((c) => {
|
|
@@ -438,15 +478,18 @@ function AuthOwlProvider({
|
|
|
438
478
|
};
|
|
439
479
|
}, [resolved, configAttempt]);
|
|
440
480
|
const merged = resolveAppearance(appearance, config);
|
|
441
|
-
const [autoLocale, setAutoLocale] =
|
|
442
|
-
|
|
481
|
+
const [autoLocale, setAutoLocale] = React5.useState(null);
|
|
482
|
+
React5.useEffect(() => {
|
|
443
483
|
if (localeProp === "auto") setAutoLocale(detectLocale());
|
|
444
484
|
}, [localeProp]);
|
|
445
485
|
const locale = resolveLocale(localeProp, autoLocale, config?.locale);
|
|
446
|
-
|
|
486
|
+
React5.useEffect(() => {
|
|
487
|
+
return setActiveLocale(resolved.decoded.projectId, locale);
|
|
488
|
+
}, [locale, resolved.decoded.projectId]);
|
|
489
|
+
React5.useEffect(() => {
|
|
447
490
|
captureInvitationClaim();
|
|
448
491
|
}, []);
|
|
449
|
-
const ctxValue =
|
|
492
|
+
const ctxValue = React5.useMemo(
|
|
450
493
|
() => ({ client, appearance, config, configState, retryPublicConfig, locale }),
|
|
451
494
|
[client, appearance, config, configState, retryPublicConfig, locale]
|
|
452
495
|
);
|
|
@@ -460,13 +503,14 @@ function AuthOwlProvider({
|
|
|
460
503
|
style: { display: "contents", ...merged.style },
|
|
461
504
|
children: [
|
|
462
505
|
children,
|
|
506
|
+
/* @__PURE__ */ jsx4(LastUsedMethodSync, {}),
|
|
463
507
|
invitationPrompt ? /* @__PURE__ */ jsx4(InvitationPrompt, {}) : null
|
|
464
508
|
]
|
|
465
509
|
}
|
|
466
510
|
) });
|
|
467
511
|
}
|
|
468
512
|
function useAuthOwlContext() {
|
|
469
|
-
const v =
|
|
513
|
+
const v = React5.useContext(Context);
|
|
470
514
|
if (!v) {
|
|
471
515
|
throw new Error("AuthOwl hooks must be used inside <AuthOwlProvider>");
|
|
472
516
|
}
|
|
@@ -490,6 +534,9 @@ function useAuthClient() {
|
|
|
490
534
|
function useAccount() {
|
|
491
535
|
return useAuthClient().account;
|
|
492
536
|
}
|
|
537
|
+
function usePrivacy() {
|
|
538
|
+
return useAuthClient().privacy;
|
|
539
|
+
}
|
|
493
540
|
function usePublicConfig() {
|
|
494
541
|
const { config, configState, retryPublicConfig } = useAuthOwlContext();
|
|
495
542
|
return {
|
|
@@ -501,7 +548,7 @@ function usePublicConfig() {
|
|
|
501
548
|
}
|
|
502
549
|
function useSession() {
|
|
503
550
|
const client = useAuthClient();
|
|
504
|
-
return
|
|
551
|
+
return React6.useSyncExternalStore(
|
|
505
552
|
client.sessionStore.subscribe,
|
|
506
553
|
client.sessionStore.getSnapshot,
|
|
507
554
|
client.sessionStore.getSnapshot
|
|
@@ -531,16 +578,16 @@ function useAuth() {
|
|
|
531
578
|
}
|
|
532
579
|
function useOrganization() {
|
|
533
580
|
const client = useAuthClient();
|
|
534
|
-
const apiRef =
|
|
581
|
+
const apiRef = React6.useRef(client.organization);
|
|
535
582
|
apiRef.current = client.organization;
|
|
536
583
|
const { data, isPending } = useSession();
|
|
537
584
|
const membership = data?.session?.membership ?? null;
|
|
538
585
|
const activeOrganizationId = data?.session?.activeOrganizationId ?? null;
|
|
539
586
|
const identity = data?.user?.id ?? null;
|
|
540
|
-
const [organization, setOrganization] =
|
|
541
|
-
const [orgLoaded, setOrgLoaded] =
|
|
542
|
-
const requestRef =
|
|
543
|
-
|
|
587
|
+
const [organization, setOrganization] = React6.useState(null);
|
|
588
|
+
const [orgLoaded, setOrgLoaded] = React6.useState(false);
|
|
589
|
+
const requestRef = React6.useRef(0);
|
|
590
|
+
React6.useEffect(() => {
|
|
544
591
|
const token = ++requestRef.current;
|
|
545
592
|
setOrganization(null);
|
|
546
593
|
setOrgLoaded(false);
|
|
@@ -564,7 +611,7 @@ function useOrganization() {
|
|
|
564
611
|
requestRef.current += 1;
|
|
565
612
|
};
|
|
566
613
|
}, [identity, activeOrganizationId, isPending]);
|
|
567
|
-
const bound =
|
|
614
|
+
const bound = React6.useMemo(() => createMembershipHas(membership), [membership]);
|
|
568
615
|
return {
|
|
569
616
|
organization,
|
|
570
617
|
membership,
|
|
@@ -579,13 +626,13 @@ function useOrganization() {
|
|
|
579
626
|
}
|
|
580
627
|
function useInvitationRecipientHint() {
|
|
581
628
|
const client = useAuthClient();
|
|
582
|
-
const apiRef =
|
|
629
|
+
const apiRef = React6.useRef(client.organization);
|
|
583
630
|
apiRef.current = client.organization;
|
|
584
|
-
const [result, setResult] =
|
|
631
|
+
const [result, setResult] = React6.useState({
|
|
585
632
|
recipientHint: null,
|
|
586
633
|
isLoaded: false
|
|
587
634
|
});
|
|
588
|
-
|
|
635
|
+
React6.useEffect(() => {
|
|
589
636
|
let active = true;
|
|
590
637
|
const claim = readInvitationClaim();
|
|
591
638
|
if (!claim) {
|
|
@@ -616,18 +663,18 @@ function useInvitationRecipientHint() {
|
|
|
616
663
|
}
|
|
617
664
|
function useOrganizationInvitation() {
|
|
618
665
|
const client = useAuthClient();
|
|
619
|
-
const apiRef =
|
|
666
|
+
const apiRef = React6.useRef(client.organization);
|
|
620
667
|
apiRef.current = client.organization;
|
|
621
668
|
const { data, isPending } = useSession();
|
|
622
669
|
const identity = data?.user?.id ?? null;
|
|
623
|
-
const [claim, setClaim] =
|
|
624
|
-
const [invitation, setInvitation] =
|
|
625
|
-
const [status, setStatus] =
|
|
626
|
-
const requestRef =
|
|
627
|
-
|
|
670
|
+
const [claim, setClaim] = React6.useState(null);
|
|
671
|
+
const [invitation, setInvitation] = React6.useState(null);
|
|
672
|
+
const [status, setStatus] = React6.useState("idle");
|
|
673
|
+
const requestRef = React6.useRef(0);
|
|
674
|
+
React6.useEffect(() => {
|
|
628
675
|
setClaim(readInvitationClaim());
|
|
629
676
|
}, [identity]);
|
|
630
|
-
|
|
677
|
+
React6.useEffect(() => {
|
|
631
678
|
const token = ++requestRef.current;
|
|
632
679
|
if (isPending || !claim) return;
|
|
633
680
|
if (!identity) {
|
|
@@ -650,7 +697,7 @@ function useOrganizationInvitation() {
|
|
|
650
697
|
requestRef.current += 1;
|
|
651
698
|
};
|
|
652
699
|
}, [claim, identity, isPending]);
|
|
653
|
-
const accept =
|
|
700
|
+
const accept = React6.useCallback(async () => {
|
|
654
701
|
const current = readInvitationClaim();
|
|
655
702
|
if (!current) return false;
|
|
656
703
|
setStatus("joining");
|
|
@@ -672,7 +719,7 @@ function useOrganizationInvitation() {
|
|
|
672
719
|
} else setStatus("error");
|
|
673
720
|
return false;
|
|
674
721
|
}, []);
|
|
675
|
-
const dismiss =
|
|
722
|
+
const dismiss = React6.useCallback(() => {
|
|
676
723
|
clearInvitationClaim();
|
|
677
724
|
setClaim(null);
|
|
678
725
|
setInvitation(null);
|
|
@@ -733,10 +780,10 @@ function useConsent() {
|
|
|
733
780
|
const client = useAuthClient();
|
|
734
781
|
const { user, isLoaded } = useUser();
|
|
735
782
|
const userId = user?.id ?? null;
|
|
736
|
-
const [status, setStatus] =
|
|
737
|
-
const [isLoading, setIsLoading] =
|
|
738
|
-
const reqRef =
|
|
739
|
-
const load =
|
|
783
|
+
const [status, setStatus] = React6.useState(null);
|
|
784
|
+
const [isLoading, setIsLoading] = React6.useState(true);
|
|
785
|
+
const reqRef = React6.useRef(0);
|
|
786
|
+
const load = React6.useCallback(async () => {
|
|
740
787
|
const reqId = ++reqRef.current;
|
|
741
788
|
setIsLoading(true);
|
|
742
789
|
let next;
|
|
@@ -749,7 +796,7 @@ function useConsent() {
|
|
|
749
796
|
setStatus(next);
|
|
750
797
|
setIsLoading(false);
|
|
751
798
|
}, [client]);
|
|
752
|
-
|
|
799
|
+
React6.useEffect(() => {
|
|
753
800
|
reqRef.current += 1;
|
|
754
801
|
setStatus(null);
|
|
755
802
|
if (!isLoaded) {
|
|
@@ -759,7 +806,7 @@ function useConsent() {
|
|
|
759
806
|
void load();
|
|
760
807
|
}, [load, isLoaded, userId]);
|
|
761
808
|
const version = typeof status?.version === "number" && Number.isFinite(status.version) ? status.version : null;
|
|
762
|
-
const accept =
|
|
809
|
+
const accept = React6.useCallback(async () => {
|
|
763
810
|
if (version == null) return;
|
|
764
811
|
try {
|
|
765
812
|
await client.acceptConsent(version);
|
|
@@ -782,35 +829,6 @@ function useSignOut() {
|
|
|
782
829
|
return { signOut: client.signOut };
|
|
783
830
|
}
|
|
784
831
|
|
|
785
|
-
// src/components/use-submit-action.ts
|
|
786
|
-
import * as React6 from "react";
|
|
787
|
-
function useSubmitAction() {
|
|
788
|
-
const [pending, setPending] = React6.useState(false);
|
|
789
|
-
const [error, setError] = React6.useState(null);
|
|
790
|
-
const toMessage = useServerError();
|
|
791
|
-
const run = React6.useCallback(
|
|
792
|
-
async (action, { failure, onSuccess, mapError, keepPendingOnSuccess }) => {
|
|
793
|
-
setError(null);
|
|
794
|
-
setPending(true);
|
|
795
|
-
try {
|
|
796
|
-
const res = await action();
|
|
797
|
-
if (res?.error) {
|
|
798
|
-
setError(mapError?.(res.error) ?? toMessage(res.error, failure));
|
|
799
|
-
setPending(false);
|
|
800
|
-
return;
|
|
801
|
-
}
|
|
802
|
-
await onSuccess?.(res ?? { data: null, error: null });
|
|
803
|
-
if (!keepPendingOnSuccess) setPending(false);
|
|
804
|
-
} catch {
|
|
805
|
-
setError(failure);
|
|
806
|
-
setPending(false);
|
|
807
|
-
}
|
|
808
|
-
},
|
|
809
|
-
[toMessage]
|
|
810
|
-
);
|
|
811
|
-
return { pending, error, setError, run };
|
|
812
|
-
}
|
|
813
|
-
|
|
814
832
|
// src/components/Spinner.tsx
|
|
815
833
|
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
816
834
|
function Spinner() {
|
|
@@ -839,91 +857,11 @@ function FormError({ children, className, "data-testid": testId }) {
|
|
|
839
857
|
);
|
|
840
858
|
}
|
|
841
859
|
|
|
842
|
-
// src/components/organization/model.ts
|
|
843
|
-
function organizationSlugFromName(name) {
|
|
844
|
-
return name.normalize("NFKD").toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 63);
|
|
845
|
-
}
|
|
846
|
-
function organizationRoles(role) {
|
|
847
|
-
return role.split(",").map((value) => value.trim()).filter(Boolean);
|
|
848
|
-
}
|
|
849
|
-
function hasOrganizationRole(member, role) {
|
|
850
|
-
return member ? organizationRoles(member.role).includes(role) : false;
|
|
851
|
-
}
|
|
852
|
-
function canManageOrganization(member) {
|
|
853
|
-
return hasOrganizationRole(member, "owner") || hasOrganizationRole(member, "admin");
|
|
854
|
-
}
|
|
855
|
-
function roleHasStatement(roles, heldRoles, resource, action) {
|
|
856
|
-
return roles.some((role) => {
|
|
857
|
-
if (!heldRoles.has(role.role) || typeof role.permission !== "object" || role.permission === null) {
|
|
858
|
-
return false;
|
|
859
|
-
}
|
|
860
|
-
const actions = role.permission[resource];
|
|
861
|
-
return Array.isArray(actions) && actions.includes(action);
|
|
862
|
-
});
|
|
863
|
-
}
|
|
864
|
-
function teamManagementCapabilities(member, dynamicRoles) {
|
|
865
|
-
const heldRoles = new Set(organizationRoles(member.role));
|
|
866
|
-
if (heldRoles.has("owner") || heldRoles.has("admin")) {
|
|
867
|
-
return {
|
|
868
|
-
createTeam: true,
|
|
869
|
-
updateTeam: true,
|
|
870
|
-
deleteTeam: true,
|
|
871
|
-
addTeamMember: true,
|
|
872
|
-
removeTeamMember: true
|
|
873
|
-
};
|
|
874
|
-
}
|
|
875
|
-
return {
|
|
876
|
-
createTeam: roleHasStatement(dynamicRoles, heldRoles, "team", "create"),
|
|
877
|
-
updateTeam: roleHasStatement(dynamicRoles, heldRoles, "team", "update"),
|
|
878
|
-
deleteTeam: roleHasStatement(dynamicRoles, heldRoles, "team", "delete"),
|
|
879
|
-
addTeamMember: roleHasStatement(dynamicRoles, heldRoles, "member", "update"),
|
|
880
|
-
removeTeamMember: roleHasStatement(dynamicRoles, heldRoles, "member", "delete")
|
|
881
|
-
};
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
// src/components/organization/use-organization-roles.ts
|
|
885
|
-
import * as React7 from "react";
|
|
886
|
-
var BUILTIN_ROLES = ["owner", "admin", "member"];
|
|
887
|
-
function useOrganizationRoles(organizationId) {
|
|
888
|
-
const api = useAuthClient().organization;
|
|
889
|
-
const apiRef = React7.useRef(api);
|
|
890
|
-
apiRef.current = api;
|
|
891
|
-
const [dynamicRoles, setDynamicRoles] = React7.useState([]);
|
|
892
|
-
const requestRef = React7.useRef(0);
|
|
893
|
-
React7.useEffect(() => {
|
|
894
|
-
const token = ++requestRef.current;
|
|
895
|
-
setDynamicRoles([]);
|
|
896
|
-
if (!organizationId) return;
|
|
897
|
-
void (async () => {
|
|
898
|
-
try {
|
|
899
|
-
const result = await apiRef.current.listRoles({ organizationId });
|
|
900
|
-
if (token !== requestRef.current) return;
|
|
901
|
-
setDynamicRoles((result.data ?? []).filter((entry) => entry.role.trim().length > 0));
|
|
902
|
-
} catch {
|
|
903
|
-
}
|
|
904
|
-
})();
|
|
905
|
-
return () => {
|
|
906
|
-
requestRef.current += 1;
|
|
907
|
-
};
|
|
908
|
-
}, [organizationId]);
|
|
909
|
-
const roles = React7.useMemo(() => {
|
|
910
|
-
const seen = /* @__PURE__ */ new Set();
|
|
911
|
-
const out = [];
|
|
912
|
-
for (const candidate of [...BUILTIN_ROLES, ...dynamicRoles.map((entry) => entry.role)]) {
|
|
913
|
-
const key = candidate.trim();
|
|
914
|
-
if (!key || seen.has(key)) continue;
|
|
915
|
-
seen.add(key);
|
|
916
|
-
out.push(key);
|
|
917
|
-
}
|
|
918
|
-
return out;
|
|
919
|
-
}, [dynamicRoles]);
|
|
920
|
-
return { roles, dynamicRoles };
|
|
921
|
-
}
|
|
922
|
-
|
|
923
860
|
export {
|
|
924
861
|
DEFAULT_BRAND_COLOR,
|
|
925
862
|
useAuthClient,
|
|
926
863
|
useAccount,
|
|
864
|
+
usePrivacy,
|
|
927
865
|
usePublicConfig,
|
|
928
866
|
useSession,
|
|
929
867
|
useUser,
|
|
@@ -947,16 +885,11 @@ export {
|
|
|
947
885
|
useServerError,
|
|
948
886
|
ModalSurface,
|
|
949
887
|
InvitationPrompt,
|
|
888
|
+
useLastUsedSignInMethod,
|
|
889
|
+
useSignInMethodRecorder,
|
|
950
890
|
AuthOwlProvider,
|
|
951
891
|
useAuthOwlContext,
|
|
952
|
-
useSubmitAction,
|
|
953
892
|
Spinner,
|
|
954
893
|
Busy,
|
|
955
|
-
FormError
|
|
956
|
-
organizationSlugFromName,
|
|
957
|
-
organizationRoles,
|
|
958
|
-
hasOrganizationRole,
|
|
959
|
-
canManageOrganization,
|
|
960
|
-
teamManagementCapabilities,
|
|
961
|
-
useOrganizationRoles
|
|
894
|
+
FormError
|
|
962
895
|
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useAuthClient
|
|
3
|
+
} from "./chunk-TOVDZ2ZE.js";
|
|
4
|
+
|
|
5
|
+
// src/components/organization/use-organization-roles.ts
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
var BUILTIN_ROLES = ["owner", "admin", "member"];
|
|
8
|
+
function useOrganizationRoles(organizationId) {
|
|
9
|
+
const api = useAuthClient().organization;
|
|
10
|
+
const apiRef = React.useRef(api);
|
|
11
|
+
apiRef.current = api;
|
|
12
|
+
const [dynamicRoles, setDynamicRoles] = React.useState([]);
|
|
13
|
+
const requestRef = React.useRef(0);
|
|
14
|
+
React.useEffect(() => {
|
|
15
|
+
const token = ++requestRef.current;
|
|
16
|
+
setDynamicRoles([]);
|
|
17
|
+
if (!organizationId) return;
|
|
18
|
+
void (async () => {
|
|
19
|
+
try {
|
|
20
|
+
const result = await apiRef.current.listRoles({ organizationId });
|
|
21
|
+
if (token !== requestRef.current) return;
|
|
22
|
+
setDynamicRoles((result.data ?? []).filter((entry) => entry.role.trim().length > 0));
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
})();
|
|
26
|
+
return () => {
|
|
27
|
+
requestRef.current += 1;
|
|
28
|
+
};
|
|
29
|
+
}, [organizationId]);
|
|
30
|
+
const roles = React.useMemo(() => {
|
|
31
|
+
const seen = /* @__PURE__ */ new Set();
|
|
32
|
+
const out = [];
|
|
33
|
+
for (const candidate of [...BUILTIN_ROLES, ...dynamicRoles.map((entry) => entry.role)]) {
|
|
34
|
+
const key = candidate.trim();
|
|
35
|
+
if (!key || seen.has(key)) continue;
|
|
36
|
+
seen.add(key);
|
|
37
|
+
out.push(key);
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}, [dynamicRoles]);
|
|
41
|
+
return { roles, dynamicRoles };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
useOrganizationRoles
|
|
46
|
+
};
|