@authowl/react-native 0.3.15 → 0.4.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 +9 -1
- package/dist/index.cjs +420 -61
- package/dist/index.d.cts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +424 -63
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -168,6 +168,9 @@ function usePublicConfig() {
|
|
|
168
168
|
isLoading: publicConfigState === "loading"
|
|
169
169
|
};
|
|
170
170
|
}
|
|
171
|
+
function usePrivacy() {
|
|
172
|
+
return useAuthOwlContext().client.privacy;
|
|
173
|
+
}
|
|
171
174
|
function useSession() {
|
|
172
175
|
const { client } = useAuthOwlContext();
|
|
173
176
|
const store = client.sessionStore;
|
|
@@ -521,11 +524,15 @@ function SignIn({
|
|
|
521
524
|
// src/components/SignUp.tsx
|
|
522
525
|
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
523
526
|
import { Linking, Pressable as Pressable2, Text as Text3, View as View3 } from "react-native";
|
|
524
|
-
import {
|
|
527
|
+
import {
|
|
528
|
+
buildPrivacySignUpEvidence,
|
|
529
|
+
createIdempotencyKey,
|
|
530
|
+
resolveProjectCapabilities as resolveProjectCapabilities2
|
|
531
|
+
} from "@authowl/core/native";
|
|
525
532
|
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
526
533
|
function SignUp({ onSignedUp, structuredName = false, theme = defaultTheme }) {
|
|
527
534
|
const t = useT();
|
|
528
|
-
const { direction } = useLocale();
|
|
535
|
+
const { locale, direction } = useLocale();
|
|
529
536
|
const toMessage = useServerError();
|
|
530
537
|
const client = useAuthOwlClient();
|
|
531
538
|
const config = usePublicConfig();
|
|
@@ -539,10 +546,18 @@ function SignUp({ onSignedUp, structuredName = false, theme = defaultTheme }) {
|
|
|
539
546
|
const [busy, setBusy] = useState3(false);
|
|
540
547
|
const [error, setError] = useState3(null);
|
|
541
548
|
const [acceptedConsent, setAcceptedConsent] = useState3(false);
|
|
549
|
+
const [grantedPurposeCodes, setGrantedPurposeCodes] = useState3(
|
|
550
|
+
() => /* @__PURE__ */ new Set()
|
|
551
|
+
);
|
|
552
|
+
const [privacyCorrelationId] = useState3(createIdempotencyKey);
|
|
542
553
|
const legal = config.data?.legal;
|
|
554
|
+
const privacy = config.data?.privacy;
|
|
543
555
|
useEffect2(() => {
|
|
544
556
|
setAcceptedConsent(false);
|
|
545
557
|
}, [legal?.version]);
|
|
558
|
+
useEffect2(() => {
|
|
559
|
+
setGrantedPurposeCodes(/* @__PURE__ */ new Set());
|
|
560
|
+
}, [privacy]);
|
|
546
561
|
const useStructuredName = structuredName || capabilities.firstLastName;
|
|
547
562
|
const displayName = useStructuredName ? [firstName.trim(), lastName.trim()].filter(Boolean).join(" ") : name.trim();
|
|
548
563
|
const canSubmit = email.trim().length > 0 && password.length >= capabilities.passwordMinLength && password.length <= capabilities.passwordMaxLength && displayName.length > 0 && (!legal?.required || acceptedConsent);
|
|
@@ -555,6 +570,14 @@ function SignUp({ onSignedUp, structuredName = false, theme = defaultTheme }) {
|
|
|
555
570
|
password,
|
|
556
571
|
name: displayName,
|
|
557
572
|
...legal?.required ? { consentVersion: legal.version } : {},
|
|
573
|
+
...privacy && privacy.notices.length > 0 ? {
|
|
574
|
+
privacyEvidence: buildPrivacySignUpEvidence(
|
|
575
|
+
privacy,
|
|
576
|
+
locale,
|
|
577
|
+
grantedPurposeCodes,
|
|
578
|
+
privacyCorrelationId
|
|
579
|
+
)
|
|
580
|
+
} : {},
|
|
558
581
|
...useStructuredName ? { firstName: firstName.trim(), lastName: lastName.trim() } : {}
|
|
559
582
|
});
|
|
560
583
|
setBusy(false);
|
|
@@ -692,6 +715,25 @@ function SignUp({ onSignedUp, structuredName = false, theme = defaultTheme }) {
|
|
|
692
715
|
consentSuffix
|
|
693
716
|
] })
|
|
694
717
|
] }) : null,
|
|
718
|
+
privacy && (privacy.notices.length > 0 || privacy.consentPurposes.length > 0) ? /* @__PURE__ */ jsx3(
|
|
719
|
+
NativePrivacySignUpEvidence,
|
|
720
|
+
{
|
|
721
|
+
privacy,
|
|
722
|
+
locale,
|
|
723
|
+
direction,
|
|
724
|
+
grantedPurposeCodes,
|
|
725
|
+
onPurposeChange: (purposeCode, granted) => {
|
|
726
|
+
setGrantedPurposeCodes((current) => {
|
|
727
|
+
const next = new Set(current);
|
|
728
|
+
if (granted) next.add(purposeCode);
|
|
729
|
+
else next.delete(purposeCode);
|
|
730
|
+
return next;
|
|
731
|
+
});
|
|
732
|
+
},
|
|
733
|
+
theme,
|
|
734
|
+
disabled: busy
|
|
735
|
+
}
|
|
736
|
+
) : null,
|
|
695
737
|
/* @__PURE__ */ jsx3(FormError, { message: error, theme }),
|
|
696
738
|
/* @__PURE__ */ jsx3(
|
|
697
739
|
SubmitButton,
|
|
@@ -707,21 +749,338 @@ function SignUp({ onSignedUp, structuredName = false, theme = defaultTheme }) {
|
|
|
707
749
|
)
|
|
708
750
|
] });
|
|
709
751
|
}
|
|
752
|
+
function NativePrivacySignUpEvidence({
|
|
753
|
+
privacy,
|
|
754
|
+
locale,
|
|
755
|
+
direction,
|
|
756
|
+
grantedPurposeCodes,
|
|
757
|
+
onPurposeChange,
|
|
758
|
+
theme,
|
|
759
|
+
disabled
|
|
760
|
+
}) {
|
|
761
|
+
const t = useT();
|
|
762
|
+
return /* @__PURE__ */ jsxs3(
|
|
763
|
+
View3,
|
|
764
|
+
{
|
|
765
|
+
style: {
|
|
766
|
+
gap: theme.spacing,
|
|
767
|
+
borderWidth: 1,
|
|
768
|
+
borderColor: theme.border,
|
|
769
|
+
borderRadius: theme.radius,
|
|
770
|
+
backgroundColor: theme.surface,
|
|
771
|
+
padding: theme.spacing
|
|
772
|
+
},
|
|
773
|
+
testID: "authowl-signup-privacy-evidence",
|
|
774
|
+
children: [
|
|
775
|
+
/* @__PURE__ */ jsxs3(View3, { style: { gap: 4 }, children: [
|
|
776
|
+
/* @__PURE__ */ jsx3(Text3, { style: { color: theme.text, fontSize: 16, fontWeight: "600" }, children: t("privacy.signup.title") }),
|
|
777
|
+
/* @__PURE__ */ jsx3(Text3, { style: { color: theme.mutedText, fontSize: 13, lineHeight: 19 }, children: t("privacy.signup.description") })
|
|
778
|
+
] }),
|
|
779
|
+
privacy.notices.map((notice) => /* @__PURE__ */ jsxs3(
|
|
780
|
+
View3,
|
|
781
|
+
{
|
|
782
|
+
style: { gap: 4, borderTopWidth: 1, borderTopColor: theme.border, paddingTop: 10 },
|
|
783
|
+
children: [
|
|
784
|
+
/* @__PURE__ */ jsx3(Text3, { style: { color: theme.text, fontSize: 14, fontWeight: "600", writingDirection: direction }, children: notice.title[locale] }),
|
|
785
|
+
/* @__PURE__ */ jsx3(Text3, { style: { color: theme.mutedText, fontSize: 12, lineHeight: 18, writingDirection: direction }, children: notice.body[locale] })
|
|
786
|
+
]
|
|
787
|
+
},
|
|
788
|
+
notice.noticeVersionId
|
|
789
|
+
)),
|
|
790
|
+
privacy.consentPurposes.length > 0 ? /* @__PURE__ */ jsxs3(View3, { style: { gap: 8 }, children: [
|
|
791
|
+
/* @__PURE__ */ jsx3(Text3, { style: { color: theme.text, fontSize: 13, fontWeight: "600" }, children: t("privacy.signup.optional") }),
|
|
792
|
+
privacy.consentPurposes.map((purpose) => {
|
|
793
|
+
const granted = grantedPurposeCodes.has(purpose.code);
|
|
794
|
+
return /* @__PURE__ */ jsxs3(
|
|
795
|
+
Pressable2,
|
|
796
|
+
{
|
|
797
|
+
testID: `authowl-signup-purpose-${purpose.code}`,
|
|
798
|
+
accessibilityRole: "checkbox",
|
|
799
|
+
accessibilityState: { checked: granted, disabled },
|
|
800
|
+
disabled,
|
|
801
|
+
onPress: () => onPurposeChange(purpose.code, !granted),
|
|
802
|
+
style: { flexDirection: "row", alignItems: "flex-start", gap: 8 },
|
|
803
|
+
children: [
|
|
804
|
+
/* @__PURE__ */ jsx3(
|
|
805
|
+
View3,
|
|
806
|
+
{
|
|
807
|
+
style: {
|
|
808
|
+
width: 18,
|
|
809
|
+
height: 18,
|
|
810
|
+
alignItems: "center",
|
|
811
|
+
justifyContent: "center",
|
|
812
|
+
borderWidth: 1,
|
|
813
|
+
borderColor: granted ? theme.accent : theme.border,
|
|
814
|
+
borderRadius: 4,
|
|
815
|
+
backgroundColor: granted ? theme.accent : theme.background
|
|
816
|
+
},
|
|
817
|
+
children: granted ? /* @__PURE__ */ jsx3(Text3, { style: { color: theme.accentText, fontSize: 13 }, children: "\u2713" }) : null
|
|
818
|
+
}
|
|
819
|
+
),
|
|
820
|
+
/* @__PURE__ */ jsxs3(View3, { style: { flex: 1, gap: 2 }, children: [
|
|
821
|
+
/* @__PURE__ */ jsx3(Text3, { style: { color: theme.text, fontSize: 13, fontWeight: "600", writingDirection: direction }, children: purpose.title[locale] }),
|
|
822
|
+
/* @__PURE__ */ jsx3(Text3, { style: { color: theme.mutedText, fontSize: 12, lineHeight: 17, writingDirection: direction }, children: purpose.description[locale] })
|
|
823
|
+
] })
|
|
824
|
+
]
|
|
825
|
+
},
|
|
826
|
+
purpose.purposeVersionId
|
|
827
|
+
);
|
|
828
|
+
}),
|
|
829
|
+
/* @__PURE__ */ jsx3(Text3, { style: { color: theme.mutedText, fontSize: 12, lineHeight: 18 }, children: t("privacy.signup.choiceNote") })
|
|
830
|
+
] }) : null
|
|
831
|
+
]
|
|
832
|
+
}
|
|
833
|
+
);
|
|
834
|
+
}
|
|
710
835
|
|
|
711
|
-
// src/components/
|
|
712
|
-
import { useState as useState4 } from "react";
|
|
713
|
-
import { Text as Text4, View as View4 } from "react-native";
|
|
836
|
+
// src/components/PrivacyCenter.tsx
|
|
837
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo4, useState as useState4 } from "react";
|
|
838
|
+
import { ActivityIndicator as ActivityIndicator2, Pressable as Pressable3, Text as Text4, View as View4 } from "react-native";
|
|
714
839
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
840
|
+
var RIGHT_KEYS = {
|
|
841
|
+
access: "privacy.right.access",
|
|
842
|
+
correction: "privacy.right.correction",
|
|
843
|
+
portability: "privacy.right.portability",
|
|
844
|
+
erasure: "privacy.right.erasure",
|
|
845
|
+
restriction: "privacy.right.restriction",
|
|
846
|
+
objection: "privacy.right.objection",
|
|
847
|
+
consent_withdrawal: "privacy.right.consentWithdrawal"
|
|
848
|
+
};
|
|
849
|
+
var STATE_KEYS = {
|
|
850
|
+
received: "privacy.state.received",
|
|
851
|
+
identity_pending: "privacy.state.identityPending",
|
|
852
|
+
in_progress: "privacy.state.inProgress",
|
|
853
|
+
restricted: "privacy.state.restricted",
|
|
854
|
+
completed: "privacy.state.completed",
|
|
855
|
+
denied: "privacy.state.denied",
|
|
856
|
+
withdrawn: "privacy.state.withdrawn"
|
|
857
|
+
};
|
|
858
|
+
function PrivacyCenter({ theme = defaultTheme } = {}) {
|
|
859
|
+
const t = useT();
|
|
860
|
+
const { locale, direction } = useLocale();
|
|
861
|
+
const toMessage = useServerError();
|
|
862
|
+
const client = useAuthOwlClient();
|
|
863
|
+
const config = usePublicConfig();
|
|
864
|
+
const session = useSession();
|
|
865
|
+
const [preferences, setPreferences] = useState4([]);
|
|
866
|
+
const [requests, setRequests] = useState4([]);
|
|
867
|
+
const [loading, setLoading] = useState4(true);
|
|
868
|
+
const [error, setError] = useState4(null);
|
|
869
|
+
const [pendingPurpose, setPendingPurpose] = useState4(null);
|
|
870
|
+
const [pendingRight, setPendingRight] = useState4(null);
|
|
871
|
+
const signedIn = session.data !== null;
|
|
872
|
+
const refresh = useCallback2(async (showLoading = false) => {
|
|
873
|
+
if (!signedIn) {
|
|
874
|
+
setLoading(false);
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
if (showLoading) setLoading(true);
|
|
878
|
+
const [consent, rights] = await Promise.all([
|
|
879
|
+
client.privacy.listConsentPreferences(),
|
|
880
|
+
client.privacy.listRightsRequests()
|
|
881
|
+
]);
|
|
882
|
+
const failure = consent.error ?? rights.error;
|
|
883
|
+
if (failure) setError(toMessage(failure, "privacy.error.load"));
|
|
884
|
+
else {
|
|
885
|
+
setPreferences(consent.data?.preferences ?? []);
|
|
886
|
+
setRequests(rights.data?.requests ?? []);
|
|
887
|
+
setError(null);
|
|
888
|
+
}
|
|
889
|
+
setLoading(false);
|
|
890
|
+
}, [client, signedIn, toMessage]);
|
|
891
|
+
useEffect3(() => {
|
|
892
|
+
if (!session.isPending) void refresh(true);
|
|
893
|
+
}, [refresh, session.data?.user.id, session.isPending]);
|
|
894
|
+
const preferencesByCode = useMemo4(
|
|
895
|
+
() => new Map(preferences.map((preference) => [preference.code, preference])),
|
|
896
|
+
[preferences]
|
|
897
|
+
);
|
|
898
|
+
async function updateConsent(purposeCode, granted) {
|
|
899
|
+
const privacy2 = config.data?.privacy;
|
|
900
|
+
const purpose = privacy2?.consentPurposes.find((item) => item.code === purposeCode);
|
|
901
|
+
const notice = privacy2?.notices.find((item) => item.purposeCodes.includes(purposeCode));
|
|
902
|
+
if (!purpose || !notice) {
|
|
903
|
+
setError(t("privacy.error.unavailable"));
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
setPendingPurpose(purposeCode);
|
|
907
|
+
setError(null);
|
|
908
|
+
const result = await client.privacy.recordConsent({
|
|
909
|
+
purposeCode,
|
|
910
|
+
purposeVersionId: purpose.purposeVersionId,
|
|
911
|
+
noticeVersionId: notice.noticeVersionId,
|
|
912
|
+
decision: granted ? "granted" : "withdrawn",
|
|
913
|
+
locale
|
|
914
|
+
});
|
|
915
|
+
if (result.error) setError(toMessage(result.error, "privacy.error.save"));
|
|
916
|
+
else await refresh();
|
|
917
|
+
setPendingPurpose(null);
|
|
918
|
+
}
|
|
919
|
+
async function createRequest(rightType) {
|
|
920
|
+
setPendingRight(rightType);
|
|
921
|
+
setError(null);
|
|
922
|
+
const result = await client.privacy.createRightsRequest({ rightType, locale });
|
|
923
|
+
if (result.error) setError(toMessage(result.error, "privacy.error.request"));
|
|
924
|
+
else await refresh();
|
|
925
|
+
setPendingRight(null);
|
|
926
|
+
}
|
|
927
|
+
if (session.isPending || loading) {
|
|
928
|
+
return /* @__PURE__ */ jsx4(ActivityIndicator2, { color: theme.accent, testID: "authowl-privacy-loading" });
|
|
929
|
+
}
|
|
930
|
+
if (!signedIn) return /* @__PURE__ */ jsx4(Text4, { style: { color: theme.mutedText }, children: t("privacy.signedOut") });
|
|
931
|
+
const privacy = config.data?.privacy;
|
|
932
|
+
return /* @__PURE__ */ jsxs4(
|
|
933
|
+
View4,
|
|
934
|
+
{
|
|
935
|
+
testID: "authowl-privacy-center",
|
|
936
|
+
style: { gap: theme.spacing, backgroundColor: theme.background },
|
|
937
|
+
children: [
|
|
938
|
+
/* @__PURE__ */ jsxs4(View4, { style: { gap: 4 }, children: [
|
|
939
|
+
/* @__PURE__ */ jsx4(Text4, { style: { color: theme.mutedText, fontSize: 12, fontWeight: "700" }, children: t("privacy.dataUse") }),
|
|
940
|
+
/* @__PURE__ */ jsx4(Text4, { style: { color: theme.text, fontSize: 22, fontWeight: "600" }, children: t("privacy.title") }),
|
|
941
|
+
/* @__PURE__ */ jsx4(Text4, { style: { color: theme.mutedText, fontSize: 14, lineHeight: 20 }, children: t("privacy.description") })
|
|
942
|
+
] }),
|
|
943
|
+
/* @__PURE__ */ jsx4(FormError, { message: error, theme, testID: "authowl-privacy-error" }),
|
|
944
|
+
/* @__PURE__ */ jsx4(
|
|
945
|
+
PrivacyBlock,
|
|
946
|
+
{
|
|
947
|
+
title: t("privacy.choices.title"),
|
|
948
|
+
description: t("privacy.choices.description"),
|
|
949
|
+
theme,
|
|
950
|
+
children: (privacy?.consentPurposes.length ?? 0) === 0 ? /* @__PURE__ */ jsx4(Text4, { style: { color: theme.mutedText }, children: t("privacy.choices.empty") }) : privacy.consentPurposes.map((purpose) => {
|
|
951
|
+
const granted = preferencesByCode.get(purpose.code)?.state === "granted";
|
|
952
|
+
const pending = pendingPurpose === purpose.code;
|
|
953
|
+
return /* @__PURE__ */ jsxs4(
|
|
954
|
+
View4,
|
|
955
|
+
{
|
|
956
|
+
style: { flexDirection: "row", alignItems: "center", gap: 10 },
|
|
957
|
+
children: [
|
|
958
|
+
/* @__PURE__ */ jsxs4(View4, { style: { flex: 1, gap: 2 }, children: [
|
|
959
|
+
/* @__PURE__ */ jsx4(Text4, { style: { color: theme.text, fontWeight: "600", writingDirection: direction }, children: purpose.title[locale] }),
|
|
960
|
+
/* @__PURE__ */ jsx4(Text4, { style: { color: theme.mutedText, fontSize: 12, lineHeight: 18, writingDirection: direction }, children: purpose.description[locale] })
|
|
961
|
+
] }),
|
|
962
|
+
/* @__PURE__ */ jsx4(
|
|
963
|
+
Pressable3,
|
|
964
|
+
{
|
|
965
|
+
testID: `authowl-privacy-purpose-${purpose.code}`,
|
|
966
|
+
accessibilityRole: "switch",
|
|
967
|
+
accessibilityLabel: purpose.title[locale],
|
|
968
|
+
accessibilityState: { checked: granted, disabled: pending },
|
|
969
|
+
disabled: pending,
|
|
970
|
+
onPress: () => void updateConsent(purpose.code, !granted),
|
|
971
|
+
style: {
|
|
972
|
+
minWidth: 58,
|
|
973
|
+
borderRadius: theme.radius,
|
|
974
|
+
paddingHorizontal: 10,
|
|
975
|
+
paddingVertical: 8,
|
|
976
|
+
alignItems: "center",
|
|
977
|
+
backgroundColor: granted ? theme.accent : theme.surface,
|
|
978
|
+
borderWidth: 1,
|
|
979
|
+
borderColor: granted ? theme.accent : theme.border,
|
|
980
|
+
opacity: pending ? 0.55 : 1
|
|
981
|
+
},
|
|
982
|
+
children: /* @__PURE__ */ jsx4(Text4, { style: { color: granted ? theme.accentText : theme.text, fontWeight: "600" }, children: pending ? t("common.working") : t(granted ? "privacy.on" : "privacy.off") })
|
|
983
|
+
}
|
|
984
|
+
)
|
|
985
|
+
]
|
|
986
|
+
},
|
|
987
|
+
purpose.purposeVersionId
|
|
988
|
+
);
|
|
989
|
+
})
|
|
990
|
+
}
|
|
991
|
+
),
|
|
992
|
+
/* @__PURE__ */ jsx4(
|
|
993
|
+
PrivacyBlock,
|
|
994
|
+
{
|
|
995
|
+
title: t("privacy.rights.title"),
|
|
996
|
+
description: t("privacy.rights.description"),
|
|
997
|
+
theme,
|
|
998
|
+
children: Object.keys(RIGHT_KEYS).map((right) => /* @__PURE__ */ jsx4(
|
|
999
|
+
Pressable3,
|
|
1000
|
+
{
|
|
1001
|
+
testID: `authowl-privacy-right-${right}`,
|
|
1002
|
+
accessibilityRole: "button",
|
|
1003
|
+
accessibilityState: { disabled: pendingRight !== null, busy: pendingRight === right },
|
|
1004
|
+
disabled: pendingRight !== null,
|
|
1005
|
+
onPress: () => void createRequest(right),
|
|
1006
|
+
style: {
|
|
1007
|
+
borderWidth: 1,
|
|
1008
|
+
borderColor: right === "erasure" ? theme.danger : theme.border,
|
|
1009
|
+
borderRadius: theme.radius,
|
|
1010
|
+
padding: 12,
|
|
1011
|
+
opacity: pendingRight !== null ? 0.55 : 1
|
|
1012
|
+
},
|
|
1013
|
+
children: /* @__PURE__ */ jsx4(Text4, { style: { color: right === "erasure" ? theme.danger : theme.text, fontWeight: "600" }, children: pendingRight === right ? t("common.working") : t(RIGHT_KEYS[right]) })
|
|
1014
|
+
},
|
|
1015
|
+
right
|
|
1016
|
+
))
|
|
1017
|
+
}
|
|
1018
|
+
),
|
|
1019
|
+
/* @__PURE__ */ jsx4(
|
|
1020
|
+
PrivacyBlock,
|
|
1021
|
+
{
|
|
1022
|
+
title: t("privacy.requests.title"),
|
|
1023
|
+
description: t("privacy.requests.description"),
|
|
1024
|
+
theme,
|
|
1025
|
+
children: requests.length === 0 ? /* @__PURE__ */ jsx4(Text4, { style: { color: theme.mutedText }, children: t("privacy.requests.empty") }) : requests.map((request) => /* @__PURE__ */ jsxs4(
|
|
1026
|
+
View4,
|
|
1027
|
+
{
|
|
1028
|
+
style: { flexDirection: "row", justifyContent: "space-between", gap: 12 },
|
|
1029
|
+
children: [
|
|
1030
|
+
/* @__PURE__ */ jsx4(Text4, { style: { flex: 1, color: theme.text }, children: t(RIGHT_KEYS[request.rightType]) }),
|
|
1031
|
+
/* @__PURE__ */ jsx4(Text4, { style: { color: theme.mutedText, fontWeight: "600" }, children: t(STATE_KEYS[request.state]) })
|
|
1032
|
+
]
|
|
1033
|
+
},
|
|
1034
|
+
request.id
|
|
1035
|
+
))
|
|
1036
|
+
}
|
|
1037
|
+
)
|
|
1038
|
+
]
|
|
1039
|
+
}
|
|
1040
|
+
);
|
|
1041
|
+
}
|
|
1042
|
+
function PrivacyBlock({
|
|
1043
|
+
title,
|
|
1044
|
+
description,
|
|
1045
|
+
theme,
|
|
1046
|
+
children
|
|
1047
|
+
}) {
|
|
1048
|
+
return /* @__PURE__ */ jsxs4(
|
|
1049
|
+
View4,
|
|
1050
|
+
{
|
|
1051
|
+
style: {
|
|
1052
|
+
gap: theme.spacing,
|
|
1053
|
+
borderWidth: 1,
|
|
1054
|
+
borderColor: theme.border,
|
|
1055
|
+
borderRadius: theme.radius,
|
|
1056
|
+
backgroundColor: theme.surface,
|
|
1057
|
+
padding: theme.spacing
|
|
1058
|
+
},
|
|
1059
|
+
children: [
|
|
1060
|
+
/* @__PURE__ */ jsxs4(View4, { style: { gap: 3 }, children: [
|
|
1061
|
+
/* @__PURE__ */ jsx4(Text4, { style: { color: theme.text, fontSize: 16, fontWeight: "600" }, children: title }),
|
|
1062
|
+
/* @__PURE__ */ jsx4(Text4, { style: { color: theme.mutedText, fontSize: 13, lineHeight: 19 }, children: description })
|
|
1063
|
+
] }),
|
|
1064
|
+
children
|
|
1065
|
+
]
|
|
1066
|
+
}
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// src/components/EmailOtpForm.tsx
|
|
1071
|
+
import { useState as useState5 } from "react";
|
|
1072
|
+
import { Text as Text5, View as View5 } from "react-native";
|
|
1073
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
715
1074
|
function EmailOtpForm({ onSignedIn, theme = defaultTheme }) {
|
|
716
1075
|
const t = useT();
|
|
717
1076
|
const toMessage = useServerError();
|
|
718
1077
|
const client = useAuthOwlClient();
|
|
719
1078
|
const styles = useStyles(theme);
|
|
720
|
-
const [stage, setStage] =
|
|
721
|
-
const [email, setEmail] =
|
|
722
|
-
const [code, setCode] =
|
|
723
|
-
const [busy, setBusy] =
|
|
724
|
-
const [error, setError] =
|
|
1079
|
+
const [stage, setStage] = useState5("email");
|
|
1080
|
+
const [email, setEmail] = useState5("");
|
|
1081
|
+
const [code, setCode] = useState5("");
|
|
1082
|
+
const [busy, setBusy] = useState5(false);
|
|
1083
|
+
const [error, setError] = useState5(null);
|
|
725
1084
|
async function requestCode() {
|
|
726
1085
|
if (busy || email.trim().length === 0) return;
|
|
727
1086
|
setBusy(true);
|
|
@@ -755,8 +1114,8 @@ function EmailOtpForm({ onSignedIn, theme = defaultTheme }) {
|
|
|
755
1114
|
setError(null);
|
|
756
1115
|
}
|
|
757
1116
|
if (stage === "email") {
|
|
758
|
-
return /* @__PURE__ */
|
|
759
|
-
/* @__PURE__ */
|
|
1117
|
+
return /* @__PURE__ */ jsxs5(View5, { style: styles.container, testID: "authowl-emailotp", children: [
|
|
1118
|
+
/* @__PURE__ */ jsx5(
|
|
760
1119
|
Field,
|
|
761
1120
|
{
|
|
762
1121
|
label: t("common.emailLabel"),
|
|
@@ -770,8 +1129,8 @@ function EmailOtpForm({ onSignedIn, theme = defaultTheme }) {
|
|
|
770
1129
|
onSubmitEditing: requestCode
|
|
771
1130
|
}
|
|
772
1131
|
),
|
|
773
|
-
/* @__PURE__ */
|
|
774
|
-
/* @__PURE__ */
|
|
1132
|
+
/* @__PURE__ */ jsx5(FormError, { message: error, theme }),
|
|
1133
|
+
/* @__PURE__ */ jsx5(
|
|
775
1134
|
SubmitButton,
|
|
776
1135
|
{
|
|
777
1136
|
label: t("emailOtp.requestSubmit"),
|
|
@@ -785,8 +1144,8 @@ function EmailOtpForm({ onSignedIn, theme = defaultTheme }) {
|
|
|
785
1144
|
)
|
|
786
1145
|
] });
|
|
787
1146
|
}
|
|
788
|
-
return /* @__PURE__ */
|
|
789
|
-
/* @__PURE__ */
|
|
1147
|
+
return /* @__PURE__ */ jsxs5(View5, { style: styles.container, testID: "authowl-emailotp", children: [
|
|
1148
|
+
/* @__PURE__ */ jsx5(
|
|
790
1149
|
Field,
|
|
791
1150
|
{
|
|
792
1151
|
label: t("emailOtp.codeLabel", { email: email.trim() }),
|
|
@@ -800,8 +1159,8 @@ function EmailOtpForm({ onSignedIn, theme = defaultTheme }) {
|
|
|
800
1159
|
onSubmitEditing: verifyCode
|
|
801
1160
|
}
|
|
802
1161
|
),
|
|
803
|
-
/* @__PURE__ */
|
|
804
|
-
/* @__PURE__ */
|
|
1162
|
+
/* @__PURE__ */ jsx5(FormError, { message: error, theme }),
|
|
1163
|
+
/* @__PURE__ */ jsx5(
|
|
805
1164
|
SubmitButton,
|
|
806
1165
|
{
|
|
807
1166
|
label: t("emailOtp.verifySubmit"),
|
|
@@ -813,14 +1172,14 @@ function EmailOtpForm({ onSignedIn, theme = defaultTheme }) {
|
|
|
813
1172
|
testID: "authowl-emailotp-verify"
|
|
814
1173
|
}
|
|
815
1174
|
),
|
|
816
|
-
/* @__PURE__ */
|
|
1175
|
+
/* @__PURE__ */ jsx5(Text5, { style: styles.link, onPress: changeEmail, testID: "authowl-emailotp-change", children: t("emailOtp.changeEmail") })
|
|
817
1176
|
] });
|
|
818
1177
|
}
|
|
819
1178
|
|
|
820
1179
|
// src/components/OrganizationSwitcher.tsx
|
|
821
|
-
import { useCallback as
|
|
822
|
-
import { Pressable as
|
|
823
|
-
import { jsx as
|
|
1180
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useRef, useState as useState6 } from "react";
|
|
1181
|
+
import { Pressable as Pressable4, Text as Text6, View as View6 } from "react-native";
|
|
1182
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
824
1183
|
function OrganizationSwitcher({
|
|
825
1184
|
onSwitched,
|
|
826
1185
|
allowPersonal = false,
|
|
@@ -832,14 +1191,14 @@ function OrganizationSwitcher({
|
|
|
832
1191
|
const config = usePublicConfig();
|
|
833
1192
|
const session = useSession();
|
|
834
1193
|
const styles = useStyles(theme);
|
|
835
|
-
const [organizations, setOrganizations] =
|
|
836
|
-
const [switching, setSwitching] =
|
|
837
|
-
const [error, setError] =
|
|
1194
|
+
const [organizations, setOrganizations] = useState6(null);
|
|
1195
|
+
const [switching, setSwitching] = useState6(null);
|
|
1196
|
+
const [error, setError] = useState6(null);
|
|
838
1197
|
const activeId = session.data?.session.activeOrganizationId ?? null;
|
|
839
1198
|
const userId = session.data?.user.id ?? null;
|
|
840
1199
|
const signedIn = userId !== null;
|
|
841
1200
|
const requestGeneration = useRef(0);
|
|
842
|
-
const load =
|
|
1201
|
+
const load = useCallback3(async () => {
|
|
843
1202
|
const generation = ++requestGeneration.current;
|
|
844
1203
|
setError(null);
|
|
845
1204
|
const result = await client.organization.list();
|
|
@@ -850,7 +1209,7 @@ function OrganizationSwitcher({
|
|
|
850
1209
|
}
|
|
851
1210
|
setOrganizations(result.data ?? []);
|
|
852
1211
|
}, [client, toMessage]);
|
|
853
|
-
|
|
1212
|
+
useEffect4(() => {
|
|
854
1213
|
requestGeneration.current += 1;
|
|
855
1214
|
setOrganizations(null);
|
|
856
1215
|
setError(null);
|
|
@@ -876,14 +1235,14 @@ function OrganizationSwitcher({
|
|
|
876
1235
|
}
|
|
877
1236
|
if (config.isLoading || config.data !== null && !config.data.organizations) return null;
|
|
878
1237
|
if (!signedIn) {
|
|
879
|
-
return /* @__PURE__ */
|
|
1238
|
+
return /* @__PURE__ */ jsx6(View6, { style: styles.container, testID: "authowl-orgswitcher", children: /* @__PURE__ */ jsx6(Text6, { style: styles.label, children: t("organization.signedOut") }) });
|
|
880
1239
|
}
|
|
881
1240
|
if (organizations === null && error === null) {
|
|
882
|
-
return /* @__PURE__ */
|
|
1241
|
+
return /* @__PURE__ */ jsx6(View6, { style: styles.container, testID: "authowl-orgswitcher", children: /* @__PURE__ */ jsx6(Text6, { style: styles.label, children: t("organization.loading") }) });
|
|
883
1242
|
}
|
|
884
|
-
return /* @__PURE__ */
|
|
885
|
-
/* @__PURE__ */
|
|
886
|
-
allowPersonal ? /* @__PURE__ */
|
|
1243
|
+
return /* @__PURE__ */ jsxs6(View6, { style: styles.container, testID: "authowl-orgswitcher", children: [
|
|
1244
|
+
/* @__PURE__ */ jsx6(Text6, { style: styles.label, children: t("organization.switcher.label") }),
|
|
1245
|
+
allowPersonal ? /* @__PURE__ */ jsx6(
|
|
887
1246
|
OrganizationRow,
|
|
888
1247
|
{
|
|
889
1248
|
label: t("organization.personal"),
|
|
@@ -895,7 +1254,7 @@ function OrganizationSwitcher({
|
|
|
895
1254
|
theme
|
|
896
1255
|
}
|
|
897
1256
|
) : null,
|
|
898
|
-
(organizations ?? []).map((organization) => /* @__PURE__ */
|
|
1257
|
+
(organizations ?? []).map((organization) => /* @__PURE__ */ jsx6(
|
|
899
1258
|
OrganizationRow,
|
|
900
1259
|
{
|
|
901
1260
|
label: organization.name,
|
|
@@ -908,9 +1267,9 @@ function OrganizationSwitcher({
|
|
|
908
1267
|
},
|
|
909
1268
|
organization.id
|
|
910
1269
|
)),
|
|
911
|
-
/* @__PURE__ */
|
|
912
|
-
error !== null ? /* @__PURE__ */
|
|
913
|
-
|
|
1270
|
+
/* @__PURE__ */ jsx6(FormError, { message: error, theme, testID: "authowl-orgswitcher-error" }),
|
|
1271
|
+
error !== null ? /* @__PURE__ */ jsx6(
|
|
1272
|
+
Text6,
|
|
914
1273
|
{
|
|
915
1274
|
style: styles.link,
|
|
916
1275
|
onPress: () => void load(),
|
|
@@ -930,24 +1289,24 @@ function OrganizationRow({
|
|
|
930
1289
|
theme
|
|
931
1290
|
}) {
|
|
932
1291
|
const styles = useStyles(theme);
|
|
933
|
-
return /* @__PURE__ */
|
|
934
|
-
|
|
1292
|
+
return /* @__PURE__ */ jsx6(
|
|
1293
|
+
Pressable4,
|
|
935
1294
|
{
|
|
936
1295
|
onPress,
|
|
937
1296
|
disabled: disabled || selected,
|
|
938
1297
|
testID,
|
|
939
1298
|
accessibilityRole: "button",
|
|
940
1299
|
accessibilityState: { disabled: disabled || selected, busy },
|
|
941
|
-
children: /* @__PURE__ */
|
|
1300
|
+
children: /* @__PURE__ */ jsx6(Text6, { style: selected ? [styles.label, { color: theme.accent }] : styles.label, children: label })
|
|
942
1301
|
}
|
|
943
1302
|
);
|
|
944
1303
|
}
|
|
945
1304
|
|
|
946
1305
|
// src/components/PasskeyEnrollment.tsx
|
|
947
|
-
import { useState as
|
|
948
|
-
import { Text as
|
|
1306
|
+
import { useState as useState7 } from "react";
|
|
1307
|
+
import { Text as Text7, View as View7 } from "react-native";
|
|
949
1308
|
import { resolveProjectCapabilities as resolveProjectCapabilities3 } from "@authowl/core/native";
|
|
950
|
-
import { jsx as
|
|
1309
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
951
1310
|
function usePasskeyClient() {
|
|
952
1311
|
const client = useAuthOwlClient();
|
|
953
1312
|
return "addPasskey" in client.passkey ? client : null;
|
|
@@ -964,8 +1323,8 @@ function PasskeyEnrollment({
|
|
|
964
1323
|
const config = usePublicConfig();
|
|
965
1324
|
const capabilities = resolveProjectCapabilities3(config.data);
|
|
966
1325
|
const styles = useStyles(theme);
|
|
967
|
-
const [busy, setBusy] =
|
|
968
|
-
const [error, setError] =
|
|
1326
|
+
const [busy, setBusy] = useState7(false);
|
|
1327
|
+
const [error, setError] = useState7(null);
|
|
969
1328
|
if (client === null || config.isLoading || config.data !== null && !capabilities.passkeyAdd) {
|
|
970
1329
|
return null;
|
|
971
1330
|
}
|
|
@@ -981,11 +1340,11 @@ function PasskeyEnrollment({
|
|
|
981
1340
|
}
|
|
982
1341
|
onEnrolled?.();
|
|
983
1342
|
}
|
|
984
|
-
return /* @__PURE__ */
|
|
985
|
-
/* @__PURE__ */
|
|
986
|
-
/* @__PURE__ */
|
|
987
|
-
/* @__PURE__ */
|
|
988
|
-
/* @__PURE__ */
|
|
1343
|
+
return /* @__PURE__ */ jsxs7(View7, { style: styles.container, testID: "authowl-passkey-enrollment", children: [
|
|
1344
|
+
/* @__PURE__ */ jsx7(Text7, { style: styles.title, children: t("signUp.passkeyTitle") }),
|
|
1345
|
+
/* @__PURE__ */ jsx7(Text7, { style: styles.label, children: t("signUp.passkeyDescription") }),
|
|
1346
|
+
/* @__PURE__ */ jsx7(FormError, { message: error, theme, testID: "authowl-passkey-error" }),
|
|
1347
|
+
/* @__PURE__ */ jsx7(
|
|
989
1348
|
SubmitButton,
|
|
990
1349
|
{
|
|
991
1350
|
label: t("signUp.passkeySubmit"),
|
|
@@ -996,7 +1355,7 @@ function PasskeyEnrollment({
|
|
|
996
1355
|
testID: "authowl-passkey-submit"
|
|
997
1356
|
}
|
|
998
1357
|
),
|
|
999
|
-
onSkip ? /* @__PURE__ */
|
|
1358
|
+
onSkip ? /* @__PURE__ */ jsx7(Text7, { style: styles.link, onPress: onSkip, testID: "authowl-passkey-skip", children: t("signUp.passkeySkip") }) : null
|
|
1000
1359
|
] });
|
|
1001
1360
|
}
|
|
1002
1361
|
function PasskeySignInButton({
|
|
@@ -1009,8 +1368,8 @@ function PasskeySignInButton({
|
|
|
1009
1368
|
const config = usePublicConfig();
|
|
1010
1369
|
const capabilities = resolveProjectCapabilities3(config.data);
|
|
1011
1370
|
const styles = useStyles(theme);
|
|
1012
|
-
const [busy, setBusy] =
|
|
1013
|
-
const [error, setError] =
|
|
1371
|
+
const [busy, setBusy] = useState7(false);
|
|
1372
|
+
const [error, setError] = useState7(null);
|
|
1014
1373
|
if (client === null || config.isLoading || config.data !== null && !capabilities.passkeySignIn) return null;
|
|
1015
1374
|
async function signIn() {
|
|
1016
1375
|
if (busy || client === null) return;
|
|
@@ -1024,8 +1383,8 @@ function PasskeySignInButton({
|
|
|
1024
1383
|
}
|
|
1025
1384
|
onSignedIn?.();
|
|
1026
1385
|
}
|
|
1027
|
-
return /* @__PURE__ */
|
|
1028
|
-
/* @__PURE__ */
|
|
1386
|
+
return /* @__PURE__ */ jsxs7(View7, { style: styles.container, testID: "authowl-passkey-signin", children: [
|
|
1387
|
+
/* @__PURE__ */ jsx7(
|
|
1029
1388
|
SubmitButton,
|
|
1030
1389
|
{
|
|
1031
1390
|
label: t("passkey.signInButton"),
|
|
@@ -1036,7 +1395,7 @@ function PasskeySignInButton({
|
|
|
1036
1395
|
testID: "authowl-passkey-signin-submit"
|
|
1037
1396
|
}
|
|
1038
1397
|
),
|
|
1039
|
-
/* @__PURE__ */
|
|
1398
|
+
/* @__PURE__ */ jsx7(FormError, { message: error, theme, testID: "authowl-passkey-signin-error" })
|
|
1040
1399
|
] });
|
|
1041
1400
|
}
|
|
1042
1401
|
|
|
@@ -1053,9 +1412,9 @@ function createNativePasskeys(adapter) {
|
|
|
1053
1412
|
}
|
|
1054
1413
|
|
|
1055
1414
|
// src/components/SocialButtons.tsx
|
|
1056
|
-
import { useState as
|
|
1057
|
-
import { View as
|
|
1058
|
-
import { jsx as
|
|
1415
|
+
import { useState as useState8 } from "react";
|
|
1416
|
+
import { View as View8 } from "react-native";
|
|
1417
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1059
1418
|
function SocialButtons({
|
|
1060
1419
|
providers,
|
|
1061
1420
|
onSignedIn,
|
|
@@ -1065,8 +1424,8 @@ function SocialButtons({
|
|
|
1065
1424
|
const toMessage = useServerError();
|
|
1066
1425
|
const client = useAuthOwlClient();
|
|
1067
1426
|
const styles = useStyles(theme);
|
|
1068
|
-
const [pending, setPending] =
|
|
1069
|
-
const [error, setError] =
|
|
1427
|
+
const [pending, setPending] = useState8(null);
|
|
1428
|
+
const [error, setError] = useState8(null);
|
|
1070
1429
|
async function signIn(provider) {
|
|
1071
1430
|
if (pending !== null) return;
|
|
1072
1431
|
setPending(provider.id);
|
|
@@ -1087,8 +1446,8 @@ function SocialButtons({
|
|
|
1087
1446
|
}
|
|
1088
1447
|
}
|
|
1089
1448
|
if (providers.length === 0) return null;
|
|
1090
|
-
return /* @__PURE__ */
|
|
1091
|
-
providers.map((provider) => /* @__PURE__ */
|
|
1449
|
+
return /* @__PURE__ */ jsxs8(View8, { style: styles.container, testID: "authowl-social", children: [
|
|
1450
|
+
providers.map((provider) => /* @__PURE__ */ jsx8(
|
|
1092
1451
|
SubmitButton,
|
|
1093
1452
|
{
|
|
1094
1453
|
label: t("social.continueWith", { provider: provider.label }),
|
|
@@ -1103,7 +1462,7 @@ function SocialButtons({
|
|
|
1103
1462
|
},
|
|
1104
1463
|
provider.id
|
|
1105
1464
|
)),
|
|
1106
|
-
/* @__PURE__ */
|
|
1465
|
+
/* @__PURE__ */ jsx8(FormError, { message: error, theme, testID: "authowl-social-error" })
|
|
1107
1466
|
] });
|
|
1108
1467
|
}
|
|
1109
1468
|
|
|
@@ -1132,6 +1491,7 @@ export {
|
|
|
1132
1491
|
OrganizationSwitcher,
|
|
1133
1492
|
PasskeyEnrollment,
|
|
1134
1493
|
PasskeySignInButton,
|
|
1494
|
+
PrivacyCenter,
|
|
1135
1495
|
SignIn,
|
|
1136
1496
|
SignUp,
|
|
1137
1497
|
SocialButtons,
|
|
@@ -1150,6 +1510,7 @@ export {
|
|
|
1150
1510
|
useAuthOwlClient,
|
|
1151
1511
|
useAuthOwlLocale,
|
|
1152
1512
|
useLocale,
|
|
1513
|
+
usePrivacy,
|
|
1153
1514
|
usePublicConfig,
|
|
1154
1515
|
useServerError,
|
|
1155
1516
|
useSession,
|